## Automatically generated incremental diff
## From:   linux-2.4.28-pre3
## To:     linux-2.4.28-pre4
## Robot:  $Id: make-incremental-diff,v 1.12 2004/01/06 07:19:36 hpa Exp $

diff -urN linux-2.4.28-pre3/CREDITS linux-2.4.28-pre4/CREDITS
--- linux-2.4.28-pre3/CREDITS	2004-10-08 06:28:21.073073109 -0700
+++ linux-2.4.28-pre4/CREDITS	2004-10-08 06:28:24.457210789 -0700
@@ -1809,10 +1809,10 @@
 S: Germany
 
 N: Achim Leubner
-E: achim@vortex.de
-D: GDT SCSI Disk Array Controller driver
-S: ICP vortex Computersysteme GmbH
-S: Flein
+E: achim_leubner@adaptec.com
+D: GDT Disk Array Controller/Storage RAID controller driver
+S: ICP vortex GmbH
+S: Neckarsulm
 S: Germany
 
 N: Phil Lewis
diff -urN linux-2.4.28-pre3/Documentation/Configure.help linux-2.4.28-pre4/Documentation/Configure.help
--- linux-2.4.28-pre3/Documentation/Configure.help	2004-10-08 06:28:21.112074695 -0700
+++ linux-2.4.28-pre4/Documentation/Configure.help	2004-10-08 06:28:24.661219089 -0700
@@ -28961,13 +28961,10 @@
   This code also includes SHA-384, a 384 bit hash with 192 bits
   of security against collision attacks.
 
-CONFIG_CRYPTO_WHIRLPOOL
-  Whirlpool hash algorithm.
-
-  Whirlpool is part of the NESSIE cryptographic primtives.
-  Whirlpool works on messages shorter than 2^256 bits and
-  produces a 512 bit hash.
+CONFIG_CRYPTO_WP512
+  Whirlpool hash algorithm 512, 384 and 256-bit hashes
 
+  Whirlpool-512 is part of the NESSIE cryptographic primtives.
   Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard
 
   See also:
diff -urN linux-2.4.28-pre3/Documentation/crypto/api-intro.txt linux-2.4.28-pre4/Documentation/crypto/api-intro.txt
--- linux-2.4.28-pre3/Documentation/crypto/api-intro.txt	2004-10-08 06:28:21.114074777 -0700
+++ linux-2.4.28-pre4/Documentation/crypto/api-intro.txt	2004-10-08 06:28:24.662219130 -0700
@@ -227,6 +227,7 @@
 
 Whirlpool algorithm contributors:
   Aaron Grothe
+  Jean-Luc Cooke
 
 Generic scatterwalk code by Adam J. Richter <adam@yggdrasil.com>
 
diff -urN linux-2.4.28-pre3/Documentation/i2c/writing-clients linux-2.4.28-pre4/Documentation/i2c/writing-clients
--- linux-2.4.28-pre3/Documentation/i2c/writing-clients	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.28-pre4/Documentation/i2c/writing-clients	2004-10-08 06:28:24.751222751 -0700
@@ -24,24 +24,25 @@
 routines, a client structure specific information like the actual I2C
 address.
 
-  struct i2c_driver foo_driver
-  {  
-    /* name           */  "Foo version 2.3 and later driver",
-    /* id             */  I2C_DRIVERID_FOO,
-    /* flags          */  I2C_DF_NOTIFY,
-    /* attach_adapter */  &foo_attach_adapter,
-    /* detach_client  */  &foo_detach_client,
-    /* command        */  &foo_command,   /* May be NULL */
-    /* inc_use        */  &foo_inc_use,   /* May be NULL */
-    /* dec_use        */  &foo_dec_use    /* May be NULL */
-  }
+static struct i2c_driver foo_driver = {
+	.name		= "Foo version 2.3 driver",
+	.id		= I2C_DRIVERID_FOO, /* from i2c-id.h, optional */
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= &foo_attach_adapter,
+	.detach_client	= &foo_detach_client,
+	.command	= &foo_command, /* may be NULL */
+	.inc_use	= &foo_inc_use, /* May be NULL */
+	.dec_use	= &foo_dec_use, /* May be NULL */
+}
  
 The name can be chosen freely, and may be upto 40 characters long. Please
 use something descriptive here.
 
-The id should be a unique ID. The range 0xf000 to 0xffff is reserved for
-local use, and you can use one of those until you start distributing the
-driver. Before you do that, contact the i2c authors to get your own ID(s).
+If used, the id should be a unique ID. The range 0xf000 to 0xffff is
+reserved for local use, and you can use one of those until you start
+distributing the driver, at which time you should contact the i2c authors
+to get your own ID(s). Note that most of the time you don't need an ID
+at all so you can just omit it.
 
 Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This
 means that your driver will be notified when new adapters are found.
diff -urN linux-2.4.28-pre3/MAINTAINERS linux-2.4.28-pre4/MAINTAINERS
--- linux-2.4.28-pre3/MAINTAINERS	2004-10-08 06:28:21.181077503 -0700
+++ linux-2.4.28-pre4/MAINTAINERS	2004-10-08 06:28:24.802224826 -0700
@@ -766,7 +766,7 @@
 
 GDT SCSI DISK ARRAY CONTROLLER DRIVER
 P:	Achim Leubner
-M:	achim@vortex.de
+M:	achim_leubner@adaptec.com
 L:	linux-scsi@vger.kernel.org
 W:	http://www.icp-vortex.com/
 S:	Supported
@@ -993,6 +993,14 @@
 M:	jjciarla@raiz.uncu.edu.ar
 S:	Maintained
 
+IPVS
+P:	Wensong Zhang
+M:	wensong@linux-vs.org
+P:	Julian Anastasov
+M:	ja@ssi.bg
+L:	lvs-users@linuxvirtualserver.org
+S:	Maintained
+
 IPX NETWORK LAYER
 P:	Arnaldo Carvalho de Melo
 M:	acme@conectiva.com.br
diff -urN linux-2.4.28-pre3/Makefile linux-2.4.28-pre4/Makefile
--- linux-2.4.28-pre3/Makefile	2004-10-08 06:28:21.182077543 -0700
+++ linux-2.4.28-pre4/Makefile	2004-10-08 06:28:24.803224867 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 28
-EXTRAVERSION = -pre3
+EXTRAVERSION = -pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.28-pre3/arch/i386/kernel/acpi.c linux-2.4.28-pre4/arch/i386/kernel/acpi.c
--- linux-2.4.28-pre3/arch/i386/kernel/acpi.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.28-pre4/arch/i386/kernel/acpi.c	2004-10-08 06:28:24.808225070 -0700
@@ -389,6 +389,8 @@
 }
 
 
+extern int mp_irqs_alloc(void);
+
 /*
  * acpi_boot_init()
  *  called from setup_arch(), always.
diff -urN linux-2.4.28-pre3/arch/i386/kernel/pci-irq.c linux-2.4.28-pre4/arch/i386/kernel/pci-irq.c
--- linux-2.4.28-pre3/arch/i386/kernel/pci-irq.c	2004-10-08 06:28:21.190077869 -0700
+++ linux-2.4.28-pre4/arch/i386/kernel/pci-irq.c	2004-10-08 06:28:24.811225192 -0700
@@ -1129,6 +1129,6 @@
 	/* VIA bridges use interrupt line for apic/pci steering across
 	   the V-Link */
 	else if (interrupt_line_quirk)
-		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15);
 		
 }
diff -urN linux-2.4.28-pre3/arch/m68k/atari/stram.c linux-2.4.28-pre4/arch/m68k/atari/stram.c
--- linux-2.4.28-pre3/arch/m68k/atari/stram.c	2003-06-13 07:51:31.000000000 -0700
+++ linux-2.4.28-pre4/arch/m68k/atari/stram.c	2004-10-08 06:28:24.817225436 -0700
@@ -190,7 +190,7 @@
  * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of
  *      total memory
  */
-static int max_swap_size = -1;
+static int max_swap_size = 0;
 
 /* start and end of swapping area */
 static void *swap_start, *swap_end;
@@ -306,7 +306,7 @@
 		reserve_bootmem (0, PAGE_SIZE);
 
 #ifdef CONFIG_STRAM_SWAP
-	{
+	if (max_swap_size) {
 		void *swap_data;
 
 		start_mem = (void *) PAGE_ALIGN ((unsigned long) start_mem);
@@ -961,14 +961,33 @@
 	return( max_start );
 }
 
+#ifdef CONFIG_STRAM_SWAP
 
 /* setup parameters from command line */
-void __init stram_swap_setup(char *str, int *ints)
+void __init stram_swap_setup(char *str)
 {
-	if (ints[0] >= 1)
-		max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK;
+	int ints[3];
+	get_options(str, ARRAY_SIZE(ints), ints);
+	if (ints[0] >= 1) {
+		if (ints[1] == 1) {
+			/* always use ST-RAM as swap */
+			max_swap_size = -1;
+			if (ints[0] == 2) {
+				max_swap_size = ((ints[2] < 0 ? 0 : ints[2]) * 1024) & PAGE_MASK;
+			}
+		}
+		else if (ints[1] == 0) {
+			/* never use ST-RAM as swap */
+			max_swap_size = 0;
+		}
+		else {
+			printk( KERN_WARNING "stram_swap=%d - invalid value\n", ints[1] );
+		}
+	}
 }
 
+#endif	/* CONFIG_STRAM_SWAP */
+
 
 /* ------------------------------------------------------------------------ */
 /*								ST-RAM device								*/
diff -urN linux-2.4.28-pre3/arch/m68k/kernel/setup.c linux-2.4.28-pre4/arch/m68k/kernel/setup.c
--- linux-2.4.28-pre3/arch/m68k/kernel/setup.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.28-pre4/arch/m68k/kernel/setup.c	2004-10-08 06:28:24.819225518 -0700
@@ -290,13 +290,20 @@
 		i = 1;
 	    }
 #ifdef CONFIG_ATARI
-	    /* This option must be parsed very early */
+	    /* These options must be parsed very early */
 	    if (!strncmp( p, "switches=", 9 )) {
 		extern void atari_switches_setup( const char *, int );
 		atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
 				           (q - (p+9)) : strlen(p+9) );
 		i = 1;
 	    }
+#ifdef CONFIG_STRAM_SWAP
+	    if (!strncmp( p, "stram_swap=", 11 )) {
+		extern void stram_swap_setup( char * );
+		stram_swap_setup( p+11 );
+		i = 1;
+	    }
+#endif	/* CONFIG_STRAM_SWAP */
 #endif
 
 	    if (i) {
diff -urN linux-2.4.28-pre3/arch/m68k/mm/motorola.c linux-2.4.28-pre4/arch/m68k/mm/motorola.c
--- linux-2.4.28-pre3/arch/m68k/mm/motorola.c	2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.28-pre4/arch/m68k/mm/motorola.c	2004-10-08 06:28:24.819225518 -0700
@@ -264,7 +264,7 @@
 	printk ("before free_area_init\n");
 #endif
 	zones_size[0] = (mach_max_dma_address < (unsigned long)high_memory ?
-			 mach_max_dma_address : (unsigned long)high_memory);
+			 (mach_max_dma_address+1) : (unsigned long)high_memory);
 	zones_size[1] = (unsigned long)high_memory - zones_size[0];
 
 	zones_size[0] = (zones_size[0] - PAGE_OFFSET) >> PAGE_SHIFT;
diff -urN linux-2.4.28-pre3/arch/mips64/kernel/linux32.c linux-2.4.28-pre4/arch/mips64/kernel/linux32.c
--- linux-2.4.28-pre3/arch/mips64/kernel/linux32.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.28-pre4/arch/mips64/kernel/linux32.c	2004-10-08 06:28:24.824225721 -0700
@@ -1568,7 +1568,7 @@
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
-	if (optname == SO_ATTACH_FILTER)
+	if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
 	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
diff -urN linux-2.4.28-pre3/arch/ppc/platforms/residual.c linux-2.4.28-pre4/arch/ppc/platforms/residual.c
--- linux-2.4.28-pre3/arch/ppc/platforms/residual.c	2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.28-pre4/arch/ppc/platforms/residual.c	2004-10-08 06:28:24.858227104 -0700
@@ -493,7 +493,7 @@
 			size=tag_small_count(pkt->S1_Pack.Tag)+1;
 			printsmallpacket(pkt, size);
 		}
-		(unsigned char *) pkt+=size;
+		pkt = (PnP_TAG_PACKET *)((unsigned char *) pkt + size);
 	} while (pkt->S1_Pack.Tag != END_TAG);
 }
 
diff -urN linux-2.4.28-pre3/arch/ppc64/kernel/sys_ppc32.c linux-2.4.28-pre4/arch/ppc64/kernel/sys_ppc32.c
--- linux-2.4.28-pre3/arch/ppc64/kernel/sys_ppc32.c	2004-02-18 05:36:30.000000000 -0800
+++ linux-2.4.28-pre4/arch/ppc64/kernel/sys_ppc32.c	2004-10-08 06:28:24.861227226 -0700
@@ -3221,7 +3221,7 @@
 	
 	PPCDBG(PPCDBG_SYS32,"sys32_setsockopt - running - pid=%ld, comm=%s\n", current->pid, current->comm);
 
-	if (optname == SO_ATTACH_FILTER) {
+	if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) {
 		struct sock_fprog32 {
 			__u16 len;
 			__u32 filter;
diff -urN linux-2.4.28-pre3/arch/sparc64/kernel/pci_psycho.c linux-2.4.28-pre4/arch/sparc64/kernel/pci_psycho.c
--- linux-2.4.28-pre3/arch/sparc64/kernel/pci_psycho.c	2004-10-08 06:28:21.300082344 -0700
+++ linux-2.4.28-pre4/arch/sparc64/kernel/pci_psycho.c	2004-10-08 06:28:24.886228244 -0700
@@ -1106,17 +1106,17 @@
 	 * bits for each PBM.
 	 */
 	tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
-	tmp |= (PSYCHO_PCICTRL_SBH_ERR |
-		PSYCHO_PCICTRL_SERR |
-		PSYCHO_PCICTRL_SBH_INT |
+	tmp |= (PSYCHO_PCICTRL_SERR |
+		PSYCHO_PCICTRL_SBH_ERR |
 		PSYCHO_PCICTRL_EEN);
+	tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
 	psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
 		     
 	tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
-	tmp |= (PSYCHO_PCICTRL_SBH_ERR |
-		PSYCHO_PCICTRL_SERR |
-		PSYCHO_PCICTRL_SBH_INT |
+	tmp |= (PSYCHO_PCICTRL_SERR |
+		PSYCHO_PCICTRL_SBH_ERR |
 		PSYCHO_PCICTRL_EEN);
+	tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
 	psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
 }
 
diff -urN linux-2.4.28-pre3/arch/sparc64/kernel/pci_schizo.c linux-2.4.28-pre4/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.28-pre3/arch/sparc64/kernel/pci_schizo.c	2004-10-08 06:28:21.304082507 -0700
+++ linux-2.4.28-pre4/arch/sparc64/kernel/pci_schizo.c	2004-10-08 06:28:24.890228406 -0700
@@ -1423,10 +1423,10 @@
 		    SCHIZO_PCICTRL_RTRY_ERR |
 		    SCHIZO_PCICTRL_SBH_ERR |
 		    SCHIZO_PCICTRL_SERR |
-		    SCHIZO_PCICTRL_SBH_INT |
 		    SCHIZO_PCICTRL_EEN);
 
-	err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
+	err_no_mask = (SCHIZO_PCICTRL_DTO_ERR |
+		       SCHIZO_PCICTRL_SBH_INT);
 
 	/* Enable PCI Error interrupts and clear error
 	 * bits for each PBM.
diff -urN linux-2.4.28-pre3/arch/sparc64/kernel/sys_sparc32.c linux-2.4.28-pre4/arch/sparc64/kernel/sys_sparc32.c
--- linux-2.4.28-pre3/arch/sparc64/kernel/sys_sparc32.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.28-pre4/arch/sparc64/kernel/sys_sparc32.c	2004-10-08 06:28:24.897228691 -0700
@@ -2996,10 +2996,11 @@
 	if (optname == IPT_SO_SET_REPLACE)
 		return do_netfilter_replace(fd, level, optname,
 					    optval, optlen);
-	if (optname == SO_ATTACH_FILTER)
+	if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
-	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+	if (level == SOL_SOCKET && 
+	    (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO))
 		return do_set_sock_timeout(fd, level, optname, optval, optlen);
 
 	return sys_setsockopt(fd, level, optname, optval, optlen);
diff -urN linux-2.4.28-pre3/arch/x86_64/ia32/socket32.c linux-2.4.28-pre4/arch/x86_64/ia32/socket32.c
--- linux-2.4.28-pre3/arch/x86_64/ia32/socket32.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.28-pre4/arch/x86_64/ia32/socket32.c	2004-10-08 06:28:24.969231620 -0700
@@ -555,7 +555,7 @@
 asmlinkage long sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
-	if (optname == SO_ATTACH_FILTER)
+	if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER)
 		return do_set_attach_filter(fd, level, optname,
 					    optval, optlen);
 	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
diff -urN linux-2.4.28-pre3/crypto/Config.in linux-2.4.28-pre4/crypto/Config.in
--- linux-2.4.28-pre3/crypto/Config.in	2004-10-08 06:28:21.337083850 -0700
+++ linux-2.4.28-pre4/crypto/Config.in	2004-10-08 06:28:24.973231783 -0700
@@ -58,7 +58,7 @@
   fi
   tristate       '  SHA256 digest algorithm' CONFIG_CRYPTO_SHA256
   tristate       '  SHA384 and SHA512 digest algorithms' CONFIG_CRYPTO_SHA512
-  tristate       '  Whirlpool digest algorithm' CONFIG_CRYPTO_WHIRLPOOL
+  tristate       '  Whirlpool digest algorithms' CONFIG_CRYPTO_WP512
   if [ "$CONFIG_INET_ESP" = "y" -o \
        "$CONFIG_INET_ESP" = "m" -o \
        "$CONFIG_INET6_ESP" = "y" -o \
diff -urN linux-2.4.28-pre3/crypto/Makefile linux-2.4.28-pre4/crypto/Makefile
--- linux-2.4.28-pre3/crypto/Makefile	2004-10-08 06:28:21.337083850 -0700
+++ linux-2.4.28-pre4/crypto/Makefile	2004-10-08 06:28:24.973231783 -0700
@@ -19,7 +19,7 @@
 obj-$(CONFIG_CRYPTO_SHA1) += sha1.o
 obj-$(CONFIG_CRYPTO_SHA256) += sha256.o
 obj-$(CONFIG_CRYPTO_SHA512) += sha512.o
-obj-$(CONFIG_CRYPTO_WHIRLPOOL) += whirlpool.o
+obj-$(CONFIG_CRYPTO_WP512) += wp512.o
 obj-$(CONFIG_CRYPTO_DES) += des.o
 obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
 obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
diff -urN linux-2.4.28-pre3/crypto/api.c linux-2.4.28-pre4/crypto/api.c
--- linux-2.4.28-pre3/crypto/api.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.28-pre4/crypto/api.c	2004-10-08 06:28:24.974231824 -0700
@@ -156,8 +156,12 @@
 
 void crypto_free_tfm(struct crypto_tfm *tfm)
 {
+	struct crypto_alg *alg = tfm->__crt_alg;
+	int size = sizeof(*tfm) + alg->cra_ctxsize;
+
 	crypto_exit_ops(tfm);
-	crypto_alg_put(tfm->__crt_alg);
+	crypto_alg_put(alg);
+	memset(tfm, 0, size);
 	kfree(tfm);
 }
 
diff -urN linux-2.4.28-pre3/crypto/tcrypt.c linux-2.4.28-pre4/crypto/tcrypt.c
--- linux-2.4.28-pre3/crypto/tcrypt.c	2004-10-08 06:28:21.343084094 -0700
+++ linux-2.4.28-pre4/crypto/tcrypt.c	2004-10-08 06:28:24.979232027 -0700
@@ -63,7 +63,8 @@
 static char *check[] = {
 	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
 	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", 
-	"arc4", "michael_mic", "deflate", "tea", "xtea", "whirlpool", NULL
+	"arc4", "michael_mic", "deflate", "tea", "xtea", "wp512", 
+	"wp384", "wp256", NULL
 };
 
 static void
@@ -581,7 +582,9 @@
 
 		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
 		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
-		test_hash("whirlpool", whirlpool_tv_template, WHIRLPOOL_TEST_VECTORS);
+		test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
+		test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS);
+		test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS);
 		test_deflate();		
 #ifdef CONFIG_CRYPTO_HMAC
 		test_hmac("md5", hmac_md5_tv_template, HMAC_MD5_TEST_VECTORS);
@@ -686,9 +689,16 @@
 	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;
 	case 22:
-		test_hash("whirlpool", whirlpool_tv_template, WHIRLPOOL_TEST_VECTORS);
+		test_hash("wp512", wp512_tv_template, WP512_TEST_VECTORS);
+		break;
+
+	case 23:
+		test_hash("wp384", wp384_tv_template, WP384_TEST_VECTORS);
+		break;
+
+	case 24:
+		test_hash("wp256", wp256_tv_template, WP256_TEST_VECTORS);
 		break;
 
 #ifdef CONFIG_CRYPTO_HMAC
diff -urN linux-2.4.28-pre3/crypto/tcrypt.h linux-2.4.28-pre4/crypto/tcrypt.h
--- linux-2.4.28-pre3/crypto/tcrypt.h	2004-10-08 06:28:21.345084175 -0700
+++ linux-2.4.28-pre4/crypto/tcrypt.h	2004-10-08 06:28:24.982232149 -0700
@@ -555,9 +555,9 @@
  * by Vincent Rijmen and Paulo S. L. M. Barreto as part of the NESSIE
  * submission
  */
-#define WHIRLPOOL_TEST_VECTORS	8
+#define WP512_TEST_VECTORS	8
 
-struct hash_testvec whirlpool_tv_template[] = {
+struct hash_testvec wp512_tv_template[] = {
 	{ 
 		.plaintext = "",
 		.psize	= 0,
@@ -653,6 +653,154 @@
 	},
 };
 
+#define WP384_TEST_VECTORS	8
+
+struct hash_testvec wp384_tv_template[] = {
+	{ 
+		.plaintext = "",
+		.psize	= 0,
+		.digest	= { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66,
+			    0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26,
+			    0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8,
+			    0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7,
+			    0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB,
+			    0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57 },
+
+
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F,
+			    0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7,
+			    0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69,
+			    0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42,
+			    0xD1, 0x1B, 0xC6, 0x45, 0x41, 0x3A, 0xEF, 0xF6,
+			    0x3A, 0x42, 0x39, 0x1A, 0x39, 0x14, 0x5A, 0x59 },
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB,
+			    0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B,
+			    0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72,
+			    0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C,
+			    0x71, 0x81, 0xEE, 0xBD, 0xB6, 0xC5, 0x7E, 0x27,
+			    0x7D, 0x0E, 0x34, 0x95, 0x71, 0x14, 0xCB, 0xD6 },
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, 
+			    0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, 
+			    0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, 
+			    0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B, 
+			    0x84, 0x21, 0x55, 0x76, 0x59, 0xEF, 0x55, 0xC1, 
+			    0x06, 0xB4, 0xB5, 0x2A, 0xC5, 0xA4, 0xAA, 0xA6 },
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9,
+			    0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A,
+			    0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5,
+			    0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B,
+			    0x08, 0xBF, 0x2A, 0x92, 0x51, 0xC3, 0x0B, 0x6A,
+			    0x0B, 0x8A, 0xAE, 0x86, 0x17, 0x7A, 0xB4, 0xA6 },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+			     "abcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B,
+			    0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90,
+			    0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC,
+			    0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E,
+			    0x08, 0xEB, 0xA2, 0x66, 0x29, 0x12, 0x9D, 0x8F,
+			    0xB7, 0xCB, 0x57, 0x21, 0x1B, 0x92, 0x81, 0xA6 },
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			     "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D,
+			    0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0,
+			    0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6,
+			    0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29,
+			    0x4D, 0x5B, 0xD8, 0xDF, 0x2A, 0x6C, 0x44, 0xE5,
+			    0x38, 0xCD, 0x04, 0x7B, 0x26, 0x81, 0xA5, 0x1A },
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, 
+			    0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48,
+			    0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62,
+			    0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69,
+			    0x16, 0xBD, 0xC8, 0x03, 0x1B, 0xC5, 0xBE, 0x1B,
+			    0x7B, 0x94, 0x76, 0x39, 0xFE, 0x05, 0x0B, 0x56 },
+	},
+};
+
+#define WP256_TEST_VECTORS	8
+
+struct hash_testvec wp256_tv_template[] = {
+	{ 
+		.plaintext = "",
+		.psize	= 0,
+		.digest	= { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66,
+			    0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26,
+			    0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8,
+			    0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7 },
+
+
+	}, {
+		.plaintext = "a",
+		.psize	= 1,
+		.digest	= { 0x8A, 0xCA, 0x26, 0x02, 0x79, 0x2A, 0xEC, 0x6F,
+			    0x11, 0xA6, 0x72, 0x06, 0x53, 0x1F, 0xB7, 0xD7,
+			    0xF0, 0xDF, 0xF5, 0x94, 0x13, 0x14, 0x5E, 0x69,
+			    0x73, 0xC4, 0x50, 0x01, 0xD0, 0x08, 0x7B, 0x42 },
+	}, {
+		.plaintext = "abc",
+		.psize	= 3,
+		.digest	= { 0x4E, 0x24, 0x48, 0xA4, 0xC6, 0xF4, 0x86, 0xBB,
+			    0x16, 0xB6, 0x56, 0x2C, 0x73, 0xB4, 0x02, 0x0B,
+			    0xF3, 0x04, 0x3E, 0x3A, 0x73, 0x1B, 0xCE, 0x72,
+			    0x1A, 0xE1, 0xB3, 0x03, 0xD9, 0x7E, 0x6D, 0x4C },
+	}, {
+		.plaintext = "message digest",
+		.psize	= 14,
+		.digest	= { 0x37, 0x8C, 0x84, 0xA4, 0x12, 0x6E, 0x2D, 0xC6, 
+			    0xE5, 0x6D, 0xCC, 0x74, 0x58, 0x37, 0x7A, 0xAC, 
+			    0x83, 0x8D, 0x00, 0x03, 0x22, 0x30, 0xF5, 0x3C, 
+			    0xE1, 0xF5, 0x70, 0x0C, 0x0F, 0xFB, 0x4D, 0x3B },
+	}, {
+		.plaintext = "abcdefghijklmnopqrstuvwxyz",
+		.psize	= 26,
+		.digest	= { 0xF1, 0xD7, 0x54, 0x66, 0x26, 0x36, 0xFF, 0xE9,
+			    0x2C, 0x82, 0xEB, 0xB9, 0x21, 0x2A, 0x48, 0x4A,
+			    0x8D, 0x38, 0x63, 0x1E, 0xAD, 0x42, 0x38, 0xF5,
+			    0x44, 0x2E, 0xE1, 0x3B, 0x80, 0x54, 0xE4, 0x1B },
+	}, {
+		.plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+			     "abcdefghijklmnopqrstuvwxyz0123456789",
+		.psize	= 62,
+		.digest	= { 0xDC, 0x37, 0xE0, 0x08, 0xCF, 0x9E, 0xE6, 0x9B,
+			    0xF1, 0x1F, 0x00, 0xED, 0x9A, 0xBA, 0x26, 0x90,
+			    0x1D, 0xD7, 0xC2, 0x8C, 0xDE, 0xC0, 0x66, 0xCC,
+			    0x6A, 0xF4, 0x2E, 0x40, 0xF8, 0x2F, 0x3A, 0x1E },
+	}, {
+		.plaintext = "1234567890123456789012345678901234567890"
+			     "1234567890123456789012345678901234567890",
+		.psize	= 80,
+		.digest	= { 0x46, 0x6E, 0xF1, 0x8B, 0xAB, 0xB0, 0x15, 0x4D,
+			    0x25, 0xB9, 0xD3, 0x8A, 0x64, 0x14, 0xF5, 0xC0,
+			    0x87, 0x84, 0x37, 0x2B, 0xCC, 0xB2, 0x04, 0xD6,
+			    0x54, 0x9C, 0x4A, 0xFA, 0xDB, 0x60, 0x14, 0x29 },
+	}, {
+		.plaintext = "abcdbcdecdefdefgefghfghighijhijk",
+		.psize	= 32,
+		.digest	= { 0x2A, 0x98, 0x7E, 0xA4, 0x0F, 0x91, 0x70, 0x61, 
+			    0xF5, 0xD6, 0xF0, 0xA0, 0xE4, 0x64, 0x4F, 0x48,
+			    0x8A, 0x7A, 0x5A, 0x52, 0xDE, 0xEE, 0x65, 0x62,
+			    0x07, 0xC5, 0x62, 0xF9, 0x88, 0xE9, 0x5C, 0x69 },
+	},
+};
+
 /*
  * DES test vectors.
  */
diff -urN linux-2.4.28-pre3/crypto/tea.c linux-2.4.28-pre4/crypto/tea.c
--- linux-2.4.28-pre3/crypto/tea.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.28-pre4/crypto/tea.c	2004-10-08 06:28:24.982232149 -0700
@@ -154,7 +154,7 @@
 
 	while (sum != limit) {
 		y += (z << 4 ^ z >> 5) + (z ^ sum) + ctx->KEY[sum&3]; 
-		sum += TEA_DELTA;
+		sum += XTEA_DELTA;
 		z += (y << 4 ^ y >> 5) + (y ^ sum) + ctx->KEY[sum>>11 &3]; 
 	}
 	
diff -urN linux-2.4.28-pre3/crypto/whirlpool.c linux-2.4.28-pre4/crypto/whirlpool.c
--- linux-2.4.28-pre3/crypto/whirlpool.c	2004-10-08 06:28:21.350084379 -0700
+++ linux-2.4.28-pre4/crypto/whirlpool.c	1969-12-31 16:00:00.000000000 -0800
@@ -1,1131 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Whirlpool hashing Algorithm
- *
- * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and
- * Vincent Rijmen.  It has been selected as one of cryptographic
- * primitives by the NESSIE project http://www.cryptonessie.org/
- *
- * 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 23, 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 WHIRLPOOL_DIGEST_SIZE 64
-#define WHIRLPOOL_BLOCK_SIZE  64
-#define WHIRLPOOL_LENGTHBYTES 32
-
-#define WHIRLPOOL_ROUNDS 10
-
-struct whirlpool_ctx {
-	u8  bitLength[WHIRLPOOL_LENGTHBYTES];
-	u8  buffer[WHIRLPOOL_BLOCK_SIZE];
-	int bufferBits;
-	int bufferPos;
-	u64 hash[WHIRLPOOL_DIGEST_SIZE/8];
-};
-
-/*
- * Though Whirlpool is endianness-neutral, the encryption tables are listed
- * in BIG-ENDIAN format, which is adopted throughout this implementation
- * (but little-endian notation would be equally suitable if consistently
- * employed).
- */
-
-static const u64 C0[256] = {
-	0x18186018c07830d8ULL, 0x23238c2305af4626ULL, 0xc6c63fc67ef991b8ULL,
-	0xe8e887e8136fcdfbULL, 0x878726874ca113cbULL, 0xb8b8dab8a9626d11ULL,
-	0x0101040108050209ULL, 0x4f4f214f426e9e0dULL, 0x3636d836adee6c9bULL,
-	0xa6a6a2a6590451ffULL, 0xd2d26fd2debdb90cULL, 0xf5f5f3f5fb06f70eULL,
-	0x7979f979ef80f296ULL, 0x6f6fa16f5fcede30ULL, 0x91917e91fcef3f6dULL,
-	0x52525552aa07a4f8ULL, 0x60609d6027fdc047ULL, 0xbcbccabc89766535ULL,
-	0x9b9b569baccd2b37ULL, 0x8e8e028e048c018aULL, 0xa3a3b6a371155bd2ULL,
-	0x0c0c300c603c186cULL, 0x7b7bf17bff8af684ULL, 0x3535d435b5e16a80ULL,
-	0x1d1d741de8693af5ULL, 0xe0e0a7e05347ddb3ULL, 0xd7d77bd7f6acb321ULL,
-	0xc2c22fc25eed999cULL, 0x2e2eb82e6d965c43ULL, 0x4b4b314b627a9629ULL,
-	0xfefedffea321e15dULL, 0x575741578216aed5ULL, 0x15155415a8412abdULL,
-	0x7777c1779fb6eee8ULL, 0x3737dc37a5eb6e92ULL, 0xe5e5b3e57b56d79eULL,
-	0x9f9f469f8cd92313ULL, 0xf0f0e7f0d317fd23ULL, 0x4a4a354a6a7f9420ULL,
-	0xdada4fda9e95a944ULL, 0x58587d58fa25b0a2ULL, 0xc9c903c906ca8fcfULL,
-	0x2929a429558d527cULL, 0x0a0a280a5022145aULL, 0xb1b1feb1e14f7f50ULL,
-	0xa0a0baa0691a5dc9ULL, 0x6b6bb16b7fdad614ULL, 0x85852e855cab17d9ULL,
-	0xbdbdcebd8173673cULL, 0x5d5d695dd234ba8fULL, 0x1010401080502090ULL,
-	0xf4f4f7f4f303f507ULL, 0xcbcb0bcb16c08bddULL, 0x3e3ef83eedc67cd3ULL,
-	0x0505140528110a2dULL, 0x676781671fe6ce78ULL, 0xe4e4b7e47353d597ULL,
-	0x27279c2725bb4e02ULL, 0x4141194132588273ULL, 0x8b8b168b2c9d0ba7ULL,
-	0xa7a7a6a7510153f6ULL, 0x7d7de97dcf94fab2ULL, 0x95956e95dcfb3749ULL,
-	0xd8d847d88e9fad56ULL, 0xfbfbcbfb8b30eb70ULL, 0xeeee9fee2371c1cdULL,
-	0x7c7ced7cc791f8bbULL, 0x6666856617e3cc71ULL, 0xdddd53dda68ea77bULL,
-	0x17175c17b84b2eafULL, 0x4747014702468e45ULL, 0x9e9e429e84dc211aULL,
-	0xcaca0fca1ec589d4ULL, 0x2d2db42d75995a58ULL, 0xbfbfc6bf9179632eULL,
-	0x07071c07381b0e3fULL, 0xadad8ead012347acULL, 0x5a5a755aea2fb4b0ULL,
-	0x838336836cb51befULL, 0x3333cc3385ff66b6ULL, 0x636391633ff2c65cULL,
-	0x02020802100a0412ULL, 0xaaaa92aa39384993ULL, 0x7171d971afa8e2deULL,
-	0xc8c807c80ecf8dc6ULL, 0x19196419c87d32d1ULL, 0x494939497270923bULL,
-	0xd9d943d9869aaf5fULL, 0xf2f2eff2c31df931ULL, 0xe3e3abe34b48dba8ULL,
-	0x5b5b715be22ab6b9ULL, 0x88881a8834920dbcULL, 0x9a9a529aa4c8293eULL,
-	0x262698262dbe4c0bULL, 0x3232c8328dfa64bfULL, 0xb0b0fab0e94a7d59ULL,
-	0xe9e983e91b6acff2ULL, 0x0f0f3c0f78331e77ULL, 0xd5d573d5e6a6b733ULL,
-	0x80803a8074ba1df4ULL, 0xbebec2be997c6127ULL, 0xcdcd13cd26de87ebULL,
-	0x3434d034bde46889ULL, 0x48483d487a759032ULL, 0xffffdbffab24e354ULL,
-	0x7a7af57af78ff48dULL, 0x90907a90f4ea3d64ULL, 0x5f5f615fc23ebe9dULL,
-	0x202080201da0403dULL, 0x6868bd6867d5d00fULL, 0x1a1a681ad07234caULL,
-	0xaeae82ae192c41b7ULL, 0xb4b4eab4c95e757dULL, 0x54544d549a19a8ceULL,
-	0x93937693ece53b7fULL, 0x222288220daa442fULL, 0x64648d6407e9c863ULL,
-	0xf1f1e3f1db12ff2aULL, 0x7373d173bfa2e6ccULL, 0x12124812905a2482ULL,
-	0x40401d403a5d807aULL, 0x0808200840281048ULL, 0xc3c32bc356e89b95ULL,
-	0xecec97ec337bc5dfULL, 0xdbdb4bdb9690ab4dULL, 0xa1a1bea1611f5fc0ULL,
-	0x8d8d0e8d1c830791ULL, 0x3d3df43df5c97ac8ULL, 0x97976697ccf1335bULL,
-	0x0000000000000000ULL, 0xcfcf1bcf36d483f9ULL, 0x2b2bac2b4587566eULL,
-	0x7676c57697b3ece1ULL, 0x8282328264b019e6ULL, 0xd6d67fd6fea9b128ULL,
-	0x1b1b6c1bd87736c3ULL, 0xb5b5eeb5c15b7774ULL, 0xafaf86af112943beULL,
-	0x6a6ab56a77dfd41dULL, 0x50505d50ba0da0eaULL, 0x45450945124c8a57ULL,
-	0xf3f3ebf3cb18fb38ULL, 0x3030c0309df060adULL, 0xefef9bef2b74c3c4ULL,
-	0x3f3ffc3fe5c37edaULL, 0x55554955921caac7ULL, 0xa2a2b2a2791059dbULL,
-	0xeaea8fea0365c9e9ULL, 0x656589650fecca6aULL, 0xbabad2bab9686903ULL,
-	0x2f2fbc2f65935e4aULL, 0xc0c027c04ee79d8eULL, 0xdede5fdebe81a160ULL,
-	0x1c1c701ce06c38fcULL, 0xfdfdd3fdbb2ee746ULL, 0x4d4d294d52649a1fULL,
-	0x92927292e4e03976ULL, 0x7575c9758fbceafaULL, 0x06061806301e0c36ULL,
-	0x8a8a128a249809aeULL, 0xb2b2f2b2f940794bULL, 0xe6e6bfe66359d185ULL,
-	0x0e0e380e70361c7eULL, 0x1f1f7c1ff8633ee7ULL, 0x6262956237f7c455ULL,
-	0xd4d477d4eea3b53aULL, 0xa8a89aa829324d81ULL, 0x96966296c4f43152ULL,
-	0xf9f9c3f99b3aef62ULL, 0xc5c533c566f697a3ULL, 0x2525942535b14a10ULL,
-	0x59597959f220b2abULL, 0x84842a8454ae15d0ULL, 0x7272d572b7a7e4c5ULL,
-	0x3939e439d5dd72ecULL, 0x4c4c2d4c5a619816ULL, 0x5e5e655eca3bbc94ULL,
-	0x7878fd78e785f09fULL, 0x3838e038ddd870e5ULL, 0x8c8c0a8c14860598ULL,
-	0xd1d163d1c6b2bf17ULL, 0xa5a5aea5410b57e4ULL, 0xe2e2afe2434dd9a1ULL,
-	0x616199612ff8c24eULL, 0xb3b3f6b3f1457b42ULL, 0x2121842115a54234ULL,
-	0x9c9c4a9c94d62508ULL, 0x1e1e781ef0663ceeULL, 0x4343114322528661ULL,
-	0xc7c73bc776fc93b1ULL, 0xfcfcd7fcb32be54fULL, 0x0404100420140824ULL,
-	0x51515951b208a2e3ULL, 0x99995e99bcc72f25ULL, 0x6d6da96d4fc4da22ULL,
-	0x0d0d340d68391a65ULL, 0xfafacffa8335e979ULL, 0xdfdf5bdfb684a369ULL,
-	0x7e7ee57ed79bfca9ULL, 0x242490243db44819ULL, 0x3b3bec3bc5d776feULL,
-	0xabab96ab313d4b9aULL, 0xcece1fce3ed181f0ULL, 0x1111441188552299ULL,
-	0x8f8f068f0c890383ULL, 0x4e4e254e4a6b9c04ULL, 0xb7b7e6b7d1517366ULL,
-	0xebeb8beb0b60cbe0ULL, 0x3c3cf03cfdcc78c1ULL, 0x81813e817cbf1ffdULL,
-	0x94946a94d4fe3540ULL, 0xf7f7fbf7eb0cf31cULL, 0xb9b9deb9a1676f18ULL,
-	0x13134c13985f268bULL, 0x2c2cb02c7d9c5851ULL, 0xd3d36bd3d6b8bb05ULL,
-	0xe7e7bbe76b5cd38cULL, 0x6e6ea56e57cbdc39ULL, 0xc4c437c46ef395aaULL,
-	0x03030c03180f061bULL, 0x565645568a13acdcULL, 0x44440d441a49885eULL,
-	0x7f7fe17fdf9efea0ULL, 0xa9a99ea921374f88ULL, 0x2a2aa82a4d825467ULL,
-	0xbbbbd6bbb16d6b0aULL, 0xc1c123c146e29f87ULL, 0x53535153a202a6f1ULL,
-	0xdcdc57dcae8ba572ULL, 0x0b0b2c0b58271653ULL, 0x9d9d4e9d9cd32701ULL,
-	0x6c6cad6c47c1d82bULL, 0x3131c43195f562a4ULL, 0x7474cd7487b9e8f3ULL,
-	0xf6f6fff6e309f115ULL, 0x464605460a438c4cULL, 0xacac8aac092645a5ULL,
-	0x89891e893c970fb5ULL, 0x14145014a04428b4ULL, 0xe1e1a3e15b42dfbaULL,
-	0x16165816b04e2ca6ULL, 0x3a3ae83acdd274f7ULL, 0x6969b9696fd0d206ULL,
-	0x09092409482d1241ULL, 0x7070dd70a7ade0d7ULL, 0xb6b6e2b6d954716fULL,
-	0xd0d067d0ceb7bd1eULL, 0xeded93ed3b7ec7d6ULL, 0xcccc17cc2edb85e2ULL,
-	0x424215422a578468ULL, 0x98985a98b4c22d2cULL, 0xa4a4aaa4490e55edULL,
-	0x2828a0285d885075ULL, 0x5c5c6d5cda31b886ULL, 0xf8f8c7f8933fed6bULL,
-	0x8686228644a411c2ULL,
-};
-
-static const u64 C1[256] = {
-	0xd818186018c07830ULL, 0x2623238c2305af46ULL, 0xb8c6c63fc67ef991ULL,
-	0xfbe8e887e8136fcdULL, 0xcb878726874ca113ULL, 0x11b8b8dab8a9626dULL,
-	0x0901010401080502ULL, 0x0d4f4f214f426e9eULL, 0x9b3636d836adee6cULL,
-	0xffa6a6a2a6590451ULL, 0x0cd2d26fd2debdb9ULL, 0x0ef5f5f3f5fb06f7ULL,
-	0x967979f979ef80f2ULL, 0x306f6fa16f5fcedeULL, 0x6d91917e91fcef3fULL,
-	0xf852525552aa07a4ULL, 0x4760609d6027fdc0ULL, 0x35bcbccabc897665ULL,
-	0x379b9b569baccd2bULL, 0x8a8e8e028e048c01ULL, 0xd2a3a3b6a371155bULL,
-	0x6c0c0c300c603c18ULL, 0x847b7bf17bff8af6ULL, 0x803535d435b5e16aULL,
-	0xf51d1d741de8693aULL, 0xb3e0e0a7e05347ddULL, 0x21d7d77bd7f6acb3ULL,
-	0x9cc2c22fc25eed99ULL, 0x432e2eb82e6d965cULL, 0x294b4b314b627a96ULL,
-	0x5dfefedffea321e1ULL, 0xd5575741578216aeULL, 0xbd15155415a8412aULL,
-	0xe87777c1779fb6eeULL, 0x923737dc37a5eb6eULL, 0x9ee5e5b3e57b56d7ULL,
-	0x139f9f469f8cd923ULL, 0x23f0f0e7f0d317fdULL, 0x204a4a354a6a7f94ULL,
-	0x44dada4fda9e95a9ULL, 0xa258587d58fa25b0ULL, 0xcfc9c903c906ca8fULL,
-	0x7c2929a429558d52ULL, 0x5a0a0a280a502214ULL, 0x50b1b1feb1e14f7fULL,
-	0xc9a0a0baa0691a5dULL, 0x146b6bb16b7fdad6ULL, 0xd985852e855cab17ULL,
-	0x3cbdbdcebd817367ULL, 0x8f5d5d695dd234baULL, 0x9010104010805020ULL,
-	0x07f4f4f7f4f303f5ULL, 0xddcbcb0bcb16c08bULL, 0xd33e3ef83eedc67cULL,
-	0x2d0505140528110aULL, 0x78676781671fe6ceULL, 0x97e4e4b7e47353d5ULL,
-	0x0227279c2725bb4eULL, 0x7341411941325882ULL, 0xa78b8b168b2c9d0bULL,
-	0xf6a7a7a6a7510153ULL, 0xb27d7de97dcf94faULL, 0x4995956e95dcfb37ULL,
-	0x56d8d847d88e9fadULL, 0x70fbfbcbfb8b30ebULL, 0xcdeeee9fee2371c1ULL,
-	0xbb7c7ced7cc791f8ULL, 0x716666856617e3ccULL, 0x7bdddd53dda68ea7ULL,
-	0xaf17175c17b84b2eULL, 0x454747014702468eULL, 0x1a9e9e429e84dc21ULL,
-	0xd4caca0fca1ec589ULL, 0x582d2db42d75995aULL, 0x2ebfbfc6bf917963ULL,
-	0x3f07071c07381b0eULL, 0xacadad8ead012347ULL, 0xb05a5a755aea2fb4ULL,
-	0xef838336836cb51bULL, 0xb63333cc3385ff66ULL, 0x5c636391633ff2c6ULL,
-	0x1202020802100a04ULL, 0x93aaaa92aa393849ULL, 0xde7171d971afa8e2ULL,
-	0xc6c8c807c80ecf8dULL, 0xd119196419c87d32ULL, 0x3b49493949727092ULL,
-	0x5fd9d943d9869aafULL, 0x31f2f2eff2c31df9ULL, 0xa8e3e3abe34b48dbULL,
-	0xb95b5b715be22ab6ULL, 0xbc88881a8834920dULL, 0x3e9a9a529aa4c829ULL,
-	0x0b262698262dbe4cULL, 0xbf3232c8328dfa64ULL, 0x59b0b0fab0e94a7dULL,
-	0xf2e9e983e91b6acfULL, 0x770f0f3c0f78331eULL, 0x33d5d573d5e6a6b7ULL,
-	0xf480803a8074ba1dULL, 0x27bebec2be997c61ULL, 0xebcdcd13cd26de87ULL,
-	0x893434d034bde468ULL, 0x3248483d487a7590ULL, 0x54ffffdbffab24e3ULL,
-	0x8d7a7af57af78ff4ULL, 0x6490907a90f4ea3dULL, 0x9d5f5f615fc23ebeULL,
-	0x3d202080201da040ULL, 0x0f6868bd6867d5d0ULL, 0xca1a1a681ad07234ULL,
-	0xb7aeae82ae192c41ULL, 0x7db4b4eab4c95e75ULL, 0xce54544d549a19a8ULL,
-	0x7f93937693ece53bULL, 0x2f222288220daa44ULL, 0x6364648d6407e9c8ULL,
-	0x2af1f1e3f1db12ffULL, 0xcc7373d173bfa2e6ULL, 0x8212124812905a24ULL,
-	0x7a40401d403a5d80ULL, 0x4808082008402810ULL, 0x95c3c32bc356e89bULL,
-	0xdfecec97ec337bc5ULL, 0x4ddbdb4bdb9690abULL, 0xc0a1a1bea1611f5fULL,
-	0x918d8d0e8d1c8307ULL, 0xc83d3df43df5c97aULL, 0x5b97976697ccf133ULL,
-	0x0000000000000000ULL, 0xf9cfcf1bcf36d483ULL, 0x6e2b2bac2b458756ULL,
-	0xe17676c57697b3ecULL, 0xe68282328264b019ULL, 0x28d6d67fd6fea9b1ULL,
-	0xc31b1b6c1bd87736ULL, 0x74b5b5eeb5c15b77ULL, 0xbeafaf86af112943ULL,
-	0x1d6a6ab56a77dfd4ULL, 0xea50505d50ba0da0ULL, 0x5745450945124c8aULL,
-	0x38f3f3ebf3cb18fbULL, 0xad3030c0309df060ULL, 0xc4efef9bef2b74c3ULL,
-	0xda3f3ffc3fe5c37eULL, 0xc755554955921caaULL, 0xdba2a2b2a2791059ULL,
-	0xe9eaea8fea0365c9ULL, 0x6a656589650feccaULL, 0x03babad2bab96869ULL,
-	0x4a2f2fbc2f65935eULL, 0x8ec0c027c04ee79dULL, 0x60dede5fdebe81a1ULL,
-	0xfc1c1c701ce06c38ULL, 0x46fdfdd3fdbb2ee7ULL, 0x1f4d4d294d52649aULL,
-	0x7692927292e4e039ULL, 0xfa7575c9758fbceaULL, 0x3606061806301e0cULL,
-	0xae8a8a128a249809ULL, 0x4bb2b2f2b2f94079ULL, 0x85e6e6bfe66359d1ULL,
-	0x7e0e0e380e70361cULL, 0xe71f1f7c1ff8633eULL, 0x556262956237f7c4ULL,
-	0x3ad4d477d4eea3b5ULL, 0x81a8a89aa829324dULL, 0x5296966296c4f431ULL,
-	0x62f9f9c3f99b3aefULL, 0xa3c5c533c566f697ULL, 0x102525942535b14aULL,
-	0xab59597959f220b2ULL, 0xd084842a8454ae15ULL, 0xc57272d572b7a7e4ULL,
-	0xec3939e439d5dd72ULL, 0x164c4c2d4c5a6198ULL, 0x945e5e655eca3bbcULL,
-	0x9f7878fd78e785f0ULL, 0xe53838e038ddd870ULL, 0x988c8c0a8c148605ULL,
-	0x17d1d163d1c6b2bfULL, 0xe4a5a5aea5410b57ULL, 0xa1e2e2afe2434dd9ULL,
-	0x4e616199612ff8c2ULL, 0x42b3b3f6b3f1457bULL, 0x342121842115a542ULL,
-	0x089c9c4a9c94d625ULL, 0xee1e1e781ef0663cULL, 0x6143431143225286ULL,
-	0xb1c7c73bc776fc93ULL, 0x4ffcfcd7fcb32be5ULL, 0x2404041004201408ULL,
-	0xe351515951b208a2ULL, 0x2599995e99bcc72fULL, 0x226d6da96d4fc4daULL,
-	0x650d0d340d68391aULL, 0x79fafacffa8335e9ULL, 0x69dfdf5bdfb684a3ULL,
-	0xa97e7ee57ed79bfcULL, 0x19242490243db448ULL, 0xfe3b3bec3bc5d776ULL,
-	0x9aabab96ab313d4bULL, 0xf0cece1fce3ed181ULL, 0x9911114411885522ULL,
-	0x838f8f068f0c8903ULL, 0x044e4e254e4a6b9cULL, 0x66b7b7e6b7d15173ULL,
-	0xe0ebeb8beb0b60cbULL, 0xc13c3cf03cfdcc78ULL, 0xfd81813e817cbf1fULL,
-	0x4094946a94d4fe35ULL, 0x1cf7f7fbf7eb0cf3ULL, 0x18b9b9deb9a1676fULL,
-	0x8b13134c13985f26ULL, 0x512c2cb02c7d9c58ULL, 0x05d3d36bd3d6b8bbULL,
-	0x8ce7e7bbe76b5cd3ULL, 0x396e6ea56e57cbdcULL, 0xaac4c437c46ef395ULL,
-	0x1b03030c03180f06ULL, 0xdc565645568a13acULL, 0x5e44440d441a4988ULL,
-	0xa07f7fe17fdf9efeULL, 0x88a9a99ea921374fULL, 0x672a2aa82a4d8254ULL,
-	0x0abbbbd6bbb16d6bULL, 0x87c1c123c146e29fULL, 0xf153535153a202a6ULL,
-	0x72dcdc57dcae8ba5ULL, 0x530b0b2c0b582716ULL, 0x019d9d4e9d9cd327ULL,
-	0x2b6c6cad6c47c1d8ULL, 0xa43131c43195f562ULL, 0xf37474cd7487b9e8ULL,
-	0x15f6f6fff6e309f1ULL, 0x4c464605460a438cULL, 0xa5acac8aac092645ULL,
-	0xb589891e893c970fULL, 0xb414145014a04428ULL, 0xbae1e1a3e15b42dfULL,
-	0xa616165816b04e2cULL, 0xf73a3ae83acdd274ULL, 0x066969b9696fd0d2ULL,
-	0x4109092409482d12ULL, 0xd77070dd70a7ade0ULL, 0x6fb6b6e2b6d95471ULL,
-	0x1ed0d067d0ceb7bdULL, 0xd6eded93ed3b7ec7ULL, 0xe2cccc17cc2edb85ULL,
-	0x68424215422a5784ULL, 0x2c98985a98b4c22dULL, 0xeda4a4aaa4490e55ULL,
-	0x752828a0285d8850ULL, 0x865c5c6d5cda31b8ULL, 0x6bf8f8c7f8933fedULL,
-	0xc28686228644a411ULL,
-};
-
-static const u64 C2[256] = {
-	0x30d818186018c078ULL, 0x462623238c2305afULL, 0x91b8c6c63fc67ef9ULL,
-	0xcdfbe8e887e8136fULL, 0x13cb878726874ca1ULL, 0x6d11b8b8dab8a962ULL,
-	0x0209010104010805ULL, 0x9e0d4f4f214f426eULL, 0x6c9b3636d836adeeULL,
-	0x51ffa6a6a2a65904ULL, 0xb90cd2d26fd2debdULL, 0xf70ef5f5f3f5fb06ULL,
-	0xf2967979f979ef80ULL, 0xde306f6fa16f5fceULL, 0x3f6d91917e91fcefULL,
-	0xa4f852525552aa07ULL, 0xc04760609d6027fdULL, 0x6535bcbccabc8976ULL,
-	0x2b379b9b569baccdULL, 0x018a8e8e028e048cULL, 0x5bd2a3a3b6a37115ULL,
-	0x186c0c0c300c603cULL, 0xf6847b7bf17bff8aULL, 0x6a803535d435b5e1ULL,
-	0x3af51d1d741de869ULL, 0xddb3e0e0a7e05347ULL, 0xb321d7d77bd7f6acULL,
-	0x999cc2c22fc25eedULL, 0x5c432e2eb82e6d96ULL, 0x96294b4b314b627aULL,
-	0xe15dfefedffea321ULL, 0xaed5575741578216ULL, 0x2abd15155415a841ULL,
-	0xeee87777c1779fb6ULL, 0x6e923737dc37a5ebULL, 0xd79ee5e5b3e57b56ULL,
-	0x23139f9f469f8cd9ULL, 0xfd23f0f0e7f0d317ULL, 0x94204a4a354a6a7fULL,
-	0xa944dada4fda9e95ULL, 0xb0a258587d58fa25ULL, 0x8fcfc9c903c906caULL,
-	0x527c2929a429558dULL, 0x145a0a0a280a5022ULL, 0x7f50b1b1feb1e14fULL,
-	0x5dc9a0a0baa0691aULL, 0xd6146b6bb16b7fdaULL, 0x17d985852e855cabULL,
-	0x673cbdbdcebd8173ULL, 0xba8f5d5d695dd234ULL, 0x2090101040108050ULL,
-	0xf507f4f4f7f4f303ULL, 0x8bddcbcb0bcb16c0ULL, 0x7cd33e3ef83eedc6ULL,
-	0x0a2d050514052811ULL, 0xce78676781671fe6ULL, 0xd597e4e4b7e47353ULL,
-	0x4e0227279c2725bbULL, 0x8273414119413258ULL, 0x0ba78b8b168b2c9dULL,
-	0x53f6a7a7a6a75101ULL, 0xfab27d7de97dcf94ULL, 0x374995956e95dcfbULL,
-	0xad56d8d847d88e9fULL, 0xeb70fbfbcbfb8b30ULL, 0xc1cdeeee9fee2371ULL,
-	0xf8bb7c7ced7cc791ULL, 0xcc716666856617e3ULL, 0xa77bdddd53dda68eULL,
-	0x2eaf17175c17b84bULL, 0x8e45474701470246ULL, 0x211a9e9e429e84dcULL,
-	0x89d4caca0fca1ec5ULL, 0x5a582d2db42d7599ULL, 0x632ebfbfc6bf9179ULL,
-	0x0e3f07071c07381bULL, 0x47acadad8ead0123ULL, 0xb4b05a5a755aea2fULL,
-	0x1bef838336836cb5ULL, 0x66b63333cc3385ffULL, 0xc65c636391633ff2ULL,
-	0x041202020802100aULL, 0x4993aaaa92aa3938ULL, 0xe2de7171d971afa8ULL,
-	0x8dc6c8c807c80ecfULL, 0x32d119196419c87dULL, 0x923b494939497270ULL,
-	0xaf5fd9d943d9869aULL, 0xf931f2f2eff2c31dULL, 0xdba8e3e3abe34b48ULL,
-	0xb6b95b5b715be22aULL, 0x0dbc88881a883492ULL, 0x293e9a9a529aa4c8ULL,
-	0x4c0b262698262dbeULL, 0x64bf3232c8328dfaULL, 0x7d59b0b0fab0e94aULL,
-	0xcff2e9e983e91b6aULL, 0x1e770f0f3c0f7833ULL, 0xb733d5d573d5e6a6ULL,
-	0x1df480803a8074baULL, 0x6127bebec2be997cULL, 0x87ebcdcd13cd26deULL,
-	0x68893434d034bde4ULL, 0x903248483d487a75ULL, 0xe354ffffdbffab24ULL,
-	0xf48d7a7af57af78fULL, 0x3d6490907a90f4eaULL, 0xbe9d5f5f615fc23eULL,
-	0x403d202080201da0ULL, 0xd00f6868bd6867d5ULL, 0x34ca1a1a681ad072ULL,
-	0x41b7aeae82ae192cULL, 0x757db4b4eab4c95eULL, 0xa8ce54544d549a19ULL,
-	0x3b7f93937693ece5ULL, 0x442f222288220daaULL, 0xc86364648d6407e9ULL,
-	0xff2af1f1e3f1db12ULL, 0xe6cc7373d173bfa2ULL, 0x248212124812905aULL,
-	0x807a40401d403a5dULL, 0x1048080820084028ULL, 0x9b95c3c32bc356e8ULL,
-	0xc5dfecec97ec337bULL, 0xab4ddbdb4bdb9690ULL, 0x5fc0a1a1bea1611fULL,
-	0x07918d8d0e8d1c83ULL, 0x7ac83d3df43df5c9ULL, 0x335b97976697ccf1ULL,
-	0x0000000000000000ULL, 0x83f9cfcf1bcf36d4ULL, 0x566e2b2bac2b4587ULL,
-	0xece17676c57697b3ULL, 0x19e68282328264b0ULL, 0xb128d6d67fd6fea9ULL,
-	0x36c31b1b6c1bd877ULL, 0x7774b5b5eeb5c15bULL, 0x43beafaf86af1129ULL,
-	0xd41d6a6ab56a77dfULL, 0xa0ea50505d50ba0dULL, 0x8a5745450945124cULL,
-	0xfb38f3f3ebf3cb18ULL, 0x60ad3030c0309df0ULL, 0xc3c4efef9bef2b74ULL,
-	0x7eda3f3ffc3fe5c3ULL, 0xaac755554955921cULL, 0x59dba2a2b2a27910ULL,
-	0xc9e9eaea8fea0365ULL, 0xca6a656589650fecULL, 0x6903babad2bab968ULL,
-	0x5e4a2f2fbc2f6593ULL, 0x9d8ec0c027c04ee7ULL, 0xa160dede5fdebe81ULL,
-	0x38fc1c1c701ce06cULL, 0xe746fdfdd3fdbb2eULL, 0x9a1f4d4d294d5264ULL,
-	0x397692927292e4e0ULL, 0xeafa7575c9758fbcULL, 0x0c3606061806301eULL,
-	0x09ae8a8a128a2498ULL, 0x794bb2b2f2b2f940ULL, 0xd185e6e6bfe66359ULL,
-	0x1c7e0e0e380e7036ULL, 0x3ee71f1f7c1ff863ULL, 0xc4556262956237f7ULL,
-	0xb53ad4d477d4eea3ULL, 0x4d81a8a89aa82932ULL, 0x315296966296c4f4ULL,
-	0xef62f9f9c3f99b3aULL, 0x97a3c5c533c566f6ULL, 0x4a102525942535b1ULL,
-	0xb2ab59597959f220ULL, 0x15d084842a8454aeULL, 0xe4c57272d572b7a7ULL,
-	0x72ec3939e439d5ddULL, 0x98164c4c2d4c5a61ULL, 0xbc945e5e655eca3bULL,
-	0xf09f7878fd78e785ULL, 0x70e53838e038ddd8ULL, 0x05988c8c0a8c1486ULL,
-	0xbf17d1d163d1c6b2ULL, 0x57e4a5a5aea5410bULL, 0xd9a1e2e2afe2434dULL,
-	0xc24e616199612ff8ULL, 0x7b42b3b3f6b3f145ULL, 0x42342121842115a5ULL,
-	0x25089c9c4a9c94d6ULL, 0x3cee1e1e781ef066ULL, 0x8661434311432252ULL,
-	0x93b1c7c73bc776fcULL, 0xe54ffcfcd7fcb32bULL, 0x0824040410042014ULL,
-	0xa2e351515951b208ULL, 0x2f2599995e99bcc7ULL, 0xda226d6da96d4fc4ULL,
-	0x1a650d0d340d6839ULL, 0xe979fafacffa8335ULL, 0xa369dfdf5bdfb684ULL,
-	0xfca97e7ee57ed79bULL, 0x4819242490243db4ULL, 0x76fe3b3bec3bc5d7ULL,
-	0x4b9aabab96ab313dULL, 0x81f0cece1fce3ed1ULL, 0x2299111144118855ULL,
-	0x03838f8f068f0c89ULL, 0x9c044e4e254e4a6bULL, 0x7366b7b7e6b7d151ULL,
-	0xcbe0ebeb8beb0b60ULL, 0x78c13c3cf03cfdccULL, 0x1ffd81813e817cbfULL,
-	0x354094946a94d4feULL, 0xf31cf7f7fbf7eb0cULL, 0x6f18b9b9deb9a167ULL,
-	0x268b13134c13985fULL, 0x58512c2cb02c7d9cULL, 0xbb05d3d36bd3d6b8ULL,
-	0xd38ce7e7bbe76b5cULL, 0xdc396e6ea56e57cbULL, 0x95aac4c437c46ef3ULL,
-	0x061b03030c03180fULL, 0xacdc565645568a13ULL, 0x885e44440d441a49ULL,
-	0xfea07f7fe17fdf9eULL, 0x4f88a9a99ea92137ULL, 0x54672a2aa82a4d82ULL,
-	0x6b0abbbbd6bbb16dULL, 0x9f87c1c123c146e2ULL, 0xa6f153535153a202ULL,
-	0xa572dcdc57dcae8bULL, 0x16530b0b2c0b5827ULL, 0x27019d9d4e9d9cd3ULL,
-	0xd82b6c6cad6c47c1ULL, 0x62a43131c43195f5ULL, 0xe8f37474cd7487b9ULL,
-	0xf115f6f6fff6e309ULL, 0x8c4c464605460a43ULL, 0x45a5acac8aac0926ULL,
-	0x0fb589891e893c97ULL, 0x28b414145014a044ULL, 0xdfbae1e1a3e15b42ULL,
-	0x2ca616165816b04eULL, 0x74f73a3ae83acdd2ULL, 0xd2066969b9696fd0ULL,
-	0x124109092409482dULL, 0xe0d77070dd70a7adULL, 0x716fb6b6e2b6d954ULL,
-	0xbd1ed0d067d0ceb7ULL, 0xc7d6eded93ed3b7eULL, 0x85e2cccc17cc2edbULL,
-	0x8468424215422a57ULL, 0x2d2c98985a98b4c2ULL, 0x55eda4a4aaa4490eULL,
-	0x50752828a0285d88ULL, 0xb8865c5c6d5cda31ULL, 0xed6bf8f8c7f8933fULL,
-	0x11c28686228644a4ULL,
-};
-
-static const u64 C3[256] = {
-	0x7830d818186018c0ULL, 0xaf462623238c2305ULL, 0xf991b8c6c63fc67eULL,
-	0x6fcdfbe8e887e813ULL, 0xa113cb878726874cULL, 0x626d11b8b8dab8a9ULL,
-	0x0502090101040108ULL, 0x6e9e0d4f4f214f42ULL, 0xee6c9b3636d836adULL,
-	0x0451ffa6a6a2a659ULL, 0xbdb90cd2d26fd2deULL, 0x06f70ef5f5f3f5fbULL,
-	0x80f2967979f979efULL, 0xcede306f6fa16f5fULL, 0xef3f6d91917e91fcULL,
-	0x07a4f852525552aaULL, 0xfdc04760609d6027ULL, 0x766535bcbccabc89ULL,
-	0xcd2b379b9b569bacULL, 0x8c018a8e8e028e04ULL, 0x155bd2a3a3b6a371ULL,
-	0x3c186c0c0c300c60ULL, 0x8af6847b7bf17bffULL, 0xe16a803535d435b5ULL,
-	0x693af51d1d741de8ULL, 0x47ddb3e0e0a7e053ULL, 0xacb321d7d77bd7f6ULL,
-	0xed999cc2c22fc25eULL, 0x965c432e2eb82e6dULL, 0x7a96294b4b314b62ULL,
-	0x21e15dfefedffea3ULL, 0x16aed55757415782ULL, 0x412abd15155415a8ULL,
-	0xb6eee87777c1779fULL, 0xeb6e923737dc37a5ULL, 0x56d79ee5e5b3e57bULL,
-	0xd923139f9f469f8cULL, 0x17fd23f0f0e7f0d3ULL, 0x7f94204a4a354a6aULL,
-	0x95a944dada4fda9eULL, 0x25b0a258587d58faULL, 0xca8fcfc9c903c906ULL,
-	0x8d527c2929a42955ULL, 0x22145a0a0a280a50ULL, 0x4f7f50b1b1feb1e1ULL,
-	0x1a5dc9a0a0baa069ULL, 0xdad6146b6bb16b7fULL, 0xab17d985852e855cULL,
-	0x73673cbdbdcebd81ULL, 0x34ba8f5d5d695dd2ULL, 0x5020901010401080ULL,
-	0x03f507f4f4f7f4f3ULL, 0xc08bddcbcb0bcb16ULL, 0xc67cd33e3ef83eedULL,
-	0x110a2d0505140528ULL, 0xe6ce78676781671fULL, 0x53d597e4e4b7e473ULL,
-	0xbb4e0227279c2725ULL, 0x5882734141194132ULL, 0x9d0ba78b8b168b2cULL,
-	0x0153f6a7a7a6a751ULL, 0x94fab27d7de97dcfULL, 0xfb374995956e95dcULL,
-	0x9fad56d8d847d88eULL, 0x30eb70fbfbcbfb8bULL, 0x71c1cdeeee9fee23ULL,
-	0x91f8bb7c7ced7cc7ULL, 0xe3cc716666856617ULL, 0x8ea77bdddd53dda6ULL,
-	0x4b2eaf17175c17b8ULL, 0x468e454747014702ULL, 0xdc211a9e9e429e84ULL,
-	0xc589d4caca0fca1eULL, 0x995a582d2db42d75ULL, 0x79632ebfbfc6bf91ULL,
-	0x1b0e3f07071c0738ULL, 0x2347acadad8ead01ULL, 0x2fb4b05a5a755aeaULL,
-	0xb51bef838336836cULL, 0xff66b63333cc3385ULL, 0xf2c65c636391633fULL,
-	0x0a04120202080210ULL, 0x384993aaaa92aa39ULL, 0xa8e2de7171d971afULL,
-	0xcf8dc6c8c807c80eULL, 0x7d32d119196419c8ULL, 0x70923b4949394972ULL,
-	0x9aaf5fd9d943d986ULL, 0x1df931f2f2eff2c3ULL, 0x48dba8e3e3abe34bULL,
-	0x2ab6b95b5b715be2ULL, 0x920dbc88881a8834ULL, 0xc8293e9a9a529aa4ULL,
-	0xbe4c0b262698262dULL, 0xfa64bf3232c8328dULL, 0x4a7d59b0b0fab0e9ULL,
-	0x6acff2e9e983e91bULL, 0x331e770f0f3c0f78ULL, 0xa6b733d5d573d5e6ULL,
-	0xba1df480803a8074ULL, 0x7c6127bebec2be99ULL, 0xde87ebcdcd13cd26ULL,
-	0xe468893434d034bdULL, 0x75903248483d487aULL, 0x24e354ffffdbffabULL,
-	0x8ff48d7a7af57af7ULL, 0xea3d6490907a90f4ULL, 0x3ebe9d5f5f615fc2ULL,
-	0xa0403d202080201dULL, 0xd5d00f6868bd6867ULL, 0x7234ca1a1a681ad0ULL,
-	0x2c41b7aeae82ae19ULL, 0x5e757db4b4eab4c9ULL, 0x19a8ce54544d549aULL,
-	0xe53b7f93937693ecULL, 0xaa442f222288220dULL, 0xe9c86364648d6407ULL,
-	0x12ff2af1f1e3f1dbULL, 0xa2e6cc7373d173bfULL, 0x5a24821212481290ULL,
-	0x5d807a40401d403aULL, 0x2810480808200840ULL, 0xe89b95c3c32bc356ULL,
-	0x7bc5dfecec97ec33ULL, 0x90ab4ddbdb4bdb96ULL, 0x1f5fc0a1a1bea161ULL,
-	0x8307918d8d0e8d1cULL, 0xc97ac83d3df43df5ULL, 0xf1335b97976697ccULL,
-	0x0000000000000000ULL, 0xd483f9cfcf1bcf36ULL, 0x87566e2b2bac2b45ULL,
-	0xb3ece17676c57697ULL, 0xb019e68282328264ULL, 0xa9b128d6d67fd6feULL,
-	0x7736c31b1b6c1bd8ULL, 0x5b7774b5b5eeb5c1ULL, 0x2943beafaf86af11ULL,
-	0xdfd41d6a6ab56a77ULL, 0x0da0ea50505d50baULL, 0x4c8a574545094512ULL,
-	0x18fb38f3f3ebf3cbULL, 0xf060ad3030c0309dULL, 0x74c3c4efef9bef2bULL,
-	0xc37eda3f3ffc3fe5ULL, 0x1caac75555495592ULL, 0x1059dba2a2b2a279ULL,
-	0x65c9e9eaea8fea03ULL, 0xecca6a656589650fULL, 0x686903babad2bab9ULL,
-	0x935e4a2f2fbc2f65ULL, 0xe79d8ec0c027c04eULL, 0x81a160dede5fdebeULL,
-	0x6c38fc1c1c701ce0ULL, 0x2ee746fdfdd3fdbbULL, 0x649a1f4d4d294d52ULL,
-	0xe0397692927292e4ULL, 0xbceafa7575c9758fULL, 0x1e0c360606180630ULL,
-	0x9809ae8a8a128a24ULL, 0x40794bb2b2f2b2f9ULL, 0x59d185e6e6bfe663ULL,
-	0x361c7e0e0e380e70ULL, 0x633ee71f1f7c1ff8ULL, 0xf7c4556262956237ULL,
-	0xa3b53ad4d477d4eeULL, 0x324d81a8a89aa829ULL, 0xf4315296966296c4ULL,
-	0x3aef62f9f9c3f99bULL, 0xf697a3c5c533c566ULL, 0xb14a102525942535ULL,
-	0x20b2ab59597959f2ULL, 0xae15d084842a8454ULL, 0xa7e4c57272d572b7ULL,
-	0xdd72ec3939e439d5ULL, 0x6198164c4c2d4c5aULL, 0x3bbc945e5e655ecaULL,
-	0x85f09f7878fd78e7ULL, 0xd870e53838e038ddULL, 0x8605988c8c0a8c14ULL,
-	0xb2bf17d1d163d1c6ULL, 0x0b57e4a5a5aea541ULL, 0x4dd9a1e2e2afe243ULL,
-	0xf8c24e616199612fULL, 0x457b42b3b3f6b3f1ULL, 0xa542342121842115ULL,
-	0xd625089c9c4a9c94ULL, 0x663cee1e1e781ef0ULL, 0x5286614343114322ULL,
-	0xfc93b1c7c73bc776ULL, 0x2be54ffcfcd7fcb3ULL, 0x1408240404100420ULL,
-	0x08a2e351515951b2ULL, 0xc72f2599995e99bcULL, 0xc4da226d6da96d4fULL,
-	0x391a650d0d340d68ULL, 0x35e979fafacffa83ULL, 0x84a369dfdf5bdfb6ULL,
-	0x9bfca97e7ee57ed7ULL, 0xb44819242490243dULL, 0xd776fe3b3bec3bc5ULL,
-	0x3d4b9aabab96ab31ULL, 0xd181f0cece1fce3eULL, 0x5522991111441188ULL,
-	0x8903838f8f068f0cULL, 0x6b9c044e4e254e4aULL, 0x517366b7b7e6b7d1ULL,
-	0x60cbe0ebeb8beb0bULL, 0xcc78c13c3cf03cfdULL, 0xbf1ffd81813e817cULL,
-	0xfe354094946a94d4ULL, 0x0cf31cf7f7fbf7ebULL, 0x676f18b9b9deb9a1ULL,
-	0x5f268b13134c1398ULL, 0x9c58512c2cb02c7dULL, 0xb8bb05d3d36bd3d6ULL,
-	0x5cd38ce7e7bbe76bULL, 0xcbdc396e6ea56e57ULL, 0xf395aac4c437c46eULL,
-	0x0f061b03030c0318ULL, 0x13acdc565645568aULL, 0x49885e44440d441aULL,
-	0x9efea07f7fe17fdfULL, 0x374f88a9a99ea921ULL, 0x8254672a2aa82a4dULL,
-	0x6d6b0abbbbd6bbb1ULL, 0xe29f87c1c123c146ULL, 0x02a6f153535153a2ULL,
-	0x8ba572dcdc57dcaeULL, 0x2716530b0b2c0b58ULL, 0xd327019d9d4e9d9cULL,
-	0xc1d82b6c6cad6c47ULL, 0xf562a43131c43195ULL, 0xb9e8f37474cd7487ULL,
-	0x09f115f6f6fff6e3ULL, 0x438c4c464605460aULL, 0x2645a5acac8aac09ULL,
-	0x970fb589891e893cULL, 0x4428b414145014a0ULL, 0x42dfbae1e1a3e15bULL,
-	0x4e2ca616165816b0ULL, 0xd274f73a3ae83acdULL, 0xd0d2066969b9696fULL,
-	0x2d12410909240948ULL, 0xade0d77070dd70a7ULL, 0x54716fb6b6e2b6d9ULL,
-	0xb7bd1ed0d067d0ceULL, 0x7ec7d6eded93ed3bULL, 0xdb85e2cccc17cc2eULL,
-	0x578468424215422aULL, 0xc22d2c98985a98b4ULL, 0x0e55eda4a4aaa449ULL,
-	0x8850752828a0285dULL, 0x31b8865c5c6d5cdaULL, 0x3fed6bf8f8c7f893ULL,
-	0xa411c28686228644ULL,
-};
-
-static const u64 C4[256] = {
-	0xc07830d818186018ULL, 0x05af462623238c23ULL, 0x7ef991b8c6c63fc6ULL,
-	0x136fcdfbe8e887e8ULL, 0x4ca113cb87872687ULL, 0xa9626d11b8b8dab8ULL,
-	0x0805020901010401ULL, 0x426e9e0d4f4f214fULL, 0xadee6c9b3636d836ULL,
-	0x590451ffa6a6a2a6ULL, 0xdebdb90cd2d26fd2ULL, 0xfb06f70ef5f5f3f5ULL,
-	0xef80f2967979f979ULL, 0x5fcede306f6fa16fULL, 0xfcef3f6d91917e91ULL,
-	0xaa07a4f852525552ULL, 0x27fdc04760609d60ULL, 0x89766535bcbccabcULL,
-	0xaccd2b379b9b569bULL, 0x048c018a8e8e028eULL, 0x71155bd2a3a3b6a3ULL,
-	0x603c186c0c0c300cULL, 0xff8af6847b7bf17bULL, 0xb5e16a803535d435ULL,
-	0xe8693af51d1d741dULL, 0x5347ddb3e0e0a7e0ULL, 0xf6acb321d7d77bd7ULL,
-	0x5eed999cc2c22fc2ULL, 0x6d965c432e2eb82eULL, 0x627a96294b4b314bULL,
-	0xa321e15dfefedffeULL, 0x8216aed557574157ULL, 0xa8412abd15155415ULL,
-	0x9fb6eee87777c177ULL, 0xa5eb6e923737dc37ULL, 0x7b56d79ee5e5b3e5ULL,
-	0x8cd923139f9f469fULL, 0xd317fd23f0f0e7f0ULL, 0x6a7f94204a4a354aULL,
-	0x9e95a944dada4fdaULL, 0xfa25b0a258587d58ULL, 0x06ca8fcfc9c903c9ULL,
-	0x558d527c2929a429ULL, 0x5022145a0a0a280aULL, 0xe14f7f50b1b1feb1ULL,
-	0x691a5dc9a0a0baa0ULL, 0x7fdad6146b6bb16bULL, 0x5cab17d985852e85ULL,
-	0x8173673cbdbdcebdULL, 0xd234ba8f5d5d695dULL, 0x8050209010104010ULL,
-	0xf303f507f4f4f7f4ULL, 0x16c08bddcbcb0bcbULL, 0xedc67cd33e3ef83eULL,
-	0x28110a2d05051405ULL, 0x1fe6ce7867678167ULL, 0x7353d597e4e4b7e4ULL,
-	0x25bb4e0227279c27ULL, 0x3258827341411941ULL, 0x2c9d0ba78b8b168bULL,
-	0x510153f6a7a7a6a7ULL, 0xcf94fab27d7de97dULL, 0xdcfb374995956e95ULL,
-	0x8e9fad56d8d847d8ULL, 0x8b30eb70fbfbcbfbULL, 0x2371c1cdeeee9feeULL,
-	0xc791f8bb7c7ced7cULL, 0x17e3cc7166668566ULL, 0xa68ea77bdddd53ddULL,
-	0xb84b2eaf17175c17ULL, 0x02468e4547470147ULL, 0x84dc211a9e9e429eULL,
-	0x1ec589d4caca0fcaULL, 0x75995a582d2db42dULL, 0x9179632ebfbfc6bfULL,
-	0x381b0e3f07071c07ULL, 0x012347acadad8eadULL, 0xea2fb4b05a5a755aULL,
-	0x6cb51bef83833683ULL, 0x85ff66b63333cc33ULL, 0x3ff2c65c63639163ULL,
-	0x100a041202020802ULL, 0x39384993aaaa92aaULL, 0xafa8e2de7171d971ULL,
-	0x0ecf8dc6c8c807c8ULL, 0xc87d32d119196419ULL, 0x7270923b49493949ULL,
-	0x869aaf5fd9d943d9ULL, 0xc31df931f2f2eff2ULL, 0x4b48dba8e3e3abe3ULL,
-	0xe22ab6b95b5b715bULL, 0x34920dbc88881a88ULL, 0xa4c8293e9a9a529aULL,
-	0x2dbe4c0b26269826ULL, 0x8dfa64bf3232c832ULL, 0xe94a7d59b0b0fab0ULL,
-	0x1b6acff2e9e983e9ULL, 0x78331e770f0f3c0fULL, 0xe6a6b733d5d573d5ULL,
-	0x74ba1df480803a80ULL, 0x997c6127bebec2beULL, 0x26de87ebcdcd13cdULL,
-	0xbde468893434d034ULL, 0x7a75903248483d48ULL, 0xab24e354ffffdbffULL,
-	0xf78ff48d7a7af57aULL, 0xf4ea3d6490907a90ULL, 0xc23ebe9d5f5f615fULL,
-	0x1da0403d20208020ULL, 0x67d5d00f6868bd68ULL, 0xd07234ca1a1a681aULL,
-	0x192c41b7aeae82aeULL, 0xc95e757db4b4eab4ULL, 0x9a19a8ce54544d54ULL,
-	0xece53b7f93937693ULL, 0x0daa442f22228822ULL, 0x07e9c86364648d64ULL,
-	0xdb12ff2af1f1e3f1ULL, 0xbfa2e6cc7373d173ULL, 0x905a248212124812ULL,
-	0x3a5d807a40401d40ULL, 0x4028104808082008ULL, 0x56e89b95c3c32bc3ULL,
-	0x337bc5dfecec97ecULL, 0x9690ab4ddbdb4bdbULL, 0x611f5fc0a1a1bea1ULL,
-	0x1c8307918d8d0e8dULL, 0xf5c97ac83d3df43dULL, 0xccf1335b97976697ULL,
-	0x0000000000000000ULL, 0x36d483f9cfcf1bcfULL, 0x4587566e2b2bac2bULL,
-	0x97b3ece17676c576ULL, 0x64b019e682823282ULL, 0xfea9b128d6d67fd6ULL,
-	0xd87736c31b1b6c1bULL, 0xc15b7774b5b5eeb5ULL, 0x112943beafaf86afULL,
-	0x77dfd41d6a6ab56aULL, 0xba0da0ea50505d50ULL, 0x124c8a5745450945ULL,
-	0xcb18fb38f3f3ebf3ULL, 0x9df060ad3030c030ULL, 0x2b74c3c4efef9befULL,
-	0xe5c37eda3f3ffc3fULL, 0x921caac755554955ULL, 0x791059dba2a2b2a2ULL,
-	0x0365c9e9eaea8feaULL, 0x0fecca6a65658965ULL, 0xb9686903babad2baULL,
-	0x65935e4a2f2fbc2fULL, 0x4ee79d8ec0c027c0ULL, 0xbe81a160dede5fdeULL,
-	0xe06c38fc1c1c701cULL, 0xbb2ee746fdfdd3fdULL, 0x52649a1f4d4d294dULL,
-	0xe4e0397692927292ULL, 0x8fbceafa7575c975ULL, 0x301e0c3606061806ULL,
-	0x249809ae8a8a128aULL, 0xf940794bb2b2f2b2ULL, 0x6359d185e6e6bfe6ULL,
-	0x70361c7e0e0e380eULL, 0xf8633ee71f1f7c1fULL, 0x37f7c45562629562ULL,
-	0xeea3b53ad4d477d4ULL, 0x29324d81a8a89aa8ULL, 0xc4f4315296966296ULL,
-	0x9b3aef62f9f9c3f9ULL, 0x66f697a3c5c533c5ULL, 0x35b14a1025259425ULL,
-	0xf220b2ab59597959ULL, 0x54ae15d084842a84ULL, 0xb7a7e4c57272d572ULL,
-	0xd5dd72ec3939e439ULL, 0x5a6198164c4c2d4cULL, 0xca3bbc945e5e655eULL,
-	0xe785f09f7878fd78ULL, 0xddd870e53838e038ULL, 0x148605988c8c0a8cULL,
-	0xc6b2bf17d1d163d1ULL, 0x410b57e4a5a5aea5ULL, 0x434dd9a1e2e2afe2ULL,
-	0x2ff8c24e61619961ULL, 0xf1457b42b3b3f6b3ULL, 0x15a5423421218421ULL,
-	0x94d625089c9c4a9cULL, 0xf0663cee1e1e781eULL, 0x2252866143431143ULL,
-	0x76fc93b1c7c73bc7ULL, 0xb32be54ffcfcd7fcULL, 0x2014082404041004ULL,
-	0xb208a2e351515951ULL, 0xbcc72f2599995e99ULL, 0x4fc4da226d6da96dULL,
-	0x68391a650d0d340dULL, 0x8335e979fafacffaULL, 0xb684a369dfdf5bdfULL,
-	0xd79bfca97e7ee57eULL, 0x3db4481924249024ULL, 0xc5d776fe3b3bec3bULL,
-	0x313d4b9aabab96abULL, 0x3ed181f0cece1fceULL, 0x8855229911114411ULL,
-	0x0c8903838f8f068fULL, 0x4a6b9c044e4e254eULL, 0xd1517366b7b7e6b7ULL,
-	0x0b60cbe0ebeb8bebULL, 0xfdcc78c13c3cf03cULL, 0x7cbf1ffd81813e81ULL,
-	0xd4fe354094946a94ULL, 0xeb0cf31cf7f7fbf7ULL, 0xa1676f18b9b9deb9ULL,
-	0x985f268b13134c13ULL, 0x7d9c58512c2cb02cULL, 0xd6b8bb05d3d36bd3ULL,
-	0x6b5cd38ce7e7bbe7ULL, 0x57cbdc396e6ea56eULL, 0x6ef395aac4c437c4ULL,
-	0x180f061b03030c03ULL, 0x8a13acdc56564556ULL, 0x1a49885e44440d44ULL,
-	0xdf9efea07f7fe17fULL, 0x21374f88a9a99ea9ULL, 0x4d8254672a2aa82aULL,
-	0xb16d6b0abbbbd6bbULL, 0x46e29f87c1c123c1ULL, 0xa202a6f153535153ULL,
-	0xae8ba572dcdc57dcULL, 0x582716530b0b2c0bULL, 0x9cd327019d9d4e9dULL,
-	0x47c1d82b6c6cad6cULL, 0x95f562a43131c431ULL, 0x87b9e8f37474cd74ULL,
-	0xe309f115f6f6fff6ULL, 0x0a438c4c46460546ULL, 0x092645a5acac8aacULL,
-	0x3c970fb589891e89ULL, 0xa04428b414145014ULL, 0x5b42dfbae1e1a3e1ULL,
-	0xb04e2ca616165816ULL, 0xcdd274f73a3ae83aULL, 0x6fd0d2066969b969ULL,
-	0x482d124109092409ULL, 0xa7ade0d77070dd70ULL, 0xd954716fb6b6e2b6ULL,
-	0xceb7bd1ed0d067d0ULL, 0x3b7ec7d6eded93edULL, 0x2edb85e2cccc17ccULL,
-	0x2a57846842421542ULL, 0xb4c22d2c98985a98ULL, 0x490e55eda4a4aaa4ULL,
-	0x5d8850752828a028ULL, 0xda31b8865c5c6d5cULL, 0x933fed6bf8f8c7f8ULL,
-	0x44a411c286862286ULL,
-};
-
-static const u64 C5[256] = {
-	0x18c07830d8181860ULL, 0x2305af462623238cULL, 0xc67ef991b8c6c63fULL,
-	0xe8136fcdfbe8e887ULL, 0x874ca113cb878726ULL, 0xb8a9626d11b8b8daULL,
-	0x0108050209010104ULL, 0x4f426e9e0d4f4f21ULL, 0x36adee6c9b3636d8ULL,
-	0xa6590451ffa6a6a2ULL, 0xd2debdb90cd2d26fULL, 0xf5fb06f70ef5f5f3ULL,
-	0x79ef80f2967979f9ULL, 0x6f5fcede306f6fa1ULL, 0x91fcef3f6d91917eULL,
-	0x52aa07a4f8525255ULL, 0x6027fdc04760609dULL, 0xbc89766535bcbccaULL,
-	0x9baccd2b379b9b56ULL, 0x8e048c018a8e8e02ULL, 0xa371155bd2a3a3b6ULL,
-	0x0c603c186c0c0c30ULL, 0x7bff8af6847b7bf1ULL, 0x35b5e16a803535d4ULL,
-	0x1de8693af51d1d74ULL, 0xe05347ddb3e0e0a7ULL, 0xd7f6acb321d7d77bULL,
-	0xc25eed999cc2c22fULL, 0x2e6d965c432e2eb8ULL, 0x4b627a96294b4b31ULL,
-	0xfea321e15dfefedfULL, 0x578216aed5575741ULL, 0x15a8412abd151554ULL,
-	0x779fb6eee87777c1ULL, 0x37a5eb6e923737dcULL, 0xe57b56d79ee5e5b3ULL,
-	0x9f8cd923139f9f46ULL, 0xf0d317fd23f0f0e7ULL, 0x4a6a7f94204a4a35ULL,
-	0xda9e95a944dada4fULL, 0x58fa25b0a258587dULL, 0xc906ca8fcfc9c903ULL,
-	0x29558d527c2929a4ULL, 0x0a5022145a0a0a28ULL, 0xb1e14f7f50b1b1feULL,
-	0xa0691a5dc9a0a0baULL, 0x6b7fdad6146b6bb1ULL, 0x855cab17d985852eULL,
-	0xbd8173673cbdbdceULL, 0x5dd234ba8f5d5d69ULL, 0x1080502090101040ULL,
-	0xf4f303f507f4f4f7ULL, 0xcb16c08bddcbcb0bULL, 0x3eedc67cd33e3ef8ULL,
-	0x0528110a2d050514ULL, 0x671fe6ce78676781ULL, 0xe47353d597e4e4b7ULL,
-	0x2725bb4e0227279cULL, 0x4132588273414119ULL, 0x8b2c9d0ba78b8b16ULL,
-	0xa7510153f6a7a7a6ULL, 0x7dcf94fab27d7de9ULL, 0x95dcfb374995956eULL,
-	0xd88e9fad56d8d847ULL, 0xfb8b30eb70fbfbcbULL, 0xee2371c1cdeeee9fULL,
-	0x7cc791f8bb7c7cedULL, 0x6617e3cc71666685ULL, 0xdda68ea77bdddd53ULL,
-	0x17b84b2eaf17175cULL, 0x4702468e45474701ULL, 0x9e84dc211a9e9e42ULL,
-	0xca1ec589d4caca0fULL, 0x2d75995a582d2db4ULL, 0xbf9179632ebfbfc6ULL,
-	0x07381b0e3f07071cULL, 0xad012347acadad8eULL, 0x5aea2fb4b05a5a75ULL,
-	0x836cb51bef838336ULL, 0x3385ff66b63333ccULL, 0x633ff2c65c636391ULL,
-	0x02100a0412020208ULL, 0xaa39384993aaaa92ULL, 0x71afa8e2de7171d9ULL,
-	0xc80ecf8dc6c8c807ULL, 0x19c87d32d1191964ULL, 0x497270923b494939ULL,
-	0xd9869aaf5fd9d943ULL, 0xf2c31df931f2f2efULL, 0xe34b48dba8e3e3abULL,
-	0x5be22ab6b95b5b71ULL, 0x8834920dbc88881aULL, 0x9aa4c8293e9a9a52ULL,
-	0x262dbe4c0b262698ULL, 0x328dfa64bf3232c8ULL, 0xb0e94a7d59b0b0faULL,
-	0xe91b6acff2e9e983ULL, 0x0f78331e770f0f3cULL, 0xd5e6a6b733d5d573ULL,
-	0x8074ba1df480803aULL, 0xbe997c6127bebec2ULL, 0xcd26de87ebcdcd13ULL,
-	0x34bde468893434d0ULL, 0x487a75903248483dULL, 0xffab24e354ffffdbULL,
-	0x7af78ff48d7a7af5ULL, 0x90f4ea3d6490907aULL, 0x5fc23ebe9d5f5f61ULL,
-	0x201da0403d202080ULL, 0x6867d5d00f6868bdULL, 0x1ad07234ca1a1a68ULL,
-	0xae192c41b7aeae82ULL, 0xb4c95e757db4b4eaULL, 0x549a19a8ce54544dULL,
-	0x93ece53b7f939376ULL, 0x220daa442f222288ULL, 0x6407e9c86364648dULL,
-	0xf1db12ff2af1f1e3ULL, 0x73bfa2e6cc7373d1ULL, 0x12905a2482121248ULL,
-	0x403a5d807a40401dULL, 0x0840281048080820ULL, 0xc356e89b95c3c32bULL,
-	0xec337bc5dfecec97ULL, 0xdb9690ab4ddbdb4bULL, 0xa1611f5fc0a1a1beULL,
-	0x8d1c8307918d8d0eULL, 0x3df5c97ac83d3df4ULL, 0x97ccf1335b979766ULL,
-	0x0000000000000000ULL, 0xcf36d483f9cfcf1bULL, 0x2b4587566e2b2bacULL,
-	0x7697b3ece17676c5ULL, 0x8264b019e6828232ULL, 0xd6fea9b128d6d67fULL,
-	0x1bd87736c31b1b6cULL, 0xb5c15b7774b5b5eeULL, 0xaf112943beafaf86ULL,
-	0x6a77dfd41d6a6ab5ULL, 0x50ba0da0ea50505dULL, 0x45124c8a57454509ULL,
-	0xf3cb18fb38f3f3ebULL, 0x309df060ad3030c0ULL, 0xef2b74c3c4efef9bULL,
-	0x3fe5c37eda3f3ffcULL, 0x55921caac7555549ULL, 0xa2791059dba2a2b2ULL,
-	0xea0365c9e9eaea8fULL, 0x650fecca6a656589ULL, 0xbab9686903babad2ULL,
-	0x2f65935e4a2f2fbcULL, 0xc04ee79d8ec0c027ULL, 0xdebe81a160dede5fULL,
-	0x1ce06c38fc1c1c70ULL, 0xfdbb2ee746fdfdd3ULL, 0x4d52649a1f4d4d29ULL,
-	0x92e4e03976929272ULL, 0x758fbceafa7575c9ULL, 0x06301e0c36060618ULL,
-	0x8a249809ae8a8a12ULL, 0xb2f940794bb2b2f2ULL, 0xe66359d185e6e6bfULL,
-	0x0e70361c7e0e0e38ULL, 0x1ff8633ee71f1f7cULL, 0x6237f7c455626295ULL,
-	0xd4eea3b53ad4d477ULL, 0xa829324d81a8a89aULL, 0x96c4f43152969662ULL,
-	0xf99b3aef62f9f9c3ULL, 0xc566f697a3c5c533ULL, 0x2535b14a10252594ULL,
-	0x59f220b2ab595979ULL, 0x8454ae15d084842aULL, 0x72b7a7e4c57272d5ULL,
-	0x39d5dd72ec3939e4ULL, 0x4c5a6198164c4c2dULL, 0x5eca3bbc945e5e65ULL,
-	0x78e785f09f7878fdULL, 0x38ddd870e53838e0ULL, 0x8c148605988c8c0aULL,
-	0xd1c6b2bf17d1d163ULL, 0xa5410b57e4a5a5aeULL, 0xe2434dd9a1e2e2afULL,
-	0x612ff8c24e616199ULL, 0xb3f1457b42b3b3f6ULL, 0x2115a54234212184ULL,
-	0x9c94d625089c9c4aULL, 0x1ef0663cee1e1e78ULL, 0x4322528661434311ULL,
-	0xc776fc93b1c7c73bULL, 0xfcb32be54ffcfcd7ULL, 0x0420140824040410ULL,
-	0x51b208a2e3515159ULL, 0x99bcc72f2599995eULL, 0x6d4fc4da226d6da9ULL,
-	0x0d68391a650d0d34ULL, 0xfa8335e979fafacfULL, 0xdfb684a369dfdf5bULL,
-	0x7ed79bfca97e7ee5ULL, 0x243db44819242490ULL, 0x3bc5d776fe3b3becULL,
-	0xab313d4b9aabab96ULL, 0xce3ed181f0cece1fULL, 0x1188552299111144ULL,
-	0x8f0c8903838f8f06ULL, 0x4e4a6b9c044e4e25ULL, 0xb7d1517366b7b7e6ULL,
-	0xeb0b60cbe0ebeb8bULL, 0x3cfdcc78c13c3cf0ULL, 0x817cbf1ffd81813eULL,
-	0x94d4fe354094946aULL, 0xf7eb0cf31cf7f7fbULL, 0xb9a1676f18b9b9deULL,
-	0x13985f268b13134cULL, 0x2c7d9c58512c2cb0ULL, 0xd3d6b8bb05d3d36bULL,
-	0xe76b5cd38ce7e7bbULL, 0x6e57cbdc396e6ea5ULL, 0xc46ef395aac4c437ULL,
-	0x03180f061b03030cULL, 0x568a13acdc565645ULL, 0x441a49885e44440dULL,
-	0x7fdf9efea07f7fe1ULL, 0xa921374f88a9a99eULL, 0x2a4d8254672a2aa8ULL,
-	0xbbb16d6b0abbbbd6ULL, 0xc146e29f87c1c123ULL, 0x53a202a6f1535351ULL,
-	0xdcae8ba572dcdc57ULL, 0x0b582716530b0b2cULL, 0x9d9cd327019d9d4eULL,
-	0x6c47c1d82b6c6cadULL, 0x3195f562a43131c4ULL, 0x7487b9e8f37474cdULL,
-	0xf6e309f115f6f6ffULL, 0x460a438c4c464605ULL, 0xac092645a5acac8aULL,
-	0x893c970fb589891eULL, 0x14a04428b4141450ULL, 0xe15b42dfbae1e1a3ULL,
-	0x16b04e2ca6161658ULL, 0x3acdd274f73a3ae8ULL, 0x696fd0d2066969b9ULL,
-	0x09482d1241090924ULL, 0x70a7ade0d77070ddULL, 0xb6d954716fb6b6e2ULL,
-	0xd0ceb7bd1ed0d067ULL, 0xed3b7ec7d6eded93ULL, 0xcc2edb85e2cccc17ULL,
-	0x422a578468424215ULL, 0x98b4c22d2c98985aULL, 0xa4490e55eda4a4aaULL,
-	0x285d8850752828a0ULL, 0x5cda31b8865c5c6dULL, 0xf8933fed6bf8f8c7ULL,
-	0x8644a411c2868622ULL,
-};
-
-static const u64 C6[256] = {
-	0x6018c07830d81818ULL, 0x8c2305af46262323ULL, 0x3fc67ef991b8c6c6ULL,
-	0x87e8136fcdfbe8e8ULL, 0x26874ca113cb8787ULL, 0xdab8a9626d11b8b8ULL,
-	0x0401080502090101ULL, 0x214f426e9e0d4f4fULL, 0xd836adee6c9b3636ULL,
-	0xa2a6590451ffa6a6ULL, 0x6fd2debdb90cd2d2ULL, 0xf3f5fb06f70ef5f5ULL,
-	0xf979ef80f2967979ULL, 0xa16f5fcede306f6fULL, 0x7e91fcef3f6d9191ULL,
-	0x5552aa07a4f85252ULL, 0x9d6027fdc0476060ULL, 0xcabc89766535bcbcULL,
-	0x569baccd2b379b9bULL, 0x028e048c018a8e8eULL, 0xb6a371155bd2a3a3ULL,
-	0x300c603c186c0c0cULL, 0xf17bff8af6847b7bULL, 0xd435b5e16a803535ULL,
-	0x741de8693af51d1dULL, 0xa7e05347ddb3e0e0ULL, 0x7bd7f6acb321d7d7ULL,
-	0x2fc25eed999cc2c2ULL, 0xb82e6d965c432e2eULL, 0x314b627a96294b4bULL,
-	0xdffea321e15dfefeULL, 0x41578216aed55757ULL, 0x5415a8412abd1515ULL,
-	0xc1779fb6eee87777ULL, 0xdc37a5eb6e923737ULL, 0xb3e57b56d79ee5e5ULL,
-	0x469f8cd923139f9fULL, 0xe7f0d317fd23f0f0ULL, 0x354a6a7f94204a4aULL,
-	0x4fda9e95a944dadaULL, 0x7d58fa25b0a25858ULL, 0x03c906ca8fcfc9c9ULL,
-	0xa429558d527c2929ULL, 0x280a5022145a0a0aULL, 0xfeb1e14f7f50b1b1ULL,
-	0xbaa0691a5dc9a0a0ULL, 0xb16b7fdad6146b6bULL, 0x2e855cab17d98585ULL,
-	0xcebd8173673cbdbdULL, 0x695dd234ba8f5d5dULL, 0x4010805020901010ULL,
-	0xf7f4f303f507f4f4ULL, 0x0bcb16c08bddcbcbULL, 0xf83eedc67cd33e3eULL,
-	0x140528110a2d0505ULL, 0x81671fe6ce786767ULL, 0xb7e47353d597e4e4ULL,
-	0x9c2725bb4e022727ULL, 0x1941325882734141ULL, 0x168b2c9d0ba78b8bULL,
-	0xa6a7510153f6a7a7ULL, 0xe97dcf94fab27d7dULL, 0x6e95dcfb37499595ULL,
-	0x47d88e9fad56d8d8ULL, 0xcbfb8b30eb70fbfbULL, 0x9fee2371c1cdeeeeULL,
-	0xed7cc791f8bb7c7cULL, 0x856617e3cc716666ULL, 0x53dda68ea77bddddULL,
-	0x5c17b84b2eaf1717ULL, 0x014702468e454747ULL, 0x429e84dc211a9e9eULL,
-	0x0fca1ec589d4cacaULL, 0xb42d75995a582d2dULL, 0xc6bf9179632ebfbfULL,
-	0x1c07381b0e3f0707ULL, 0x8ead012347acadadULL, 0x755aea2fb4b05a5aULL,
-	0x36836cb51bef8383ULL, 0xcc3385ff66b63333ULL, 0x91633ff2c65c6363ULL,
-	0x0802100a04120202ULL, 0x92aa39384993aaaaULL, 0xd971afa8e2de7171ULL,
-	0x07c80ecf8dc6c8c8ULL, 0x6419c87d32d11919ULL, 0x39497270923b4949ULL,
-	0x43d9869aaf5fd9d9ULL, 0xeff2c31df931f2f2ULL, 0xabe34b48dba8e3e3ULL,
-	0x715be22ab6b95b5bULL, 0x1a8834920dbc8888ULL, 0x529aa4c8293e9a9aULL,
-	0x98262dbe4c0b2626ULL, 0xc8328dfa64bf3232ULL, 0xfab0e94a7d59b0b0ULL,
-	0x83e91b6acff2e9e9ULL, 0x3c0f78331e770f0fULL, 0x73d5e6a6b733d5d5ULL,
-	0x3a8074ba1df48080ULL, 0xc2be997c6127bebeULL, 0x13cd26de87ebcdcdULL,
-	0xd034bde468893434ULL, 0x3d487a7590324848ULL, 0xdbffab24e354ffffULL,
-	0xf57af78ff48d7a7aULL, 0x7a90f4ea3d649090ULL, 0x615fc23ebe9d5f5fULL,
-	0x80201da0403d2020ULL, 0xbd6867d5d00f6868ULL, 0x681ad07234ca1a1aULL,
-	0x82ae192c41b7aeaeULL, 0xeab4c95e757db4b4ULL, 0x4d549a19a8ce5454ULL,
-	0x7693ece53b7f9393ULL, 0x88220daa442f2222ULL, 0x8d6407e9c8636464ULL,
-	0xe3f1db12ff2af1f1ULL, 0xd173bfa2e6cc7373ULL, 0x4812905a24821212ULL,
-	0x1d403a5d807a4040ULL, 0x2008402810480808ULL, 0x2bc356e89b95c3c3ULL,
-	0x97ec337bc5dfececULL, 0x4bdb9690ab4ddbdbULL, 0xbea1611f5fc0a1a1ULL,
-	0x0e8d1c8307918d8dULL, 0xf43df5c97ac83d3dULL, 0x6697ccf1335b9797ULL,
-	0x0000000000000000ULL, 0x1bcf36d483f9cfcfULL, 0xac2b4587566e2b2bULL,
-	0xc57697b3ece17676ULL, 0x328264b019e68282ULL, 0x7fd6fea9b128d6d6ULL,
-	0x6c1bd87736c31b1bULL, 0xeeb5c15b7774b5b5ULL, 0x86af112943beafafULL,
-	0xb56a77dfd41d6a6aULL, 0x5d50ba0da0ea5050ULL, 0x0945124c8a574545ULL,
-	0xebf3cb18fb38f3f3ULL, 0xc0309df060ad3030ULL, 0x9bef2b74c3c4efefULL,
-	0xfc3fe5c37eda3f3fULL, 0x4955921caac75555ULL, 0xb2a2791059dba2a2ULL,
-	0x8fea0365c9e9eaeaULL, 0x89650fecca6a6565ULL, 0xd2bab9686903babaULL,
-	0xbc2f65935e4a2f2fULL, 0x27c04ee79d8ec0c0ULL, 0x5fdebe81a160dedeULL,
-	0x701ce06c38fc1c1cULL, 0xd3fdbb2ee746fdfdULL, 0x294d52649a1f4d4dULL,
-	0x7292e4e039769292ULL, 0xc9758fbceafa7575ULL, 0x1806301e0c360606ULL,
-	0x128a249809ae8a8aULL, 0xf2b2f940794bb2b2ULL, 0xbfe66359d185e6e6ULL,
-	0x380e70361c7e0e0eULL, 0x7c1ff8633ee71f1fULL, 0x956237f7c4556262ULL,
-	0x77d4eea3b53ad4d4ULL, 0x9aa829324d81a8a8ULL, 0x6296c4f431529696ULL,
-	0xc3f99b3aef62f9f9ULL, 0x33c566f697a3c5c5ULL, 0x942535b14a102525ULL,
-	0x7959f220b2ab5959ULL, 0x2a8454ae15d08484ULL, 0xd572b7a7e4c57272ULL,
-	0xe439d5dd72ec3939ULL, 0x2d4c5a6198164c4cULL, 0x655eca3bbc945e5eULL,
-	0xfd78e785f09f7878ULL, 0xe038ddd870e53838ULL, 0x0a8c148605988c8cULL,
-	0x63d1c6b2bf17d1d1ULL, 0xaea5410b57e4a5a5ULL, 0xafe2434dd9a1e2e2ULL,
-	0x99612ff8c24e6161ULL, 0xf6b3f1457b42b3b3ULL, 0x842115a542342121ULL,
-	0x4a9c94d625089c9cULL, 0x781ef0663cee1e1eULL, 0x1143225286614343ULL,
-	0x3bc776fc93b1c7c7ULL, 0xd7fcb32be54ffcfcULL, 0x1004201408240404ULL,
-	0x5951b208a2e35151ULL, 0x5e99bcc72f259999ULL, 0xa96d4fc4da226d6dULL,
-	0x340d68391a650d0dULL, 0xcffa8335e979fafaULL, 0x5bdfb684a369dfdfULL,
-	0xe57ed79bfca97e7eULL, 0x90243db448192424ULL, 0xec3bc5d776fe3b3bULL,
-	0x96ab313d4b9aababULL, 0x1fce3ed181f0ceceULL, 0x4411885522991111ULL,
-	0x068f0c8903838f8fULL, 0x254e4a6b9c044e4eULL, 0xe6b7d1517366b7b7ULL,
-	0x8beb0b60cbe0ebebULL, 0xf03cfdcc78c13c3cULL, 0x3e817cbf1ffd8181ULL,
-	0x6a94d4fe35409494ULL, 0xfbf7eb0cf31cf7f7ULL, 0xdeb9a1676f18b9b9ULL,
-	0x4c13985f268b1313ULL, 0xb02c7d9c58512c2cULL, 0x6bd3d6b8bb05d3d3ULL,
-	0xbbe76b5cd38ce7e7ULL, 0xa56e57cbdc396e6eULL, 0x37c46ef395aac4c4ULL,
-	0x0c03180f061b0303ULL, 0x45568a13acdc5656ULL, 0x0d441a49885e4444ULL,
-	0xe17fdf9efea07f7fULL, 0x9ea921374f88a9a9ULL, 0xa82a4d8254672a2aULL,
-	0xd6bbb16d6b0abbbbULL, 0x23c146e29f87c1c1ULL, 0x5153a202a6f15353ULL,
-	0x57dcae8ba572dcdcULL, 0x2c0b582716530b0bULL, 0x4e9d9cd327019d9dULL,
-	0xad6c47c1d82b6c6cULL, 0xc43195f562a43131ULL, 0xcd7487b9e8f37474ULL,
-	0xfff6e309f115f6f6ULL, 0x05460a438c4c4646ULL, 0x8aac092645a5acacULL,
-	0x1e893c970fb58989ULL, 0x5014a04428b41414ULL, 0xa3e15b42dfbae1e1ULL,
-	0x5816b04e2ca61616ULL, 0xe83acdd274f73a3aULL, 0xb9696fd0d2066969ULL,
-	0x2409482d12410909ULL, 0xdd70a7ade0d77070ULL, 0xe2b6d954716fb6b6ULL,
-	0x67d0ceb7bd1ed0d0ULL, 0x93ed3b7ec7d6ededULL, 0x17cc2edb85e2ccccULL,
-	0x15422a5784684242ULL, 0x5a98b4c22d2c9898ULL, 0xaaa4490e55eda4a4ULL,
-	0xa0285d8850752828ULL, 0x6d5cda31b8865c5cULL, 0xc7f8933fed6bf8f8ULL,
-	0x228644a411c28686ULL,
-};
-
-static const u64 C7[256] = {
-	0x186018c07830d818ULL, 0x238c2305af462623ULL, 0xc63fc67ef991b8c6ULL,
-	0xe887e8136fcdfbe8ULL, 0x8726874ca113cb87ULL, 0xb8dab8a9626d11b8ULL,
-	0x0104010805020901ULL, 0x4f214f426e9e0d4fULL, 0x36d836adee6c9b36ULL,
-	0xa6a2a6590451ffa6ULL, 0xd26fd2debdb90cd2ULL, 0xf5f3f5fb06f70ef5ULL,
-	0x79f979ef80f29679ULL, 0x6fa16f5fcede306fULL, 0x917e91fcef3f6d91ULL,
-	0x525552aa07a4f852ULL, 0x609d6027fdc04760ULL, 0xbccabc89766535bcULL,
-	0x9b569baccd2b379bULL, 0x8e028e048c018a8eULL, 0xa3b6a371155bd2a3ULL,
-	0x0c300c603c186c0cULL, 0x7bf17bff8af6847bULL, 0x35d435b5e16a8035ULL,
-	0x1d741de8693af51dULL, 0xe0a7e05347ddb3e0ULL, 0xd77bd7f6acb321d7ULL,
-	0xc22fc25eed999cc2ULL, 0x2eb82e6d965c432eULL, 0x4b314b627a96294bULL,
-	0xfedffea321e15dfeULL, 0x5741578216aed557ULL, 0x155415a8412abd15ULL,
-	0x77c1779fb6eee877ULL, 0x37dc37a5eb6e9237ULL, 0xe5b3e57b56d79ee5ULL,
-	0x9f469f8cd923139fULL, 0xf0e7f0d317fd23f0ULL, 0x4a354a6a7f94204aULL,
-	0xda4fda9e95a944daULL, 0x587d58fa25b0a258ULL, 0xc903c906ca8fcfc9ULL,
-	0x29a429558d527c29ULL, 0x0a280a5022145a0aULL, 0xb1feb1e14f7f50b1ULL,
-	0xa0baa0691a5dc9a0ULL, 0x6bb16b7fdad6146bULL, 0x852e855cab17d985ULL,
-	0xbdcebd8173673cbdULL, 0x5d695dd234ba8f5dULL, 0x1040108050209010ULL,
-	0xf4f7f4f303f507f4ULL, 0xcb0bcb16c08bddcbULL, 0x3ef83eedc67cd33eULL,
-	0x05140528110a2d05ULL, 0x6781671fe6ce7867ULL, 0xe4b7e47353d597e4ULL,
-	0x279c2725bb4e0227ULL, 0x4119413258827341ULL, 0x8b168b2c9d0ba78bULL,
-	0xa7a6a7510153f6a7ULL, 0x7de97dcf94fab27dULL, 0x956e95dcfb374995ULL,
-	0xd847d88e9fad56d8ULL, 0xfbcbfb8b30eb70fbULL, 0xee9fee2371c1cdeeULL,
-	0x7ced7cc791f8bb7cULL, 0x66856617e3cc7166ULL, 0xdd53dda68ea77bddULL,
-	0x175c17b84b2eaf17ULL, 0x47014702468e4547ULL, 0x9e429e84dc211a9eULL,
-	0xca0fca1ec589d4caULL, 0x2db42d75995a582dULL, 0xbfc6bf9179632ebfULL,
-	0x071c07381b0e3f07ULL, 0xad8ead012347acadULL, 0x5a755aea2fb4b05aULL,
-	0x8336836cb51bef83ULL, 0x33cc3385ff66b633ULL, 0x6391633ff2c65c63ULL,
-	0x020802100a041202ULL, 0xaa92aa39384993aaULL, 0x71d971afa8e2de71ULL,
-	0xc807c80ecf8dc6c8ULL, 0x196419c87d32d119ULL, 0x4939497270923b49ULL,
-	0xd943d9869aaf5fd9ULL, 0xf2eff2c31df931f2ULL, 0xe3abe34b48dba8e3ULL,
-	0x5b715be22ab6b95bULL, 0x881a8834920dbc88ULL, 0x9a529aa4c8293e9aULL,
-	0x2698262dbe4c0b26ULL, 0x32c8328dfa64bf32ULL, 0xb0fab0e94a7d59b0ULL,
-	0xe983e91b6acff2e9ULL, 0x0f3c0f78331e770fULL, 0xd573d5e6a6b733d5ULL,
-	0x803a8074ba1df480ULL, 0xbec2be997c6127beULL, 0xcd13cd26de87ebcdULL,
-	0x34d034bde4688934ULL, 0x483d487a75903248ULL, 0xffdbffab24e354ffULL,
-	0x7af57af78ff48d7aULL, 0x907a90f4ea3d6490ULL, 0x5f615fc23ebe9d5fULL,
-	0x2080201da0403d20ULL, 0x68bd6867d5d00f68ULL, 0x1a681ad07234ca1aULL,
-	0xae82ae192c41b7aeULL, 0xb4eab4c95e757db4ULL, 0x544d549a19a8ce54ULL,
-	0x937693ece53b7f93ULL, 0x2288220daa442f22ULL, 0x648d6407e9c86364ULL,
-	0xf1e3f1db12ff2af1ULL, 0x73d173bfa2e6cc73ULL, 0x124812905a248212ULL,
-	0x401d403a5d807a40ULL, 0x0820084028104808ULL, 0xc32bc356e89b95c3ULL,
-	0xec97ec337bc5dfecULL, 0xdb4bdb9690ab4ddbULL, 0xa1bea1611f5fc0a1ULL,
-	0x8d0e8d1c8307918dULL, 0x3df43df5c97ac83dULL, 0x976697ccf1335b97ULL,
-	0x0000000000000000ULL, 0xcf1bcf36d483f9cfULL, 0x2bac2b4587566e2bULL,
-	0x76c57697b3ece176ULL, 0x82328264b019e682ULL, 0xd67fd6fea9b128d6ULL,
-	0x1b6c1bd87736c31bULL, 0xb5eeb5c15b7774b5ULL, 0xaf86af112943beafULL,
-	0x6ab56a77dfd41d6aULL, 0x505d50ba0da0ea50ULL, 0x450945124c8a5745ULL,
-	0xf3ebf3cb18fb38f3ULL, 0x30c0309df060ad30ULL, 0xef9bef2b74c3c4efULL,
-	0x3ffc3fe5c37eda3fULL, 0x554955921caac755ULL, 0xa2b2a2791059dba2ULL,
-	0xea8fea0365c9e9eaULL, 0x6589650fecca6a65ULL, 0xbad2bab9686903baULL,
-	0x2fbc2f65935e4a2fULL, 0xc027c04ee79d8ec0ULL, 0xde5fdebe81a160deULL,
-	0x1c701ce06c38fc1cULL, 0xfdd3fdbb2ee746fdULL, 0x4d294d52649a1f4dULL,
-	0x927292e4e0397692ULL, 0x75c9758fbceafa75ULL, 0x061806301e0c3606ULL,
-	0x8a128a249809ae8aULL, 0xb2f2b2f940794bb2ULL, 0xe6bfe66359d185e6ULL,
-	0x0e380e70361c7e0eULL, 0x1f7c1ff8633ee71fULL, 0x62956237f7c45562ULL,
-	0xd477d4eea3b53ad4ULL, 0xa89aa829324d81a8ULL, 0x966296c4f4315296ULL,
-	0xf9c3f99b3aef62f9ULL, 0xc533c566f697a3c5ULL, 0x25942535b14a1025ULL,
-	0x597959f220b2ab59ULL, 0x842a8454ae15d084ULL, 0x72d572b7a7e4c572ULL,
-	0x39e439d5dd72ec39ULL, 0x4c2d4c5a6198164cULL, 0x5e655eca3bbc945eULL,
-	0x78fd78e785f09f78ULL, 0x38e038ddd870e538ULL, 0x8c0a8c148605988cULL,
-	0xd163d1c6b2bf17d1ULL, 0xa5aea5410b57e4a5ULL, 0xe2afe2434dd9a1e2ULL,
-	0x6199612ff8c24e61ULL, 0xb3f6b3f1457b42b3ULL, 0x21842115a5423421ULL,
-	0x9c4a9c94d625089cULL, 0x1e781ef0663cee1eULL, 0x4311432252866143ULL,
-	0xc73bc776fc93b1c7ULL, 0xfcd7fcb32be54ffcULL, 0x0410042014082404ULL,
-	0x515951b208a2e351ULL, 0x995e99bcc72f2599ULL, 0x6da96d4fc4da226dULL,
-	0x0d340d68391a650dULL, 0xfacffa8335e979faULL, 0xdf5bdfb684a369dfULL,
-	0x7ee57ed79bfca97eULL, 0x2490243db4481924ULL, 0x3bec3bc5d776fe3bULL,
-	0xab96ab313d4b9aabULL, 0xce1fce3ed181f0ceULL, 0x1144118855229911ULL,
-	0x8f068f0c8903838fULL, 0x4e254e4a6b9c044eULL, 0xb7e6b7d1517366b7ULL,
-	0xeb8beb0b60cbe0ebULL, 0x3cf03cfdcc78c13cULL, 0x813e817cbf1ffd81ULL,
-	0x946a94d4fe354094ULL, 0xf7fbf7eb0cf31cf7ULL, 0xb9deb9a1676f18b9ULL,
-	0x134c13985f268b13ULL, 0x2cb02c7d9c58512cULL, 0xd36bd3d6b8bb05d3ULL,
-	0xe7bbe76b5cd38ce7ULL, 0x6ea56e57cbdc396eULL, 0xc437c46ef395aac4ULL,
-	0x030c03180f061b03ULL, 0x5645568a13acdc56ULL, 0x440d441a49885e44ULL,
-	0x7fe17fdf9efea07fULL, 0xa99ea921374f88a9ULL, 0x2aa82a4d8254672aULL,
-	0xbbd6bbb16d6b0abbULL, 0xc123c146e29f87c1ULL, 0x535153a202a6f153ULL,
-	0xdc57dcae8ba572dcULL, 0x0b2c0b582716530bULL, 0x9d4e9d9cd327019dULL,
-	0x6cad6c47c1d82b6cULL, 0x31c43195f562a431ULL, 0x74cd7487b9e8f374ULL,
-	0xf6fff6e309f115f6ULL, 0x4605460a438c4c46ULL, 0xac8aac092645a5acULL,
-	0x891e893c970fb589ULL, 0x145014a04428b414ULL, 0xe1a3e15b42dfbae1ULL,
-	0x165816b04e2ca616ULL, 0x3ae83acdd274f73aULL, 0x69b9696fd0d20669ULL,
-	0x092409482d124109ULL, 0x70dd70a7ade0d770ULL, 0xb6e2b6d954716fb6ULL,
-	0xd067d0ceb7bd1ed0ULL, 0xed93ed3b7ec7d6edULL, 0xcc17cc2edb85e2ccULL,
-	0x4215422a57846842ULL, 0x985a98b4c22d2c98ULL, 0xa4aaa4490e55eda4ULL,
-	0x28a0285d88507528ULL, 0x5c6d5cda31b8865cULL, 0xf8c7f8933fed6bf8ULL,
-	0x86228644a411c286ULL,
-};
-
-static const u64 rc[WHIRLPOOL_ROUNDS + 1] = {
-	0x0000000000000000ULL, 0x1823c6e887b8014fULL, 0x36a6d2f5796f9152ULL,
-	0x60bc9b8ea30c7b35ULL, 0x1de0d7c22e4bfe57ULL, 0x157737e59ff04adaULL,
-	0x58c9290ab1a06b85ULL, 0xbd5d10f4cb3e0567ULL, 0xe427418ba77d95d8ULL,
-	0xfbee7c66dd17479eULL, 0xca2dbf07ad5a8333ULL,
-};
-
-/**
- * The core Whirlpool transform.
- */
-
-static void whirlpool_process_buffer(struct whirlpool_ctx *wctx) {
-	int i, r;
-	u64 K[8];        /* the round key */
-	u64 block[8];    /* mu(buffer) */
-	u64 state[8];    /* the cipher state */
-	u64 L[8];
-	u8 *buffer = wctx->buffer;
-
-	for (i = 0; i < 8; i++, buffer += 8) {
-		block[i] =
-		(((u64)buffer[0]        ) << 56) ^
-		(((u64)buffer[1] & 0xffL) << 48) ^
-		(((u64)buffer[2] & 0xffL) << 40) ^
-		(((u64)buffer[3] & 0xffL) << 32) ^
-		(((u64)buffer[4] & 0xffL) << 24) ^
-		(((u64)buffer[5] & 0xffL) << 16) ^
-		(((u64)buffer[6] & 0xffL) <<  8) ^
-		(((u64)buffer[7] & 0xffL)      );
-	}
-
-	state[0] = block[0] ^ (K[0] = wctx->hash[0]);
-	state[1] = block[1] ^ (K[1] = wctx->hash[1]);
-	state[2] = block[2] ^ (K[2] = wctx->hash[2]);
-	state[3] = block[3] ^ (K[3] = wctx->hash[3]);
-	state[4] = block[4] ^ (K[4] = wctx->hash[4]);
-	state[5] = block[5] ^ (K[5] = wctx->hash[5]);
-	state[6] = block[6] ^ (K[6] = wctx->hash[6]);
-	state[7] = block[7] ^ (K[7] = wctx->hash[7]);
-
-	for (r = 1; r <= WHIRLPOOL_ROUNDS; r++) {
-
-		L[0] = C0[(int)(K[0] >> 56)       ] ^
-			   C1[(int)(K[7] >> 48) & 0xff] ^
-			   C2[(int)(K[6] >> 40) & 0xff] ^
-			   C3[(int)(K[5] >> 32) & 0xff] ^
-			   C4[(int)(K[4] >> 24) & 0xff] ^
-			   C5[(int)(K[3] >> 16) & 0xff] ^
-			   C6[(int)(K[2] >>  8) & 0xff] ^
-			   C7[(int)(K[1]      ) & 0xff] ^
-			   rc[r];
-
-		L[1] = C0[(int)(K[1] >> 56)       ] ^
-			   C1[(int)(K[0] >> 48) & 0xff] ^
-			   C2[(int)(K[7] >> 40) & 0xff] ^
-			   C3[(int)(K[6] >> 32) & 0xff] ^
-			   C4[(int)(K[5] >> 24) & 0xff] ^
-			   C5[(int)(K[4] >> 16) & 0xff] ^
-			   C6[(int)(K[3] >>  8) & 0xff] ^
-			   C7[(int)(K[2]      ) & 0xff];
-
-		L[2] = C0[(int)(K[2] >> 56)       ] ^
-			   C1[(int)(K[1] >> 48) & 0xff] ^
-			   C2[(int)(K[0] >> 40) & 0xff] ^
-			   C3[(int)(K[7] >> 32) & 0xff] ^
-			   C4[(int)(K[6] >> 24) & 0xff] ^
-			   C5[(int)(K[5] >> 16) & 0xff] ^
-			   C6[(int)(K[4] >>  8) & 0xff] ^
-			   C7[(int)(K[3]      ) & 0xff];
-
-		L[3] = C0[(int)(K[3] >> 56)       ] ^
-			   C1[(int)(K[2] >> 48) & 0xff] ^
-			   C2[(int)(K[1] >> 40) & 0xff] ^
-			   C3[(int)(K[0] >> 32) & 0xff] ^
-			   C4[(int)(K[7] >> 24) & 0xff] ^
-			   C5[(int)(K[6] >> 16) & 0xff] ^
-			   C6[(int)(K[5] >>  8) & 0xff] ^
-			   C7[(int)(K[4]      ) & 0xff];
-
-		L[4] = C0[(int)(K[4] >> 56)       ] ^
-			   C1[(int)(K[3] >> 48) & 0xff] ^
-			   C2[(int)(K[2] >> 40) & 0xff] ^
-			   C3[(int)(K[1] >> 32) & 0xff] ^
-			   C4[(int)(K[0] >> 24) & 0xff] ^
-			   C5[(int)(K[7] >> 16) & 0xff] ^
-			   C6[(int)(K[6] >>  8) & 0xff] ^
-			   C7[(int)(K[5]      ) & 0xff];
-
-		L[5] = C0[(int)(K[5] >> 56)       ] ^
-			   C1[(int)(K[4] >> 48) & 0xff] ^
-			   C2[(int)(K[3] >> 40) & 0xff] ^
-			   C3[(int)(K[2] >> 32) & 0xff] ^
-			   C4[(int)(K[1] >> 24) & 0xff] ^
-			   C5[(int)(K[0] >> 16) & 0xff] ^
-			   C6[(int)(K[7] >>  8) & 0xff] ^
-			   C7[(int)(K[6]      ) & 0xff];
-
-		L[6] = C0[(int)(K[6] >> 56)       ] ^
-			   C1[(int)(K[5] >> 48) & 0xff] ^
-			   C2[(int)(K[4] >> 40) & 0xff] ^
-			   C3[(int)(K[3] >> 32) & 0xff] ^
-			   C4[(int)(K[2] >> 24) & 0xff] ^
-			   C5[(int)(K[1] >> 16) & 0xff] ^
-			   C6[(int)(K[0] >>  8) & 0xff] ^
-			   C7[(int)(K[7]      ) & 0xff];
-
-		L[7] = C0[(int)(K[7] >> 56)       ] ^
-			   C1[(int)(K[6] >> 48) & 0xff] ^
-			   C2[(int)(K[5] >> 40) & 0xff] ^
-			   C3[(int)(K[4] >> 32) & 0xff] ^
-			   C4[(int)(K[3] >> 24) & 0xff] ^
-			   C5[(int)(K[2] >> 16) & 0xff] ^
-			   C6[(int)(K[1] >>  8) & 0xff] ^
-			   C7[(int)(K[0]      ) & 0xff];
-
-		K[0] = L[0];
-		K[1] = L[1];
-		K[2] = L[2];
-		K[3] = L[3];
-		K[4] = L[4];
-		K[5] = L[5];
-		K[6] = L[6];
-		K[7] = L[7];
-
-		L[0] = C0[(int)(state[0] >> 56)       ] ^
-			   C1[(int)(state[7] >> 48) & 0xff] ^
-			   C2[(int)(state[6] >> 40) & 0xff] ^
-			   C3[(int)(state[5] >> 32) & 0xff] ^
-			   C4[(int)(state[4] >> 24) & 0xff] ^
-			   C5[(int)(state[3] >> 16) & 0xff] ^
-			   C6[(int)(state[2] >>  8) & 0xff] ^
-			   C7[(int)(state[1]      ) & 0xff] ^
-			   K[0];
-
-		L[1] = C0[(int)(state[1] >> 56)       ] ^
-			   C1[(int)(state[0] >> 48) & 0xff] ^
-			   C2[(int)(state[7] >> 40) & 0xff] ^
-			   C3[(int)(state[6] >> 32) & 0xff] ^
-			   C4[(int)(state[5] >> 24) & 0xff] ^
-			   C5[(int)(state[4] >> 16) & 0xff] ^
-			   C6[(int)(state[3] >>  8) & 0xff] ^
-			   C7[(int)(state[2]      ) & 0xff] ^
-			   K[1];
-
-		L[2] = C0[(int)(state[2] >> 56)       ] ^
-			   C1[(int)(state[1] >> 48) & 0xff] ^
-			   C2[(int)(state[0] >> 40) & 0xff] ^
-			   C3[(int)(state[7] >> 32) & 0xff] ^
-			   C4[(int)(state[6] >> 24) & 0xff] ^
-			   C5[(int)(state[5] >> 16) & 0xff] ^
-			   C6[(int)(state[4] >>  8) & 0xff] ^
-			   C7[(int)(state[3]      ) & 0xff] ^
-			   K[2];
-
-		L[3] = C0[(int)(state[3] >> 56)       ] ^
-			   C1[(int)(state[2] >> 48) & 0xff] ^
-			   C2[(int)(state[1] >> 40) & 0xff] ^
-			   C3[(int)(state[0] >> 32) & 0xff] ^
-			   C4[(int)(state[7] >> 24) & 0xff] ^
-			   C5[(int)(state[6] >> 16) & 0xff] ^
-			   C6[(int)(state[5] >>  8) & 0xff] ^
-			   C7[(int)(state[4]      ) & 0xff] ^
-			   K[3];
-
-		L[4] = C0[(int)(state[4] >> 56)       ] ^
-			   C1[(int)(state[3] >> 48) & 0xff] ^
-			   C2[(int)(state[2] >> 40) & 0xff] ^
-			   C3[(int)(state[1] >> 32) & 0xff] ^
-			   C4[(int)(state[0] >> 24) & 0xff] ^
-			   C5[(int)(state[7] >> 16) & 0xff] ^
-			   C6[(int)(state[6] >>  8) & 0xff] ^
-			   C7[(int)(state[5]      ) & 0xff] ^
-			   K[4];
-
-		L[5] = C0[(int)(state[5] >> 56)       ] ^
-			   C1[(int)(state[4] >> 48) & 0xff] ^
-			   C2[(int)(state[3] >> 40) & 0xff] ^
-			   C3[(int)(state[2] >> 32) & 0xff] ^
-			   C4[(int)(state[1] >> 24) & 0xff] ^
-			   C5[(int)(state[0] >> 16) & 0xff] ^
-			   C6[(int)(state[7] >>  8) & 0xff] ^
-			   C7[(int)(state[6]      ) & 0xff] ^
-			   K[5];
-
-		L[6] = C0[(int)(state[6] >> 56)       ] ^
-			   C1[(int)(state[5] >> 48) & 0xff] ^
-			   C2[(int)(state[4] >> 40) & 0xff] ^
-			   C3[(int)(state[3] >> 32) & 0xff] ^
-			   C4[(int)(state[2] >> 24) & 0xff] ^
-			   C5[(int)(state[1] >> 16) & 0xff] ^
-			   C6[(int)(state[0] >>  8) & 0xff] ^
-			   C7[(int)(state[7]      ) & 0xff] ^
-			   K[6];
-
-		L[7] = C0[(int)(state[7] >> 56)       ] ^
-			   C1[(int)(state[6] >> 48) & 0xff] ^
-			   C2[(int)(state[5] >> 40) & 0xff] ^
-			   C3[(int)(state[4] >> 32) & 0xff] ^
-			   C4[(int)(state[3] >> 24) & 0xff] ^
-			   C5[(int)(state[2] >> 16) & 0xff] ^
-			   C6[(int)(state[1] >>  8) & 0xff] ^
-			   C7[(int)(state[0]      ) & 0xff] ^
-			   K[7];
-
-		state[0] = L[0];
-		state[1] = L[1];
-		state[2] = L[2];
-		state[3] = L[3];
-		state[4] = L[4];
-		state[5] = L[5];
-		state[6] = L[6];
-		state[7] = L[7];
-	}
-	/*
-	* apply the Miyaguchi-Preneel compression function:
-	*/
-	wctx->hash[0] ^= state[0] ^ block[0];
-	wctx->hash[1] ^= state[1] ^ block[1];
-	wctx->hash[2] ^= state[2] ^ block[2];
-	wctx->hash[3] ^= state[3] ^ block[3];
-	wctx->hash[4] ^= state[4] ^ block[4];
-	wctx->hash[5] ^= state[5] ^ block[5];
-	wctx->hash[6] ^= state[6] ^ block[6];
-	wctx->hash[7] ^= state[7] ^ block[7];
-
-}
-
-static void whirlpool_init (void *ctx) {
-	int i;
-	struct whirlpool_ctx *wctx = ctx;
-
-	memset(wctx->bitLength, 0, 32);
-	wctx->bufferBits = wctx->bufferPos = 0;
-	wctx->buffer[0] = 0;
-	for (i = 0; i < 8; i++) {
-		wctx->hash[i] = 0L;
-	}
-}
-
-static void whirlpool_update(void *ctx, const u8 *source, unsigned int len)
-{
-
-	struct whirlpool_ctx *wctx = ctx;
-	int sourcePos    = 0;
-	unsigned int bits_len = len * 8; // convert to number of bits
-	int sourceGap    = (8 - ((int)bits_len & 7)) & 7;
-	int bufferRem    = wctx->bufferBits & 7;
-	int i;
-	u32 b, carry;
-	u8 *buffer       = wctx->buffer;
-	u8 *bitLength    = wctx->bitLength;
-	int bufferBits   = wctx->bufferBits;
-	int bufferPos    = wctx->bufferPos;
-
-	u64 value = bits_len;
-	for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) {
-		carry += bitLength[i] + ((u32)value & 0xff);
-		bitLength[i] = (u8)carry;
-		carry >>= 8;
-		value >>= 8;
-	}
-	while (bits_len > 8) {
-		b = ((source[sourcePos] << sourceGap) & 0xff) |
-		((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
-		buffer[bufferPos++] |= (u8)(b >> bufferRem);
-		bufferBits += 8 - bufferRem;
-		if (bufferBits == WHIRLPOOL_DIGEST_SIZE * 8) {
-			whirlpool_process_buffer(wctx);
-			bufferBits = bufferPos = 0;
-		}
-		buffer[bufferPos] = b << (8 - bufferRem);
-		bufferBits += bufferRem;
-		bits_len -= 8;
-		sourcePos++;
-	}
-	if (bits_len > 0) {
-		b = (source[sourcePos] << sourceGap) & 0xff;
-		buffer[bufferPos] |= b >> bufferRem;
-	} else {
-		b = 0;
-	}
-	if (bufferRem + bits_len < 8) {
-		bufferBits += bits_len;
-	} else {
-		bufferPos++;
-		bufferBits += 8 - bufferRem;
-		bits_len -= 8 - bufferRem;
-		if (bufferBits == WHIRLPOOL_DIGEST_SIZE * 8) {
-			whirlpool_process_buffer(wctx);
-			bufferBits = bufferPos = 0;
-		}
-		buffer[bufferPos] = b << (8 - bufferRem);
-		bufferBits += (int)bits_len;
-	}
-
-	wctx->bufferBits   = bufferBits;
-	wctx->bufferPos    = bufferPos;
-
-}
-
-static void whirlpool_final(void *ctx, u8 *out)
-{
-	struct whirlpool_ctx *wctx = ctx;
-	int i;
-   	u8 *buffer      = wctx->buffer;
-   	u8 *bitLength   = wctx->bitLength;
-   	int bufferBits  = wctx->bufferBits;
-   	int bufferPos   = wctx->bufferPos;
-   	u8 *digest      = out;
-
-   	buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
-   	bufferPos++;
-   	if (bufferPos > WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES) {
-   		if (bufferPos < WHIRLPOOL_BLOCK_SIZE) {
-	   	memset(&buffer[bufferPos], 0, WHIRLPOOL_BLOCK_SIZE - bufferPos);
-   		}
-   		whirlpool_process_buffer(wctx);
-   		bufferPos = 0;
-   	}
-   	if (bufferPos < WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES) {
-   		memset(&buffer[bufferPos], 0,
-			  (WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES) - bufferPos);
-   	}
-   	bufferPos = WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES;
-   	memcpy(&buffer[WHIRLPOOL_BLOCK_SIZE - WHIRLPOOL_LENGTHBYTES],
-		   bitLength, WHIRLPOOL_LENGTHBYTES);
-   	whirlpool_process_buffer(wctx);
-   	for (i = 0; i < WHIRLPOOL_DIGEST_SIZE/8; i++) {
-		digest[0] = (u8)(wctx->hash[i] >> 56);
-		digest[1] = (u8)(wctx->hash[i] >> 48);
-		digest[2] = (u8)(wctx->hash[i] >> 40);
-		digest[3] = (u8)(wctx->hash[i] >> 32);
-		digest[4] = (u8)(wctx->hash[i] >> 24);
-		digest[5] = (u8)(wctx->hash[i] >> 16);
-		digest[6] = (u8)(wctx->hash[i] >>  8);
-		digest[7] = (u8)(wctx->hash[i]      );
-		digest += 8;
-   	}
-   	wctx->bufferBits   = bufferBits;
-   	wctx->bufferPos    = bufferPos;
-}
-
-static struct crypto_alg alg = {
-	.cra_name	=	"whirlpool",
-	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
-	.cra_blocksize	=	WHIRLPOOL_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct whirlpool_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),	
-	.cra_u		=	{ .digest = {
-	.dia_digestsize	=	WHIRLPOOL_DIGEST_SIZE,
-	.dia_init   	= 	whirlpool_init,
-	.dia_update 	=	whirlpool_update,
-	.dia_final  	=	whirlpool_final } }
-};
-
-static int __init init(void)
-{
-	return crypto_register_alg(&alg);
-}
-
-static void __exit fini(void)
-{
-	crypto_unregister_alg(&alg);
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm");
diff -urN linux-2.4.28-pre3/crypto/wp512.c linux-2.4.28-pre4/crypto/wp512.c
--- linux-2.4.28-pre3/crypto/wp512.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.28-pre4/crypto/wp512.c	2004-10-08 06:28:24.987232353 -0700
@@ -0,0 +1,1205 @@
+/*
+ * Cryptographic API.
+ *
+ * Whirlpool hashing Algorithm
+ *
+ * The Whirlpool algorithm was developed by Paulo S. L. M. Barreto and
+ * Vincent Rijmen.  It has been selected as one of cryptographic
+ * primitives by the NESSIE project http://www.cryptonessie.org/
+ *
+ * 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 23, 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 WP512_DIGEST_SIZE 64
+#define WP384_DIGEST_SIZE 48
+#define WP256_DIGEST_SIZE 32
+
+#define WP512_BLOCK_SIZE  64
+#define WP512_LENGTHBYTES 32
+
+#define WHIRLPOOL_ROUNDS 10
+
+struct wp512_ctx {
+	u8  bitLength[WP512_LENGTHBYTES];
+	u8  buffer[WP512_BLOCK_SIZE];
+	int bufferBits;
+	int bufferPos;
+	u64 hash[WP512_DIGEST_SIZE/8];
+};
+
+/*
+ * Though Whirlpool is endianness-neutral, the encryption tables are listed
+ * in BIG-ENDIAN format, which is adopted throughout this implementation
+ * (but little-endian notation would be equally suitable if consistently
+ * employed).
+ */
+
+static const u64 C0[256] = {
+	0x18186018c07830d8ULL, 0x23238c2305af4626ULL, 0xc6c63fc67ef991b8ULL,
+	0xe8e887e8136fcdfbULL, 0x878726874ca113cbULL, 0xb8b8dab8a9626d11ULL,
+	0x0101040108050209ULL, 0x4f4f214f426e9e0dULL, 0x3636d836adee6c9bULL,
+	0xa6a6a2a6590451ffULL, 0xd2d26fd2debdb90cULL, 0xf5f5f3f5fb06f70eULL,
+	0x7979f979ef80f296ULL, 0x6f6fa16f5fcede30ULL, 0x91917e91fcef3f6dULL,
+	0x52525552aa07a4f8ULL, 0x60609d6027fdc047ULL, 0xbcbccabc89766535ULL,
+	0x9b9b569baccd2b37ULL, 0x8e8e028e048c018aULL, 0xa3a3b6a371155bd2ULL,
+	0x0c0c300c603c186cULL, 0x7b7bf17bff8af684ULL, 0x3535d435b5e16a80ULL,
+	0x1d1d741de8693af5ULL, 0xe0e0a7e05347ddb3ULL, 0xd7d77bd7f6acb321ULL,
+	0xc2c22fc25eed999cULL, 0x2e2eb82e6d965c43ULL, 0x4b4b314b627a9629ULL,
+	0xfefedffea321e15dULL, 0x575741578216aed5ULL, 0x15155415a8412abdULL,
+	0x7777c1779fb6eee8ULL, 0x3737dc37a5eb6e92ULL, 0xe5e5b3e57b56d79eULL,
+	0x9f9f469f8cd92313ULL, 0xf0f0e7f0d317fd23ULL, 0x4a4a354a6a7f9420ULL,
+	0xdada4fda9e95a944ULL, 0x58587d58fa25b0a2ULL, 0xc9c903c906ca8fcfULL,
+	0x2929a429558d527cULL, 0x0a0a280a5022145aULL, 0xb1b1feb1e14f7f50ULL,
+	0xa0a0baa0691a5dc9ULL, 0x6b6bb16b7fdad614ULL, 0x85852e855cab17d9ULL,
+	0xbdbdcebd8173673cULL, 0x5d5d695dd234ba8fULL, 0x1010401080502090ULL,
+	0xf4f4f7f4f303f507ULL, 0xcbcb0bcb16c08bddULL, 0x3e3ef83eedc67cd3ULL,
+	0x0505140528110a2dULL, 0x676781671fe6ce78ULL, 0xe4e4b7e47353d597ULL,
+	0x27279c2725bb4e02ULL, 0x4141194132588273ULL, 0x8b8b168b2c9d0ba7ULL,
+	0xa7a7a6a7510153f6ULL, 0x7d7de97dcf94fab2ULL, 0x95956e95dcfb3749ULL,
+	0xd8d847d88e9fad56ULL, 0xfbfbcbfb8b30eb70ULL, 0xeeee9fee2371c1cdULL,
+	0x7c7ced7cc791f8bbULL, 0x6666856617e3cc71ULL, 0xdddd53dda68ea77bULL,
+	0x17175c17b84b2eafULL, 0x4747014702468e45ULL, 0x9e9e429e84dc211aULL,
+	0xcaca0fca1ec589d4ULL, 0x2d2db42d75995a58ULL, 0xbfbfc6bf9179632eULL,
+	0x07071c07381b0e3fULL, 0xadad8ead012347acULL, 0x5a5a755aea2fb4b0ULL,
+	0x838336836cb51befULL, 0x3333cc3385ff66b6ULL, 0x636391633ff2c65cULL,
+	0x02020802100a0412ULL, 0xaaaa92aa39384993ULL, 0x7171d971afa8e2deULL,
+	0xc8c807c80ecf8dc6ULL, 0x19196419c87d32d1ULL, 0x494939497270923bULL,
+	0xd9d943d9869aaf5fULL, 0xf2f2eff2c31df931ULL, 0xe3e3abe34b48dba8ULL,
+	0x5b5b715be22ab6b9ULL, 0x88881a8834920dbcULL, 0x9a9a529aa4c8293eULL,
+	0x262698262dbe4c0bULL, 0x3232c8328dfa64bfULL, 0xb0b0fab0e94a7d59ULL,
+	0xe9e983e91b6acff2ULL, 0x0f0f3c0f78331e77ULL, 0xd5d573d5e6a6b733ULL,
+	0x80803a8074ba1df4ULL, 0xbebec2be997c6127ULL, 0xcdcd13cd26de87ebULL,
+	0x3434d034bde46889ULL, 0x48483d487a759032ULL, 0xffffdbffab24e354ULL,
+	0x7a7af57af78ff48dULL, 0x90907a90f4ea3d64ULL, 0x5f5f615fc23ebe9dULL,
+	0x202080201da0403dULL, 0x6868bd6867d5d00fULL, 0x1a1a681ad07234caULL,
+	0xaeae82ae192c41b7ULL, 0xb4b4eab4c95e757dULL, 0x54544d549a19a8ceULL,
+	0x93937693ece53b7fULL, 0x222288220daa442fULL, 0x64648d6407e9c863ULL,
+	0xf1f1e3f1db12ff2aULL, 0x7373d173bfa2e6ccULL, 0x12124812905a2482ULL,
+	0x40401d403a5d807aULL, 0x0808200840281048ULL, 0xc3c32bc356e89b95ULL,
+	0xecec97ec337bc5dfULL, 0xdbdb4bdb9690ab4dULL, 0xa1a1bea1611f5fc0ULL,
+	0x8d8d0e8d1c830791ULL, 0x3d3df43df5c97ac8ULL, 0x97976697ccf1335bULL,
+	0x0000000000000000ULL, 0xcfcf1bcf36d483f9ULL, 0x2b2bac2b4587566eULL,
+	0x7676c57697b3ece1ULL, 0x8282328264b019e6ULL, 0xd6d67fd6fea9b128ULL,
+	0x1b1b6c1bd87736c3ULL, 0xb5b5eeb5c15b7774ULL, 0xafaf86af112943beULL,
+	0x6a6ab56a77dfd41dULL, 0x50505d50ba0da0eaULL, 0x45450945124c8a57ULL,
+	0xf3f3ebf3cb18fb38ULL, 0x3030c0309df060adULL, 0xefef9bef2b74c3c4ULL,
+	0x3f3ffc3fe5c37edaULL, 0x55554955921caac7ULL, 0xa2a2b2a2791059dbULL,
+	0xeaea8fea0365c9e9ULL, 0x656589650fecca6aULL, 0xbabad2bab9686903ULL,
+	0x2f2fbc2f65935e4aULL, 0xc0c027c04ee79d8eULL, 0xdede5fdebe81a160ULL,
+	0x1c1c701ce06c38fcULL, 0xfdfdd3fdbb2ee746ULL, 0x4d4d294d52649a1fULL,
+	0x92927292e4e03976ULL, 0x7575c9758fbceafaULL, 0x06061806301e0c36ULL,
+	0x8a8a128a249809aeULL, 0xb2b2f2b2f940794bULL, 0xe6e6bfe66359d185ULL,
+	0x0e0e380e70361c7eULL, 0x1f1f7c1ff8633ee7ULL, 0x6262956237f7c455ULL,
+	0xd4d477d4eea3b53aULL, 0xa8a89aa829324d81ULL, 0x96966296c4f43152ULL,
+	0xf9f9c3f99b3aef62ULL, 0xc5c533c566f697a3ULL, 0x2525942535b14a10ULL,
+	0x59597959f220b2abULL, 0x84842a8454ae15d0ULL, 0x7272d572b7a7e4c5ULL,
+	0x3939e439d5dd72ecULL, 0x4c4c2d4c5a619816ULL, 0x5e5e655eca3bbc94ULL,
+	0x7878fd78e785f09fULL, 0x3838e038ddd870e5ULL, 0x8c8c0a8c14860598ULL,
+	0xd1d163d1c6b2bf17ULL, 0xa5a5aea5410b57e4ULL, 0xe2e2afe2434dd9a1ULL,
+	0x616199612ff8c24eULL, 0xb3b3f6b3f1457b42ULL, 0x2121842115a54234ULL,
+	0x9c9c4a9c94d62508ULL, 0x1e1e781ef0663ceeULL, 0x4343114322528661ULL,
+	0xc7c73bc776fc93b1ULL, 0xfcfcd7fcb32be54fULL, 0x0404100420140824ULL,
+	0x51515951b208a2e3ULL, 0x99995e99bcc72f25ULL, 0x6d6da96d4fc4da22ULL,
+	0x0d0d340d68391a65ULL, 0xfafacffa8335e979ULL, 0xdfdf5bdfb684a369ULL,
+	0x7e7ee57ed79bfca9ULL, 0x242490243db44819ULL, 0x3b3bec3bc5d776feULL,
+	0xabab96ab313d4b9aULL, 0xcece1fce3ed181f0ULL, 0x1111441188552299ULL,
+	0x8f8f068f0c890383ULL, 0x4e4e254e4a6b9c04ULL, 0xb7b7e6b7d1517366ULL,
+	0xebeb8beb0b60cbe0ULL, 0x3c3cf03cfdcc78c1ULL, 0x81813e817cbf1ffdULL,
+	0x94946a94d4fe3540ULL, 0xf7f7fbf7eb0cf31cULL, 0xb9b9deb9a1676f18ULL,
+	0x13134c13985f268bULL, 0x2c2cb02c7d9c5851ULL, 0xd3d36bd3d6b8bb05ULL,
+	0xe7e7bbe76b5cd38cULL, 0x6e6ea56e57cbdc39ULL, 0xc4c437c46ef395aaULL,
+	0x03030c03180f061bULL, 0x565645568a13acdcULL, 0x44440d441a49885eULL,
+	0x7f7fe17fdf9efea0ULL, 0xa9a99ea921374f88ULL, 0x2a2aa82a4d825467ULL,
+	0xbbbbd6bbb16d6b0aULL, 0xc1c123c146e29f87ULL, 0x53535153a202a6f1ULL,
+	0xdcdc57dcae8ba572ULL, 0x0b0b2c0b58271653ULL, 0x9d9d4e9d9cd32701ULL,
+	0x6c6cad6c47c1d82bULL, 0x3131c43195f562a4ULL, 0x7474cd7487b9e8f3ULL,
+	0xf6f6fff6e309f115ULL, 0x464605460a438c4cULL, 0xacac8aac092645a5ULL,
+	0x89891e893c970fb5ULL, 0x14145014a04428b4ULL, 0xe1e1a3e15b42dfbaULL,
+	0x16165816b04e2ca6ULL, 0x3a3ae83acdd274f7ULL, 0x6969b9696fd0d206ULL,
+	0x09092409482d1241ULL, 0x7070dd70a7ade0d7ULL, 0xb6b6e2b6d954716fULL,
+	0xd0d067d0ceb7bd1eULL, 0xeded93ed3b7ec7d6ULL, 0xcccc17cc2edb85e2ULL,
+	0x424215422a578468ULL, 0x98985a98b4c22d2cULL, 0xa4a4aaa4490e55edULL,
+	0x2828a0285d885075ULL, 0x5c5c6d5cda31b886ULL, 0xf8f8c7f8933fed6bULL,
+	0x8686228644a411c2ULL,
+};
+
+static const u64 C1[256] = {
+	0xd818186018c07830ULL, 0x2623238c2305af46ULL, 0xb8c6c63fc67ef991ULL,
+	0xfbe8e887e8136fcdULL, 0xcb878726874ca113ULL, 0x11b8b8dab8a9626dULL,
+	0x0901010401080502ULL, 0x0d4f4f214f426e9eULL, 0x9b3636d836adee6cULL,
+	0xffa6a6a2a6590451ULL, 0x0cd2d26fd2debdb9ULL, 0x0ef5f5f3f5fb06f7ULL,
+	0x967979f979ef80f2ULL, 0x306f6fa16f5fcedeULL, 0x6d91917e91fcef3fULL,
+	0xf852525552aa07a4ULL, 0x4760609d6027fdc0ULL, 0x35bcbccabc897665ULL,
+	0x379b9b569baccd2bULL, 0x8a8e8e028e048c01ULL, 0xd2a3a3b6a371155bULL,
+	0x6c0c0c300c603c18ULL, 0x847b7bf17bff8af6ULL, 0x803535d435b5e16aULL,
+	0xf51d1d741de8693aULL, 0xb3e0e0a7e05347ddULL, 0x21d7d77bd7f6acb3ULL,
+	0x9cc2c22fc25eed99ULL, 0x432e2eb82e6d965cULL, 0x294b4b314b627a96ULL,
+	0x5dfefedffea321e1ULL, 0xd5575741578216aeULL, 0xbd15155415a8412aULL,
+	0xe87777c1779fb6eeULL, 0x923737dc37a5eb6eULL, 0x9ee5e5b3e57b56d7ULL,
+	0x139f9f469f8cd923ULL, 0x23f0f0e7f0d317fdULL, 0x204a4a354a6a7f94ULL,
+	0x44dada4fda9e95a9ULL, 0xa258587d58fa25b0ULL, 0xcfc9c903c906ca8fULL,
+	0x7c2929a429558d52ULL, 0x5a0a0a280a502214ULL, 0x50b1b1feb1e14f7fULL,
+	0xc9a0a0baa0691a5dULL, 0x146b6bb16b7fdad6ULL, 0xd985852e855cab17ULL,
+	0x3cbdbdcebd817367ULL, 0x8f5d5d695dd234baULL, 0x9010104010805020ULL,
+	0x07f4f4f7f4f303f5ULL, 0xddcbcb0bcb16c08bULL, 0xd33e3ef83eedc67cULL,
+	0x2d0505140528110aULL, 0x78676781671fe6ceULL, 0x97e4e4b7e47353d5ULL,
+	0x0227279c2725bb4eULL, 0x7341411941325882ULL, 0xa78b8b168b2c9d0bULL,
+	0xf6a7a7a6a7510153ULL, 0xb27d7de97dcf94faULL, 0x4995956e95dcfb37ULL,
+	0x56d8d847d88e9fadULL, 0x70fbfbcbfb8b30ebULL, 0xcdeeee9fee2371c1ULL,
+	0xbb7c7ced7cc791f8ULL, 0x716666856617e3ccULL, 0x7bdddd53dda68ea7ULL,
+	0xaf17175c17b84b2eULL, 0x454747014702468eULL, 0x1a9e9e429e84dc21ULL,
+	0xd4caca0fca1ec589ULL, 0x582d2db42d75995aULL, 0x2ebfbfc6bf917963ULL,
+	0x3f07071c07381b0eULL, 0xacadad8ead012347ULL, 0xb05a5a755aea2fb4ULL,
+	0xef838336836cb51bULL, 0xb63333cc3385ff66ULL, 0x5c636391633ff2c6ULL,
+	0x1202020802100a04ULL, 0x93aaaa92aa393849ULL, 0xde7171d971afa8e2ULL,
+	0xc6c8c807c80ecf8dULL, 0xd119196419c87d32ULL, 0x3b49493949727092ULL,
+	0x5fd9d943d9869aafULL, 0x31f2f2eff2c31df9ULL, 0xa8e3e3abe34b48dbULL,
+	0xb95b5b715be22ab6ULL, 0xbc88881a8834920dULL, 0x3e9a9a529aa4c829ULL,
+	0x0b262698262dbe4cULL, 0xbf3232c8328dfa64ULL, 0x59b0b0fab0e94a7dULL,
+	0xf2e9e983e91b6acfULL, 0x770f0f3c0f78331eULL, 0x33d5d573d5e6a6b7ULL,
+	0xf480803a8074ba1dULL, 0x27bebec2be997c61ULL, 0xebcdcd13cd26de87ULL,
+	0x893434d034bde468ULL, 0x3248483d487a7590ULL, 0x54ffffdbffab24e3ULL,
+	0x8d7a7af57af78ff4ULL, 0x6490907a90f4ea3dULL, 0x9d5f5f615fc23ebeULL,
+	0x3d202080201da040ULL, 0x0f6868bd6867d5d0ULL, 0xca1a1a681ad07234ULL,
+	0xb7aeae82ae192c41ULL, 0x7db4b4eab4c95e75ULL, 0xce54544d549a19a8ULL,
+	0x7f93937693ece53bULL, 0x2f222288220daa44ULL, 0x6364648d6407e9c8ULL,
+	0x2af1f1e3f1db12ffULL, 0xcc7373d173bfa2e6ULL, 0x8212124812905a24ULL,
+	0x7a40401d403a5d80ULL, 0x4808082008402810ULL, 0x95c3c32bc356e89bULL,
+	0xdfecec97ec337bc5ULL, 0x4ddbdb4bdb9690abULL, 0xc0a1a1bea1611f5fULL,
+	0x918d8d0e8d1c8307ULL, 0xc83d3df43df5c97aULL, 0x5b97976697ccf133ULL,
+	0x0000000000000000ULL, 0xf9cfcf1bcf36d483ULL, 0x6e2b2bac2b458756ULL,
+	0xe17676c57697b3ecULL, 0xe68282328264b019ULL, 0x28d6d67fd6fea9b1ULL,
+	0xc31b1b6c1bd87736ULL, 0x74b5b5eeb5c15b77ULL, 0xbeafaf86af112943ULL,
+	0x1d6a6ab56a77dfd4ULL, 0xea50505d50ba0da0ULL, 0x5745450945124c8aULL,
+	0x38f3f3ebf3cb18fbULL, 0xad3030c0309df060ULL, 0xc4efef9bef2b74c3ULL,
+	0xda3f3ffc3fe5c37eULL, 0xc755554955921caaULL, 0xdba2a2b2a2791059ULL,
+	0xe9eaea8fea0365c9ULL, 0x6a656589650feccaULL, 0x03babad2bab96869ULL,
+	0x4a2f2fbc2f65935eULL, 0x8ec0c027c04ee79dULL, 0x60dede5fdebe81a1ULL,
+	0xfc1c1c701ce06c38ULL, 0x46fdfdd3fdbb2ee7ULL, 0x1f4d4d294d52649aULL,
+	0x7692927292e4e039ULL, 0xfa7575c9758fbceaULL, 0x3606061806301e0cULL,
+	0xae8a8a128a249809ULL, 0x4bb2b2f2b2f94079ULL, 0x85e6e6bfe66359d1ULL,
+	0x7e0e0e380e70361cULL, 0xe71f1f7c1ff8633eULL, 0x556262956237f7c4ULL,
+	0x3ad4d477d4eea3b5ULL, 0x81a8a89aa829324dULL, 0x5296966296c4f431ULL,
+	0x62f9f9c3f99b3aefULL, 0xa3c5c533c566f697ULL, 0x102525942535b14aULL,
+	0xab59597959f220b2ULL, 0xd084842a8454ae15ULL, 0xc57272d572b7a7e4ULL,
+	0xec3939e439d5dd72ULL, 0x164c4c2d4c5a6198ULL, 0x945e5e655eca3bbcULL,
+	0x9f7878fd78e785f0ULL, 0xe53838e038ddd870ULL, 0x988c8c0a8c148605ULL,
+	0x17d1d163d1c6b2bfULL, 0xe4a5a5aea5410b57ULL, 0xa1e2e2afe2434dd9ULL,
+	0x4e616199612ff8c2ULL, 0x42b3b3f6b3f1457bULL, 0x342121842115a542ULL,
+	0x089c9c4a9c94d625ULL, 0xee1e1e781ef0663cULL, 0x6143431143225286ULL,
+	0xb1c7c73bc776fc93ULL, 0x4ffcfcd7fcb32be5ULL, 0x2404041004201408ULL,
+	0xe351515951b208a2ULL, 0x2599995e99bcc72fULL, 0x226d6da96d4fc4daULL,
+	0x650d0d340d68391aULL, 0x79fafacffa8335e9ULL, 0x69dfdf5bdfb684a3ULL,
+	0xa97e7ee57ed79bfcULL, 0x19242490243db448ULL, 0xfe3b3bec3bc5d776ULL,
+	0x9aabab96ab313d4bULL, 0xf0cece1fce3ed181ULL, 0x9911114411885522ULL,
+	0x838f8f068f0c8903ULL, 0x044e4e254e4a6b9cULL, 0x66b7b7e6b7d15173ULL,
+	0xe0ebeb8beb0b60cbULL, 0xc13c3cf03cfdcc78ULL, 0xfd81813e817cbf1fULL,
+	0x4094946a94d4fe35ULL, 0x1cf7f7fbf7eb0cf3ULL, 0x18b9b9deb9a1676fULL,
+	0x8b13134c13985f26ULL, 0x512c2cb02c7d9c58ULL, 0x05d3d36bd3d6b8bbULL,
+	0x8ce7e7bbe76b5cd3ULL, 0x396e6ea56e57cbdcULL, 0xaac4c437c46ef395ULL,
+	0x1b03030c03180f06ULL, 0xdc565645568a13acULL, 0x5e44440d441a4988ULL,
+	0xa07f7fe17fdf9efeULL, 0x88a9a99ea921374fULL, 0x672a2aa82a4d8254ULL,
+	0x0abbbbd6bbb16d6bULL, 0x87c1c123c146e29fULL, 0xf153535153a202a6ULL,
+	0x72dcdc57dcae8ba5ULL, 0x530b0b2c0b582716ULL, 0x019d9d4e9d9cd327ULL,
+	0x2b6c6cad6c47c1d8ULL, 0xa43131c43195f562ULL, 0xf37474cd7487b9e8ULL,
+	0x15f6f6fff6e309f1ULL, 0x4c464605460a438cULL, 0xa5acac8aac092645ULL,
+	0xb589891e893c970fULL, 0xb414145014a04428ULL, 0xbae1e1a3e15b42dfULL,
+	0xa616165816b04e2cULL, 0xf73a3ae83acdd274ULL, 0x066969b9696fd0d2ULL,
+	0x4109092409482d12ULL, 0xd77070dd70a7ade0ULL, 0x6fb6b6e2b6d95471ULL,
+	0x1ed0d067d0ceb7bdULL, 0xd6eded93ed3b7ec7ULL, 0xe2cccc17cc2edb85ULL,
+	0x68424215422a5784ULL, 0x2c98985a98b4c22dULL, 0xeda4a4aaa4490e55ULL,
+	0x752828a0285d8850ULL, 0x865c5c6d5cda31b8ULL, 0x6bf8f8c7f8933fedULL,
+	0xc28686228644a411ULL,
+};
+
+static const u64 C2[256] = {
+	0x30d818186018c078ULL, 0x462623238c2305afULL, 0x91b8c6c63fc67ef9ULL,
+	0xcdfbe8e887e8136fULL, 0x13cb878726874ca1ULL, 0x6d11b8b8dab8a962ULL,
+	0x0209010104010805ULL, 0x9e0d4f4f214f426eULL, 0x6c9b3636d836adeeULL,
+	0x51ffa6a6a2a65904ULL, 0xb90cd2d26fd2debdULL, 0xf70ef5f5f3f5fb06ULL,
+	0xf2967979f979ef80ULL, 0xde306f6fa16f5fceULL, 0x3f6d91917e91fcefULL,
+	0xa4f852525552aa07ULL, 0xc04760609d6027fdULL, 0x6535bcbccabc8976ULL,
+	0x2b379b9b569baccdULL, 0x018a8e8e028e048cULL, 0x5bd2a3a3b6a37115ULL,
+	0x186c0c0c300c603cULL, 0xf6847b7bf17bff8aULL, 0x6a803535d435b5e1ULL,
+	0x3af51d1d741de869ULL, 0xddb3e0e0a7e05347ULL, 0xb321d7d77bd7f6acULL,
+	0x999cc2c22fc25eedULL, 0x5c432e2eb82e6d96ULL, 0x96294b4b314b627aULL,
+	0xe15dfefedffea321ULL, 0xaed5575741578216ULL, 0x2abd15155415a841ULL,
+	0xeee87777c1779fb6ULL, 0x6e923737dc37a5ebULL, 0xd79ee5e5b3e57b56ULL,
+	0x23139f9f469f8cd9ULL, 0xfd23f0f0e7f0d317ULL, 0x94204a4a354a6a7fULL,
+	0xa944dada4fda9e95ULL, 0xb0a258587d58fa25ULL, 0x8fcfc9c903c906caULL,
+	0x527c2929a429558dULL, 0x145a0a0a280a5022ULL, 0x7f50b1b1feb1e14fULL,
+	0x5dc9a0a0baa0691aULL, 0xd6146b6bb16b7fdaULL, 0x17d985852e855cabULL,
+	0x673cbdbdcebd8173ULL, 0xba8f5d5d695dd234ULL, 0x2090101040108050ULL,
+	0xf507f4f4f7f4f303ULL, 0x8bddcbcb0bcb16c0ULL, 0x7cd33e3ef83eedc6ULL,
+	0x0a2d050514052811ULL, 0xce78676781671fe6ULL, 0xd597e4e4b7e47353ULL,
+	0x4e0227279c2725bbULL, 0x8273414119413258ULL, 0x0ba78b8b168b2c9dULL,
+	0x53f6a7a7a6a75101ULL, 0xfab27d7de97dcf94ULL, 0x374995956e95dcfbULL,
+	0xad56d8d847d88e9fULL, 0xeb70fbfbcbfb8b30ULL, 0xc1cdeeee9fee2371ULL,
+	0xf8bb7c7ced7cc791ULL, 0xcc716666856617e3ULL, 0xa77bdddd53dda68eULL,
+	0x2eaf17175c17b84bULL, 0x8e45474701470246ULL, 0x211a9e9e429e84dcULL,
+	0x89d4caca0fca1ec5ULL, 0x5a582d2db42d7599ULL, 0x632ebfbfc6bf9179ULL,
+	0x0e3f07071c07381bULL, 0x47acadad8ead0123ULL, 0xb4b05a5a755aea2fULL,
+	0x1bef838336836cb5ULL, 0x66b63333cc3385ffULL, 0xc65c636391633ff2ULL,
+	0x041202020802100aULL, 0x4993aaaa92aa3938ULL, 0xe2de7171d971afa8ULL,
+	0x8dc6c8c807c80ecfULL, 0x32d119196419c87dULL, 0x923b494939497270ULL,
+	0xaf5fd9d943d9869aULL, 0xf931f2f2eff2c31dULL, 0xdba8e3e3abe34b48ULL,
+	0xb6b95b5b715be22aULL, 0x0dbc88881a883492ULL, 0x293e9a9a529aa4c8ULL,
+	0x4c0b262698262dbeULL, 0x64bf3232c8328dfaULL, 0x7d59b0b0fab0e94aULL,
+	0xcff2e9e983e91b6aULL, 0x1e770f0f3c0f7833ULL, 0xb733d5d573d5e6a6ULL,
+	0x1df480803a8074baULL, 0x6127bebec2be997cULL, 0x87ebcdcd13cd26deULL,
+	0x68893434d034bde4ULL, 0x903248483d487a75ULL, 0xe354ffffdbffab24ULL,
+	0xf48d7a7af57af78fULL, 0x3d6490907a90f4eaULL, 0xbe9d5f5f615fc23eULL,
+	0x403d202080201da0ULL, 0xd00f6868bd6867d5ULL, 0x34ca1a1a681ad072ULL,
+	0x41b7aeae82ae192cULL, 0x757db4b4eab4c95eULL, 0xa8ce54544d549a19ULL,
+	0x3b7f93937693ece5ULL, 0x442f222288220daaULL, 0xc86364648d6407e9ULL,
+	0xff2af1f1e3f1db12ULL, 0xe6cc7373d173bfa2ULL, 0x248212124812905aULL,
+	0x807a40401d403a5dULL, 0x1048080820084028ULL, 0x9b95c3c32bc356e8ULL,
+	0xc5dfecec97ec337bULL, 0xab4ddbdb4bdb9690ULL, 0x5fc0a1a1bea1611fULL,
+	0x07918d8d0e8d1c83ULL, 0x7ac83d3df43df5c9ULL, 0x335b97976697ccf1ULL,
+	0x0000000000000000ULL, 0x83f9cfcf1bcf36d4ULL, 0x566e2b2bac2b4587ULL,
+	0xece17676c57697b3ULL, 0x19e68282328264b0ULL, 0xb128d6d67fd6fea9ULL,
+	0x36c31b1b6c1bd877ULL, 0x7774b5b5eeb5c15bULL, 0x43beafaf86af1129ULL,
+	0xd41d6a6ab56a77dfULL, 0xa0ea50505d50ba0dULL, 0x8a5745450945124cULL,
+	0xfb38f3f3ebf3cb18ULL, 0x60ad3030c0309df0ULL, 0xc3c4efef9bef2b74ULL,
+	0x7eda3f3ffc3fe5c3ULL, 0xaac755554955921cULL, 0x59dba2a2b2a27910ULL,
+	0xc9e9eaea8fea0365ULL, 0xca6a656589650fecULL, 0x6903babad2bab968ULL,
+	0x5e4a2f2fbc2f6593ULL, 0x9d8ec0c027c04ee7ULL, 0xa160dede5fdebe81ULL,
+	0x38fc1c1c701ce06cULL, 0xe746fdfdd3fdbb2eULL, 0x9a1f4d4d294d5264ULL,
+	0x397692927292e4e0ULL, 0xeafa7575c9758fbcULL, 0x0c3606061806301eULL,
+	0x09ae8a8a128a2498ULL, 0x794bb2b2f2b2f940ULL, 0xd185e6e6bfe66359ULL,
+	0x1c7e0e0e380e7036ULL, 0x3ee71f1f7c1ff863ULL, 0xc4556262956237f7ULL,
+	0xb53ad4d477d4eea3ULL, 0x4d81a8a89aa82932ULL, 0x315296966296c4f4ULL,
+	0xef62f9f9c3f99b3aULL, 0x97a3c5c533c566f6ULL, 0x4a102525942535b1ULL,
+	0xb2ab59597959f220ULL, 0x15d084842a8454aeULL, 0xe4c57272d572b7a7ULL,
+	0x72ec3939e439d5ddULL, 0x98164c4c2d4c5a61ULL, 0xbc945e5e655eca3bULL,
+	0xf09f7878fd78e785ULL, 0x70e53838e038ddd8ULL, 0x05988c8c0a8c1486ULL,
+	0xbf17d1d163d1c6b2ULL, 0x57e4a5a5aea5410bULL, 0xd9a1e2e2afe2434dULL,
+	0xc24e616199612ff8ULL, 0x7b42b3b3f6b3f145ULL, 0x42342121842115a5ULL,
+	0x25089c9c4a9c94d6ULL, 0x3cee1e1e781ef066ULL, 0x8661434311432252ULL,
+	0x93b1c7c73bc776fcULL, 0xe54ffcfcd7fcb32bULL, 0x0824040410042014ULL,
+	0xa2e351515951b208ULL, 0x2f2599995e99bcc7ULL, 0xda226d6da96d4fc4ULL,
+	0x1a650d0d340d6839ULL, 0xe979fafacffa8335ULL, 0xa369dfdf5bdfb684ULL,
+	0xfca97e7ee57ed79bULL, 0x4819242490243db4ULL, 0x76fe3b3bec3bc5d7ULL,
+	0x4b9aabab96ab313dULL, 0x81f0cece1fce3ed1ULL, 0x2299111144118855ULL,
+	0x03838f8f068f0c89ULL, 0x9c044e4e254e4a6bULL, 0x7366b7b7e6b7d151ULL,
+	0xcbe0ebeb8beb0b60ULL, 0x78c13c3cf03cfdccULL, 0x1ffd81813e817cbfULL,
+	0x354094946a94d4feULL, 0xf31cf7f7fbf7eb0cULL, 0x6f18b9b9deb9a167ULL,
+	0x268b13134c13985fULL, 0x58512c2cb02c7d9cULL, 0xbb05d3d36bd3d6b8ULL,
+	0xd38ce7e7bbe76b5cULL, 0xdc396e6ea56e57cbULL, 0x95aac4c437c46ef3ULL,
+	0x061b03030c03180fULL, 0xacdc565645568a13ULL, 0x885e44440d441a49ULL,
+	0xfea07f7fe17fdf9eULL, 0x4f88a9a99ea92137ULL, 0x54672a2aa82a4d82ULL,
+	0x6b0abbbbd6bbb16dULL, 0x9f87c1c123c146e2ULL, 0xa6f153535153a202ULL,
+	0xa572dcdc57dcae8bULL, 0x16530b0b2c0b5827ULL, 0x27019d9d4e9d9cd3ULL,
+	0xd82b6c6cad6c47c1ULL, 0x62a43131c43195f5ULL, 0xe8f37474cd7487b9ULL,
+	0xf115f6f6fff6e309ULL, 0x8c4c464605460a43ULL, 0x45a5acac8aac0926ULL,
+	0x0fb589891e893c97ULL, 0x28b414145014a044ULL, 0xdfbae1e1a3e15b42ULL,
+	0x2ca616165816b04eULL, 0x74f73a3ae83acdd2ULL, 0xd2066969b9696fd0ULL,
+	0x124109092409482dULL, 0xe0d77070dd70a7adULL, 0x716fb6b6e2b6d954ULL,
+	0xbd1ed0d067d0ceb7ULL, 0xc7d6eded93ed3b7eULL, 0x85e2cccc17cc2edbULL,
+	0x8468424215422a57ULL, 0x2d2c98985a98b4c2ULL, 0x55eda4a4aaa4490eULL,
+	0x50752828a0285d88ULL, 0xb8865c5c6d5cda31ULL, 0xed6bf8f8c7f8933fULL,
+	0x11c28686228644a4ULL,
+};
+
+static const u64 C3[256] = {
+	0x7830d818186018c0ULL, 0xaf462623238c2305ULL, 0xf991b8c6c63fc67eULL,
+	0x6fcdfbe8e887e813ULL, 0xa113cb878726874cULL, 0x626d11b8b8dab8a9ULL,
+	0x0502090101040108ULL, 0x6e9e0d4f4f214f42ULL, 0xee6c9b3636d836adULL,
+	0x0451ffa6a6a2a659ULL, 0xbdb90cd2d26fd2deULL, 0x06f70ef5f5f3f5fbULL,
+	0x80f2967979f979efULL, 0xcede306f6fa16f5fULL, 0xef3f6d91917e91fcULL,
+	0x07a4f852525552aaULL, 0xfdc04760609d6027ULL, 0x766535bcbccabc89ULL,
+	0xcd2b379b9b569bacULL, 0x8c018a8e8e028e04ULL, 0x155bd2a3a3b6a371ULL,
+	0x3c186c0c0c300c60ULL, 0x8af6847b7bf17bffULL, 0xe16a803535d435b5ULL,
+	0x693af51d1d741de8ULL, 0x47ddb3e0e0a7e053ULL, 0xacb321d7d77bd7f6ULL,
+	0xed999cc2c22fc25eULL, 0x965c432e2eb82e6dULL, 0x7a96294b4b314b62ULL,
+	0x21e15dfefedffea3ULL, 0x16aed55757415782ULL, 0x412abd15155415a8ULL,
+	0xb6eee87777c1779fULL, 0xeb6e923737dc37a5ULL, 0x56d79ee5e5b3e57bULL,
+	0xd923139f9f469f8cULL, 0x17fd23f0f0e7f0d3ULL, 0x7f94204a4a354a6aULL,
+	0x95a944dada4fda9eULL, 0x25b0a258587d58faULL, 0xca8fcfc9c903c906ULL,
+	0x8d527c2929a42955ULL, 0x22145a0a0a280a50ULL, 0x4f7f50b1b1feb1e1ULL,
+	0x1a5dc9a0a0baa069ULL, 0xdad6146b6bb16b7fULL, 0xab17d985852e855cULL,
+	0x73673cbdbdcebd81ULL, 0x34ba8f5d5d695dd2ULL, 0x5020901010401080ULL,
+	0x03f507f4f4f7f4f3ULL, 0xc08bddcbcb0bcb16ULL, 0xc67cd33e3ef83eedULL,
+	0x110a2d0505140528ULL, 0xe6ce78676781671fULL, 0x53d597e4e4b7e473ULL,
+	0xbb4e0227279c2725ULL, 0x5882734141194132ULL, 0x9d0ba78b8b168b2cULL,
+	0x0153f6a7a7a6a751ULL, 0x94fab27d7de97dcfULL, 0xfb374995956e95dcULL,
+	0x9fad56d8d847d88eULL, 0x30eb70fbfbcbfb8bULL, 0x71c1cdeeee9fee23ULL,
+	0x91f8bb7c7ced7cc7ULL, 0xe3cc716666856617ULL, 0x8ea77bdddd53dda6ULL,
+	0x4b2eaf17175c17b8ULL, 0x468e454747014702ULL, 0xdc211a9e9e429e84ULL,
+	0xc589d4caca0fca1eULL, 0x995a582d2db42d75ULL, 0x79632ebfbfc6bf91ULL,
+	0x1b0e3f07071c0738ULL, 0x2347acadad8ead01ULL, 0x2fb4b05a5a755aeaULL,
+	0xb51bef838336836cULL, 0xff66b63333cc3385ULL, 0xf2c65c636391633fULL,
+	0x0a04120202080210ULL, 0x384993aaaa92aa39ULL, 0xa8e2de7171d971afULL,
+	0xcf8dc6c8c807c80eULL, 0x7d32d119196419c8ULL, 0x70923b4949394972ULL,
+	0x9aaf5fd9d943d986ULL, 0x1df931f2f2eff2c3ULL, 0x48dba8e3e3abe34bULL,
+	0x2ab6b95b5b715be2ULL, 0x920dbc88881a8834ULL, 0xc8293e9a9a529aa4ULL,
+	0xbe4c0b262698262dULL, 0xfa64bf3232c8328dULL, 0x4a7d59b0b0fab0e9ULL,
+	0x6acff2e9e983e91bULL, 0x331e770f0f3c0f78ULL, 0xa6b733d5d573d5e6ULL,
+	0xba1df480803a8074ULL, 0x7c6127bebec2be99ULL, 0xde87ebcdcd13cd26ULL,
+	0xe468893434d034bdULL, 0x75903248483d487aULL, 0x24e354ffffdbffabULL,
+	0x8ff48d7a7af57af7ULL, 0xea3d6490907a90f4ULL, 0x3ebe9d5f5f615fc2ULL,
+	0xa0403d202080201dULL, 0xd5d00f6868bd6867ULL, 0x7234ca1a1a681ad0ULL,
+	0x2c41b7aeae82ae19ULL, 0x5e757db4b4eab4c9ULL, 0x19a8ce54544d549aULL,
+	0xe53b7f93937693ecULL, 0xaa442f222288220dULL, 0xe9c86364648d6407ULL,
+	0x12ff2af1f1e3f1dbULL, 0xa2e6cc7373d173bfULL, 0x5a24821212481290ULL,
+	0x5d807a40401d403aULL, 0x2810480808200840ULL, 0xe89b95c3c32bc356ULL,
+	0x7bc5dfecec97ec33ULL, 0x90ab4ddbdb4bdb96ULL, 0x1f5fc0a1a1bea161ULL,
+	0x8307918d8d0e8d1cULL, 0xc97ac83d3df43df5ULL, 0xf1335b97976697ccULL,
+	0x0000000000000000ULL, 0xd483f9cfcf1bcf36ULL, 0x87566e2b2bac2b45ULL,
+	0xb3ece17676c57697ULL, 0xb019e68282328264ULL, 0xa9b128d6d67fd6feULL,
+	0x7736c31b1b6c1bd8ULL, 0x5b7774b5b5eeb5c1ULL, 0x2943beafaf86af11ULL,
+	0xdfd41d6a6ab56a77ULL, 0x0da0ea50505d50baULL, 0x4c8a574545094512ULL,
+	0x18fb38f3f3ebf3cbULL, 0xf060ad3030c0309dULL, 0x74c3c4efef9bef2bULL,
+	0xc37eda3f3ffc3fe5ULL, 0x1caac75555495592ULL, 0x1059dba2a2b2a279ULL,
+	0x65c9e9eaea8fea03ULL, 0xecca6a656589650fULL, 0x686903babad2bab9ULL,
+	0x935e4a2f2fbc2f65ULL, 0xe79d8ec0c027c04eULL, 0x81a160dede5fdebeULL,
+	0x6c38fc1c1c701ce0ULL, 0x2ee746fdfdd3fdbbULL, 0x649a1f4d4d294d52ULL,
+	0xe0397692927292e4ULL, 0xbceafa7575c9758fULL, 0x1e0c360606180630ULL,
+	0x9809ae8a8a128a24ULL, 0x40794bb2b2f2b2f9ULL, 0x59d185e6e6bfe663ULL,
+	0x361c7e0e0e380e70ULL, 0x633ee71f1f7c1ff8ULL, 0xf7c4556262956237ULL,
+	0xa3b53ad4d477d4eeULL, 0x324d81a8a89aa829ULL, 0xf4315296966296c4ULL,
+	0x3aef62f9f9c3f99bULL, 0xf697a3c5c533c566ULL, 0xb14a102525942535ULL,
+	0x20b2ab59597959f2ULL, 0xae15d084842a8454ULL, 0xa7e4c57272d572b7ULL,
+	0xdd72ec3939e439d5ULL, 0x6198164c4c2d4c5aULL, 0x3bbc945e5e655ecaULL,
+	0x85f09f7878fd78e7ULL, 0xd870e53838e038ddULL, 0x8605988c8c0a8c14ULL,
+	0xb2bf17d1d163d1c6ULL, 0x0b57e4a5a5aea541ULL, 0x4dd9a1e2e2afe243ULL,
+	0xf8c24e616199612fULL, 0x457b42b3b3f6b3f1ULL, 0xa542342121842115ULL,
+	0xd625089c9c4a9c94ULL, 0x663cee1e1e781ef0ULL, 0x5286614343114322ULL,
+	0xfc93b1c7c73bc776ULL, 0x2be54ffcfcd7fcb3ULL, 0x1408240404100420ULL,
+	0x08a2e351515951b2ULL, 0xc72f2599995e99bcULL, 0xc4da226d6da96d4fULL,
+	0x391a650d0d340d68ULL, 0x35e979fafacffa83ULL, 0x84a369dfdf5bdfb6ULL,
+	0x9bfca97e7ee57ed7ULL, 0xb44819242490243dULL, 0xd776fe3b3bec3bc5ULL,
+	0x3d4b9aabab96ab31ULL, 0xd181f0cece1fce3eULL, 0x5522991111441188ULL,
+	0x8903838f8f068f0cULL, 0x6b9c044e4e254e4aULL, 0x517366b7b7e6b7d1ULL,
+	0x60cbe0ebeb8beb0bULL, 0xcc78c13c3cf03cfdULL, 0xbf1ffd81813e817cULL,
+	0xfe354094946a94d4ULL, 0x0cf31cf7f7fbf7ebULL, 0x676f18b9b9deb9a1ULL,
+	0x5f268b13134c1398ULL, 0x9c58512c2cb02c7dULL, 0xb8bb05d3d36bd3d6ULL,
+	0x5cd38ce7e7bbe76bULL, 0xcbdc396e6ea56e57ULL, 0xf395aac4c437c46eULL,
+	0x0f061b03030c0318ULL, 0x13acdc565645568aULL, 0x49885e44440d441aULL,
+	0x9efea07f7fe17fdfULL, 0x374f88a9a99ea921ULL, 0x8254672a2aa82a4dULL,
+	0x6d6b0abbbbd6bbb1ULL, 0xe29f87c1c123c146ULL, 0x02a6f153535153a2ULL,
+	0x8ba572dcdc57dcaeULL, 0x2716530b0b2c0b58ULL, 0xd327019d9d4e9d9cULL,
+	0xc1d82b6c6cad6c47ULL, 0xf562a43131c43195ULL, 0xb9e8f37474cd7487ULL,
+	0x09f115f6f6fff6e3ULL, 0x438c4c464605460aULL, 0x2645a5acac8aac09ULL,
+	0x970fb589891e893cULL, 0x4428b414145014a0ULL, 0x42dfbae1e1a3e15bULL,
+	0x4e2ca616165816b0ULL, 0xd274f73a3ae83acdULL, 0xd0d2066969b9696fULL,
+	0x2d12410909240948ULL, 0xade0d77070dd70a7ULL, 0x54716fb6b6e2b6d9ULL,
+	0xb7bd1ed0d067d0ceULL, 0x7ec7d6eded93ed3bULL, 0xdb85e2cccc17cc2eULL,
+	0x578468424215422aULL, 0xc22d2c98985a98b4ULL, 0x0e55eda4a4aaa449ULL,
+	0x8850752828a0285dULL, 0x31b8865c5c6d5cdaULL, 0x3fed6bf8f8c7f893ULL,
+	0xa411c28686228644ULL,
+};
+
+static const u64 C4[256] = {
+	0xc07830d818186018ULL, 0x05af462623238c23ULL, 0x7ef991b8c6c63fc6ULL,
+	0x136fcdfbe8e887e8ULL, 0x4ca113cb87872687ULL, 0xa9626d11b8b8dab8ULL,
+	0x0805020901010401ULL, 0x426e9e0d4f4f214fULL, 0xadee6c9b3636d836ULL,
+	0x590451ffa6a6a2a6ULL, 0xdebdb90cd2d26fd2ULL, 0xfb06f70ef5f5f3f5ULL,
+	0xef80f2967979f979ULL, 0x5fcede306f6fa16fULL, 0xfcef3f6d91917e91ULL,
+	0xaa07a4f852525552ULL, 0x27fdc04760609d60ULL, 0x89766535bcbccabcULL,
+	0xaccd2b379b9b569bULL, 0x048c018a8e8e028eULL, 0x71155bd2a3a3b6a3ULL,
+	0x603c186c0c0c300cULL, 0xff8af6847b7bf17bULL, 0xb5e16a803535d435ULL,
+	0xe8693af51d1d741dULL, 0x5347ddb3e0e0a7e0ULL, 0xf6acb321d7d77bd7ULL,
+	0x5eed999cc2c22fc2ULL, 0x6d965c432e2eb82eULL, 0x627a96294b4b314bULL,
+	0xa321e15dfefedffeULL, 0x8216aed557574157ULL, 0xa8412abd15155415ULL,
+	0x9fb6eee87777c177ULL, 0xa5eb6e923737dc37ULL, 0x7b56d79ee5e5b3e5ULL,
+	0x8cd923139f9f469fULL, 0xd317fd23f0f0e7f0ULL, 0x6a7f94204a4a354aULL,
+	0x9e95a944dada4fdaULL, 0xfa25b0a258587d58ULL, 0x06ca8fcfc9c903c9ULL,
+	0x558d527c2929a429ULL, 0x5022145a0a0a280aULL, 0xe14f7f50b1b1feb1ULL,
+	0x691a5dc9a0a0baa0ULL, 0x7fdad6146b6bb16bULL, 0x5cab17d985852e85ULL,
+	0x8173673cbdbdcebdULL, 0xd234ba8f5d5d695dULL, 0x8050209010104010ULL,
+	0xf303f507f4f4f7f4ULL, 0x16c08bddcbcb0bcbULL, 0xedc67cd33e3ef83eULL,
+	0x28110a2d05051405ULL, 0x1fe6ce7867678167ULL, 0x7353d597e4e4b7e4ULL,
+	0x25bb4e0227279c27ULL, 0x3258827341411941ULL, 0x2c9d0ba78b8b168bULL,
+	0x510153f6a7a7a6a7ULL, 0xcf94fab27d7de97dULL, 0xdcfb374995956e95ULL,
+	0x8e9fad56d8d847d8ULL, 0x8b30eb70fbfbcbfbULL, 0x2371c1cdeeee9feeULL,
+	0xc791f8bb7c7ced7cULL, 0x17e3cc7166668566ULL, 0xa68ea77bdddd53ddULL,
+	0xb84b2eaf17175c17ULL, 0x02468e4547470147ULL, 0x84dc211a9e9e429eULL,
+	0x1ec589d4caca0fcaULL, 0x75995a582d2db42dULL, 0x9179632ebfbfc6bfULL,
+	0x381b0e3f07071c07ULL, 0x012347acadad8eadULL, 0xea2fb4b05a5a755aULL,
+	0x6cb51bef83833683ULL, 0x85ff66b63333cc33ULL, 0x3ff2c65c63639163ULL,
+	0x100a041202020802ULL, 0x39384993aaaa92aaULL, 0xafa8e2de7171d971ULL,
+	0x0ecf8dc6c8c807c8ULL, 0xc87d32d119196419ULL, 0x7270923b49493949ULL,
+	0x869aaf5fd9d943d9ULL, 0xc31df931f2f2eff2ULL, 0x4b48dba8e3e3abe3ULL,
+	0xe22ab6b95b5b715bULL, 0x34920dbc88881a88ULL, 0xa4c8293e9a9a529aULL,
+	0x2dbe4c0b26269826ULL, 0x8dfa64bf3232c832ULL, 0xe94a7d59b0b0fab0ULL,
+	0x1b6acff2e9e983e9ULL, 0x78331e770f0f3c0fULL, 0xe6a6b733d5d573d5ULL,
+	0x74ba1df480803a80ULL, 0x997c6127bebec2beULL, 0x26de87ebcdcd13cdULL,
+	0xbde468893434d034ULL, 0x7a75903248483d48ULL, 0xab24e354ffffdbffULL,
+	0xf78ff48d7a7af57aULL, 0xf4ea3d6490907a90ULL, 0xc23ebe9d5f5f615fULL,
+	0x1da0403d20208020ULL, 0x67d5d00f6868bd68ULL, 0xd07234ca1a1a681aULL,
+	0x192c41b7aeae82aeULL, 0xc95e757db4b4eab4ULL, 0x9a19a8ce54544d54ULL,
+	0xece53b7f93937693ULL, 0x0daa442f22228822ULL, 0x07e9c86364648d64ULL,
+	0xdb12ff2af1f1e3f1ULL, 0xbfa2e6cc7373d173ULL, 0x905a248212124812ULL,
+	0x3a5d807a40401d40ULL, 0x4028104808082008ULL, 0x56e89b95c3c32bc3ULL,
+	0x337bc5dfecec97ecULL, 0x9690ab4ddbdb4bdbULL, 0x611f5fc0a1a1bea1ULL,
+	0x1c8307918d8d0e8dULL, 0xf5c97ac83d3df43dULL, 0xccf1335b97976697ULL,
+	0x0000000000000000ULL, 0x36d483f9cfcf1bcfULL, 0x4587566e2b2bac2bULL,
+	0x97b3ece17676c576ULL, 0x64b019e682823282ULL, 0xfea9b128d6d67fd6ULL,
+	0xd87736c31b1b6c1bULL, 0xc15b7774b5b5eeb5ULL, 0x112943beafaf86afULL,
+	0x77dfd41d6a6ab56aULL, 0xba0da0ea50505d50ULL, 0x124c8a5745450945ULL,
+	0xcb18fb38f3f3ebf3ULL, 0x9df060ad3030c030ULL, 0x2b74c3c4efef9befULL,
+	0xe5c37eda3f3ffc3fULL, 0x921caac755554955ULL, 0x791059dba2a2b2a2ULL,
+	0x0365c9e9eaea8feaULL, 0x0fecca6a65658965ULL, 0xb9686903babad2baULL,
+	0x65935e4a2f2fbc2fULL, 0x4ee79d8ec0c027c0ULL, 0xbe81a160dede5fdeULL,
+	0xe06c38fc1c1c701cULL, 0xbb2ee746fdfdd3fdULL, 0x52649a1f4d4d294dULL,
+	0xe4e0397692927292ULL, 0x8fbceafa7575c975ULL, 0x301e0c3606061806ULL,
+	0x249809ae8a8a128aULL, 0xf940794bb2b2f2b2ULL, 0x6359d185e6e6bfe6ULL,
+	0x70361c7e0e0e380eULL, 0xf8633ee71f1f7c1fULL, 0x37f7c45562629562ULL,
+	0xeea3b53ad4d477d4ULL, 0x29324d81a8a89aa8ULL, 0xc4f4315296966296ULL,
+	0x9b3aef62f9f9c3f9ULL, 0x66f697a3c5c533c5ULL, 0x35b14a1025259425ULL,
+	0xf220b2ab59597959ULL, 0x54ae15d084842a84ULL, 0xb7a7e4c57272d572ULL,
+	0xd5dd72ec3939e439ULL, 0x5a6198164c4c2d4cULL, 0xca3bbc945e5e655eULL,
+	0xe785f09f7878fd78ULL, 0xddd870e53838e038ULL, 0x148605988c8c0a8cULL,
+	0xc6b2bf17d1d163d1ULL, 0x410b57e4a5a5aea5ULL, 0x434dd9a1e2e2afe2ULL,
+	0x2ff8c24e61619961ULL, 0xf1457b42b3b3f6b3ULL, 0x15a5423421218421ULL,
+	0x94d625089c9c4a9cULL, 0xf0663cee1e1e781eULL, 0x2252866143431143ULL,
+	0x76fc93b1c7c73bc7ULL, 0xb32be54ffcfcd7fcULL, 0x2014082404041004ULL,
+	0xb208a2e351515951ULL, 0xbcc72f2599995e99ULL, 0x4fc4da226d6da96dULL,
+	0x68391a650d0d340dULL, 0x8335e979fafacffaULL, 0xb684a369dfdf5bdfULL,
+	0xd79bfca97e7ee57eULL, 0x3db4481924249024ULL, 0xc5d776fe3b3bec3bULL,
+	0x313d4b9aabab96abULL, 0x3ed181f0cece1fceULL, 0x8855229911114411ULL,
+	0x0c8903838f8f068fULL, 0x4a6b9c044e4e254eULL, 0xd1517366b7b7e6b7ULL,
+	0x0b60cbe0ebeb8bebULL, 0xfdcc78c13c3cf03cULL, 0x7cbf1ffd81813e81ULL,
+	0xd4fe354094946a94ULL, 0xeb0cf31cf7f7fbf7ULL, 0xa1676f18b9b9deb9ULL,
+	0x985f268b13134c13ULL, 0x7d9c58512c2cb02cULL, 0xd6b8bb05d3d36bd3ULL,
+	0x6b5cd38ce7e7bbe7ULL, 0x57cbdc396e6ea56eULL, 0x6ef395aac4c437c4ULL,
+	0x180f061b03030c03ULL, 0x8a13acdc56564556ULL, 0x1a49885e44440d44ULL,
+	0xdf9efea07f7fe17fULL, 0x21374f88a9a99ea9ULL, 0x4d8254672a2aa82aULL,
+	0xb16d6b0abbbbd6bbULL, 0x46e29f87c1c123c1ULL, 0xa202a6f153535153ULL,
+	0xae8ba572dcdc57dcULL, 0x582716530b0b2c0bULL, 0x9cd327019d9d4e9dULL,
+	0x47c1d82b6c6cad6cULL, 0x95f562a43131c431ULL, 0x87b9e8f37474cd74ULL,
+	0xe309f115f6f6fff6ULL, 0x0a438c4c46460546ULL, 0x092645a5acac8aacULL,
+	0x3c970fb589891e89ULL, 0xa04428b414145014ULL, 0x5b42dfbae1e1a3e1ULL,
+	0xb04e2ca616165816ULL, 0xcdd274f73a3ae83aULL, 0x6fd0d2066969b969ULL,
+	0x482d124109092409ULL, 0xa7ade0d77070dd70ULL, 0xd954716fb6b6e2b6ULL,
+	0xceb7bd1ed0d067d0ULL, 0x3b7ec7d6eded93edULL, 0x2edb85e2cccc17ccULL,
+	0x2a57846842421542ULL, 0xb4c22d2c98985a98ULL, 0x490e55eda4a4aaa4ULL,
+	0x5d8850752828a028ULL, 0xda31b8865c5c6d5cULL, 0x933fed6bf8f8c7f8ULL,
+	0x44a411c286862286ULL,
+};
+
+static const u64 C5[256] = {
+	0x18c07830d8181860ULL, 0x2305af462623238cULL, 0xc67ef991b8c6c63fULL,
+	0xe8136fcdfbe8e887ULL, 0x874ca113cb878726ULL, 0xb8a9626d11b8b8daULL,
+	0x0108050209010104ULL, 0x4f426e9e0d4f4f21ULL, 0x36adee6c9b3636d8ULL,
+	0xa6590451ffa6a6a2ULL, 0xd2debdb90cd2d26fULL, 0xf5fb06f70ef5f5f3ULL,
+	0x79ef80f2967979f9ULL, 0x6f5fcede306f6fa1ULL, 0x91fcef3f6d91917eULL,
+	0x52aa07a4f8525255ULL, 0x6027fdc04760609dULL, 0xbc89766535bcbccaULL,
+	0x9baccd2b379b9b56ULL, 0x8e048c018a8e8e02ULL, 0xa371155bd2a3a3b6ULL,
+	0x0c603c186c0c0c30ULL, 0x7bff8af6847b7bf1ULL, 0x35b5e16a803535d4ULL,
+	0x1de8693af51d1d74ULL, 0xe05347ddb3e0e0a7ULL, 0xd7f6acb321d7d77bULL,
+	0xc25eed999cc2c22fULL, 0x2e6d965c432e2eb8ULL, 0x4b627a96294b4b31ULL,
+	0xfea321e15dfefedfULL, 0x578216aed5575741ULL, 0x15a8412abd151554ULL,
+	0x779fb6eee87777c1ULL, 0x37a5eb6e923737dcULL, 0xe57b56d79ee5e5b3ULL,
+	0x9f8cd923139f9f46ULL, 0xf0d317fd23f0f0e7ULL, 0x4a6a7f94204a4a35ULL,
+	0xda9e95a944dada4fULL, 0x58fa25b0a258587dULL, 0xc906ca8fcfc9c903ULL,
+	0x29558d527c2929a4ULL, 0x0a5022145a0a0a28ULL, 0xb1e14f7f50b1b1feULL,
+	0xa0691a5dc9a0a0baULL, 0x6b7fdad6146b6bb1ULL, 0x855cab17d985852eULL,
+	0xbd8173673cbdbdceULL, 0x5dd234ba8f5d5d69ULL, 0x1080502090101040ULL,
+	0xf4f303f507f4f4f7ULL, 0xcb16c08bddcbcb0bULL, 0x3eedc67cd33e3ef8ULL,
+	0x0528110a2d050514ULL, 0x671fe6ce78676781ULL, 0xe47353d597e4e4b7ULL,
+	0x2725bb4e0227279cULL, 0x4132588273414119ULL, 0x8b2c9d0ba78b8b16ULL,
+	0xa7510153f6a7a7a6ULL, 0x7dcf94fab27d7de9ULL, 0x95dcfb374995956eULL,
+	0xd88e9fad56d8d847ULL, 0xfb8b30eb70fbfbcbULL, 0xee2371c1cdeeee9fULL,
+	0x7cc791f8bb7c7cedULL, 0x6617e3cc71666685ULL, 0xdda68ea77bdddd53ULL,
+	0x17b84b2eaf17175cULL, 0x4702468e45474701ULL, 0x9e84dc211a9e9e42ULL,
+	0xca1ec589d4caca0fULL, 0x2d75995a582d2db4ULL, 0xbf9179632ebfbfc6ULL,
+	0x07381b0e3f07071cULL, 0xad012347acadad8eULL, 0x5aea2fb4b05a5a75ULL,
+	0x836cb51bef838336ULL, 0x3385ff66b63333ccULL, 0x633ff2c65c636391ULL,
+	0x02100a0412020208ULL, 0xaa39384993aaaa92ULL, 0x71afa8e2de7171d9ULL,
+	0xc80ecf8dc6c8c807ULL, 0x19c87d32d1191964ULL, 0x497270923b494939ULL,
+	0xd9869aaf5fd9d943ULL, 0xf2c31df931f2f2efULL, 0xe34b48dba8e3e3abULL,
+	0x5be22ab6b95b5b71ULL, 0x8834920dbc88881aULL, 0x9aa4c8293e9a9a52ULL,
+	0x262dbe4c0b262698ULL, 0x328dfa64bf3232c8ULL, 0xb0e94a7d59b0b0faULL,
+	0xe91b6acff2e9e983ULL, 0x0f78331e770f0f3cULL, 0xd5e6a6b733d5d573ULL,
+	0x8074ba1df480803aULL, 0xbe997c6127bebec2ULL, 0xcd26de87ebcdcd13ULL,
+	0x34bde468893434d0ULL, 0x487a75903248483dULL, 0xffab24e354ffffdbULL,
+	0x7af78ff48d7a7af5ULL, 0x90f4ea3d6490907aULL, 0x5fc23ebe9d5f5f61ULL,
+	0x201da0403d202080ULL, 0x6867d5d00f6868bdULL, 0x1ad07234ca1a1a68ULL,
+	0xae192c41b7aeae82ULL, 0xb4c95e757db4b4eaULL, 0x549a19a8ce54544dULL,
+	0x93ece53b7f939376ULL, 0x220daa442f222288ULL, 0x6407e9c86364648dULL,
+	0xf1db12ff2af1f1e3ULL, 0x73bfa2e6cc7373d1ULL, 0x12905a2482121248ULL,
+	0x403a5d807a40401dULL, 0x0840281048080820ULL, 0xc356e89b95c3c32bULL,
+	0xec337bc5dfecec97ULL, 0xdb9690ab4ddbdb4bULL, 0xa1611f5fc0a1a1beULL,
+	0x8d1c8307918d8d0eULL, 0x3df5c97ac83d3df4ULL, 0x97ccf1335b979766ULL,
+	0x0000000000000000ULL, 0xcf36d483f9cfcf1bULL, 0x2b4587566e2b2bacULL,
+	0x7697b3ece17676c5ULL, 0x8264b019e6828232ULL, 0xd6fea9b128d6d67fULL,
+	0x1bd87736c31b1b6cULL, 0xb5c15b7774b5b5eeULL, 0xaf112943beafaf86ULL,
+	0x6a77dfd41d6a6ab5ULL, 0x50ba0da0ea50505dULL, 0x45124c8a57454509ULL,
+	0xf3cb18fb38f3f3ebULL, 0x309df060ad3030c0ULL, 0xef2b74c3c4efef9bULL,
+	0x3fe5c37eda3f3ffcULL, 0x55921caac7555549ULL, 0xa2791059dba2a2b2ULL,
+	0xea0365c9e9eaea8fULL, 0x650fecca6a656589ULL, 0xbab9686903babad2ULL,
+	0x2f65935e4a2f2fbcULL, 0xc04ee79d8ec0c027ULL, 0xdebe81a160dede5fULL,
+	0x1ce06c38fc1c1c70ULL, 0xfdbb2ee746fdfdd3ULL, 0x4d52649a1f4d4d29ULL,
+	0x92e4e03976929272ULL, 0x758fbceafa7575c9ULL, 0x06301e0c36060618ULL,
+	0x8a249809ae8a8a12ULL, 0xb2f940794bb2b2f2ULL, 0xe66359d185e6e6bfULL,
+	0x0e70361c7e0e0e38ULL, 0x1ff8633ee71f1f7cULL, 0x6237f7c455626295ULL,
+	0xd4eea3b53ad4d477ULL, 0xa829324d81a8a89aULL, 0x96c4f43152969662ULL,
+	0xf99b3aef62f9f9c3ULL, 0xc566f697a3c5c533ULL, 0x2535b14a10252594ULL,
+	0x59f220b2ab595979ULL, 0x8454ae15d084842aULL, 0x72b7a7e4c57272d5ULL,
+	0x39d5dd72ec3939e4ULL, 0x4c5a6198164c4c2dULL, 0x5eca3bbc945e5e65ULL,
+	0x78e785f09f7878fdULL, 0x38ddd870e53838e0ULL, 0x8c148605988c8c0aULL,
+	0xd1c6b2bf17d1d163ULL, 0xa5410b57e4a5a5aeULL, 0xe2434dd9a1e2e2afULL,
+	0x612ff8c24e616199ULL, 0xb3f1457b42b3b3f6ULL, 0x2115a54234212184ULL,
+	0x9c94d625089c9c4aULL, 0x1ef0663cee1e1e78ULL, 0x4322528661434311ULL,
+	0xc776fc93b1c7c73bULL, 0xfcb32be54ffcfcd7ULL, 0x0420140824040410ULL,
+	0x51b208a2e3515159ULL, 0x99bcc72f2599995eULL, 0x6d4fc4da226d6da9ULL,
+	0x0d68391a650d0d34ULL, 0xfa8335e979fafacfULL, 0xdfb684a369dfdf5bULL,
+	0x7ed79bfca97e7ee5ULL, 0x243db44819242490ULL, 0x3bc5d776fe3b3becULL,
+	0xab313d4b9aabab96ULL, 0xce3ed181f0cece1fULL, 0x1188552299111144ULL,
+	0x8f0c8903838f8f06ULL, 0x4e4a6b9c044e4e25ULL, 0xb7d1517366b7b7e6ULL,
+	0xeb0b60cbe0ebeb8bULL, 0x3cfdcc78c13c3cf0ULL, 0x817cbf1ffd81813eULL,
+	0x94d4fe354094946aULL, 0xf7eb0cf31cf7f7fbULL, 0xb9a1676f18b9b9deULL,
+	0x13985f268b13134cULL, 0x2c7d9c58512c2cb0ULL, 0xd3d6b8bb05d3d36bULL,
+	0xe76b5cd38ce7e7bbULL, 0x6e57cbdc396e6ea5ULL, 0xc46ef395aac4c437ULL,
+	0x03180f061b03030cULL, 0x568a13acdc565645ULL, 0x441a49885e44440dULL,
+	0x7fdf9efea07f7fe1ULL, 0xa921374f88a9a99eULL, 0x2a4d8254672a2aa8ULL,
+	0xbbb16d6b0abbbbd6ULL, 0xc146e29f87c1c123ULL, 0x53a202a6f1535351ULL,
+	0xdcae8ba572dcdc57ULL, 0x0b582716530b0b2cULL, 0x9d9cd327019d9d4eULL,
+	0x6c47c1d82b6c6cadULL, 0x3195f562a43131c4ULL, 0x7487b9e8f37474cdULL,
+	0xf6e309f115f6f6ffULL, 0x460a438c4c464605ULL, 0xac092645a5acac8aULL,
+	0x893c970fb589891eULL, 0x14a04428b4141450ULL, 0xe15b42dfbae1e1a3ULL,
+	0x16b04e2ca6161658ULL, 0x3acdd274f73a3ae8ULL, 0x696fd0d2066969b9ULL,
+	0x09482d1241090924ULL, 0x70a7ade0d77070ddULL, 0xb6d954716fb6b6e2ULL,
+	0xd0ceb7bd1ed0d067ULL, 0xed3b7ec7d6eded93ULL, 0xcc2edb85e2cccc17ULL,
+	0x422a578468424215ULL, 0x98b4c22d2c98985aULL, 0xa4490e55eda4a4aaULL,
+	0x285d8850752828a0ULL, 0x5cda31b8865c5c6dULL, 0xf8933fed6bf8f8c7ULL,
+	0x8644a411c2868622ULL,
+};
+
+static const u64 C6[256] = {
+	0x6018c07830d81818ULL, 0x8c2305af46262323ULL, 0x3fc67ef991b8c6c6ULL,
+	0x87e8136fcdfbe8e8ULL, 0x26874ca113cb8787ULL, 0xdab8a9626d11b8b8ULL,
+	0x0401080502090101ULL, 0x214f426e9e0d4f4fULL, 0xd836adee6c9b3636ULL,
+	0xa2a6590451ffa6a6ULL, 0x6fd2debdb90cd2d2ULL, 0xf3f5fb06f70ef5f5ULL,
+	0xf979ef80f2967979ULL, 0xa16f5fcede306f6fULL, 0x7e91fcef3f6d9191ULL,
+	0x5552aa07a4f85252ULL, 0x9d6027fdc0476060ULL, 0xcabc89766535bcbcULL,
+	0x569baccd2b379b9bULL, 0x028e048c018a8e8eULL, 0xb6a371155bd2a3a3ULL,
+	0x300c603c186c0c0cULL, 0xf17bff8af6847b7bULL, 0xd435b5e16a803535ULL,
+	0x741de8693af51d1dULL, 0xa7e05347ddb3e0e0ULL, 0x7bd7f6acb321d7d7ULL,
+	0x2fc25eed999cc2c2ULL, 0xb82e6d965c432e2eULL, 0x314b627a96294b4bULL,
+	0xdffea321e15dfefeULL, 0x41578216aed55757ULL, 0x5415a8412abd1515ULL,
+	0xc1779fb6eee87777ULL, 0xdc37a5eb6e923737ULL, 0xb3e57b56d79ee5e5ULL,
+	0x469f8cd923139f9fULL, 0xe7f0d317fd23f0f0ULL, 0x354a6a7f94204a4aULL,
+	0x4fda9e95a944dadaULL, 0x7d58fa25b0a25858ULL, 0x03c906ca8fcfc9c9ULL,
+	0xa429558d527c2929ULL, 0x280a5022145a0a0aULL, 0xfeb1e14f7f50b1b1ULL,
+	0xbaa0691a5dc9a0a0ULL, 0xb16b7fdad6146b6bULL, 0x2e855cab17d98585ULL,
+	0xcebd8173673cbdbdULL, 0x695dd234ba8f5d5dULL, 0x4010805020901010ULL,
+	0xf7f4f303f507f4f4ULL, 0x0bcb16c08bddcbcbULL, 0xf83eedc67cd33e3eULL,
+	0x140528110a2d0505ULL, 0x81671fe6ce786767ULL, 0xb7e47353d597e4e4ULL,
+	0x9c2725bb4e022727ULL, 0x1941325882734141ULL, 0x168b2c9d0ba78b8bULL,
+	0xa6a7510153f6a7a7ULL, 0xe97dcf94fab27d7dULL, 0x6e95dcfb37499595ULL,
+	0x47d88e9fad56d8d8ULL, 0xcbfb8b30eb70fbfbULL, 0x9fee2371c1cdeeeeULL,
+	0xed7cc791f8bb7c7cULL, 0x856617e3cc716666ULL, 0x53dda68ea77bddddULL,
+	0x5c17b84b2eaf1717ULL, 0x014702468e454747ULL, 0x429e84dc211a9e9eULL,
+	0x0fca1ec589d4cacaULL, 0xb42d75995a582d2dULL, 0xc6bf9179632ebfbfULL,
+	0x1c07381b0e3f0707ULL, 0x8ead012347acadadULL, 0x755aea2fb4b05a5aULL,
+	0x36836cb51bef8383ULL, 0xcc3385ff66b63333ULL, 0x91633ff2c65c6363ULL,
+	0x0802100a04120202ULL, 0x92aa39384993aaaaULL, 0xd971afa8e2de7171ULL,
+	0x07c80ecf8dc6c8c8ULL, 0x6419c87d32d11919ULL, 0x39497270923b4949ULL,
+	0x43d9869aaf5fd9d9ULL, 0xeff2c31df931f2f2ULL, 0xabe34b48dba8e3e3ULL,
+	0x715be22ab6b95b5bULL, 0x1a8834920dbc8888ULL, 0x529aa4c8293e9a9aULL,
+	0x98262dbe4c0b2626ULL, 0xc8328dfa64bf3232ULL, 0xfab0e94a7d59b0b0ULL,
+	0x83e91b6acff2e9e9ULL, 0x3c0f78331e770f0fULL, 0x73d5e6a6b733d5d5ULL,
+	0x3a8074ba1df48080ULL, 0xc2be997c6127bebeULL, 0x13cd26de87ebcdcdULL,
+	0xd034bde468893434ULL, 0x3d487a7590324848ULL, 0xdbffab24e354ffffULL,
+	0xf57af78ff48d7a7aULL, 0x7a90f4ea3d649090ULL, 0x615fc23ebe9d5f5fULL,
+	0x80201da0403d2020ULL, 0xbd6867d5d00f6868ULL, 0x681ad07234ca1a1aULL,
+	0x82ae192c41b7aeaeULL, 0xeab4c95e757db4b4ULL, 0x4d549a19a8ce5454ULL,
+	0x7693ece53b7f9393ULL, 0x88220daa442f2222ULL, 0x8d6407e9c8636464ULL,
+	0xe3f1db12ff2af1f1ULL, 0xd173bfa2e6cc7373ULL, 0x4812905a24821212ULL,
+	0x1d403a5d807a4040ULL, 0x2008402810480808ULL, 0x2bc356e89b95c3c3ULL,
+	0x97ec337bc5dfececULL, 0x4bdb9690ab4ddbdbULL, 0xbea1611f5fc0a1a1ULL,
+	0x0e8d1c8307918d8dULL, 0xf43df5c97ac83d3dULL, 0x6697ccf1335b9797ULL,
+	0x0000000000000000ULL, 0x1bcf36d483f9cfcfULL, 0xac2b4587566e2b2bULL,
+	0xc57697b3ece17676ULL, 0x328264b019e68282ULL, 0x7fd6fea9b128d6d6ULL,
+	0x6c1bd87736c31b1bULL, 0xeeb5c15b7774b5b5ULL, 0x86af112943beafafULL,
+	0xb56a77dfd41d6a6aULL, 0x5d50ba0da0ea5050ULL, 0x0945124c8a574545ULL,
+	0xebf3cb18fb38f3f3ULL, 0xc0309df060ad3030ULL, 0x9bef2b74c3c4efefULL,
+	0xfc3fe5c37eda3f3fULL, 0x4955921caac75555ULL, 0xb2a2791059dba2a2ULL,
+	0x8fea0365c9e9eaeaULL, 0x89650fecca6a6565ULL, 0xd2bab9686903babaULL,
+	0xbc2f65935e4a2f2fULL, 0x27c04ee79d8ec0c0ULL, 0x5fdebe81a160dedeULL,
+	0x701ce06c38fc1c1cULL, 0xd3fdbb2ee746fdfdULL, 0x294d52649a1f4d4dULL,
+	0x7292e4e039769292ULL, 0xc9758fbceafa7575ULL, 0x1806301e0c360606ULL,
+	0x128a249809ae8a8aULL, 0xf2b2f940794bb2b2ULL, 0xbfe66359d185e6e6ULL,
+	0x380e70361c7e0e0eULL, 0x7c1ff8633ee71f1fULL, 0x956237f7c4556262ULL,
+	0x77d4eea3b53ad4d4ULL, 0x9aa829324d81a8a8ULL, 0x6296c4f431529696ULL,
+	0xc3f99b3aef62f9f9ULL, 0x33c566f697a3c5c5ULL, 0x942535b14a102525ULL,
+	0x7959f220b2ab5959ULL, 0x2a8454ae15d08484ULL, 0xd572b7a7e4c57272ULL,
+	0xe439d5dd72ec3939ULL, 0x2d4c5a6198164c4cULL, 0x655eca3bbc945e5eULL,
+	0xfd78e785f09f7878ULL, 0xe038ddd870e53838ULL, 0x0a8c148605988c8cULL,
+	0x63d1c6b2bf17d1d1ULL, 0xaea5410b57e4a5a5ULL, 0xafe2434dd9a1e2e2ULL,
+	0x99612ff8c24e6161ULL, 0xf6b3f1457b42b3b3ULL, 0x842115a542342121ULL,
+	0x4a9c94d625089c9cULL, 0x781ef0663cee1e1eULL, 0x1143225286614343ULL,
+	0x3bc776fc93b1c7c7ULL, 0xd7fcb32be54ffcfcULL, 0x1004201408240404ULL,
+	0x5951b208a2e35151ULL, 0x5e99bcc72f259999ULL, 0xa96d4fc4da226d6dULL,
+	0x340d68391a650d0dULL, 0xcffa8335e979fafaULL, 0x5bdfb684a369dfdfULL,
+	0xe57ed79bfca97e7eULL, 0x90243db448192424ULL, 0xec3bc5d776fe3b3bULL,
+	0x96ab313d4b9aababULL, 0x1fce3ed181f0ceceULL, 0x4411885522991111ULL,
+	0x068f0c8903838f8fULL, 0x254e4a6b9c044e4eULL, 0xe6b7d1517366b7b7ULL,
+	0x8beb0b60cbe0ebebULL, 0xf03cfdcc78c13c3cULL, 0x3e817cbf1ffd8181ULL,
+	0x6a94d4fe35409494ULL, 0xfbf7eb0cf31cf7f7ULL, 0xdeb9a1676f18b9b9ULL,
+	0x4c13985f268b1313ULL, 0xb02c7d9c58512c2cULL, 0x6bd3d6b8bb05d3d3ULL,
+	0xbbe76b5cd38ce7e7ULL, 0xa56e57cbdc396e6eULL, 0x37c46ef395aac4c4ULL,
+	0x0c03180f061b0303ULL, 0x45568a13acdc5656ULL, 0x0d441a49885e4444ULL,
+	0xe17fdf9efea07f7fULL, 0x9ea921374f88a9a9ULL, 0xa82a4d8254672a2aULL,
+	0xd6bbb16d6b0abbbbULL, 0x23c146e29f87c1c1ULL, 0x5153a202a6f15353ULL,
+	0x57dcae8ba572dcdcULL, 0x2c0b582716530b0bULL, 0x4e9d9cd327019d9dULL,
+	0xad6c47c1d82b6c6cULL, 0xc43195f562a43131ULL, 0xcd7487b9e8f37474ULL,
+	0xfff6e309f115f6f6ULL, 0x05460a438c4c4646ULL, 0x8aac092645a5acacULL,
+	0x1e893c970fb58989ULL, 0x5014a04428b41414ULL, 0xa3e15b42dfbae1e1ULL,
+	0x5816b04e2ca61616ULL, 0xe83acdd274f73a3aULL, 0xb9696fd0d2066969ULL,
+	0x2409482d12410909ULL, 0xdd70a7ade0d77070ULL, 0xe2b6d954716fb6b6ULL,
+	0x67d0ceb7bd1ed0d0ULL, 0x93ed3b7ec7d6ededULL, 0x17cc2edb85e2ccccULL,
+	0x15422a5784684242ULL, 0x5a98b4c22d2c9898ULL, 0xaaa4490e55eda4a4ULL,
+	0xa0285d8850752828ULL, 0x6d5cda31b8865c5cULL, 0xc7f8933fed6bf8f8ULL,
+	0x228644a411c28686ULL,
+};
+
+static const u64 C7[256] = {
+	0x186018c07830d818ULL, 0x238c2305af462623ULL, 0xc63fc67ef991b8c6ULL,
+	0xe887e8136fcdfbe8ULL, 0x8726874ca113cb87ULL, 0xb8dab8a9626d11b8ULL,
+	0x0104010805020901ULL, 0x4f214f426e9e0d4fULL, 0x36d836adee6c9b36ULL,
+	0xa6a2a6590451ffa6ULL, 0xd26fd2debdb90cd2ULL, 0xf5f3f5fb06f70ef5ULL,
+	0x79f979ef80f29679ULL, 0x6fa16f5fcede306fULL, 0x917e91fcef3f6d91ULL,
+	0x525552aa07a4f852ULL, 0x609d6027fdc04760ULL, 0xbccabc89766535bcULL,
+	0x9b569baccd2b379bULL, 0x8e028e048c018a8eULL, 0xa3b6a371155bd2a3ULL,
+	0x0c300c603c186c0cULL, 0x7bf17bff8af6847bULL, 0x35d435b5e16a8035ULL,
+	0x1d741de8693af51dULL, 0xe0a7e05347ddb3e0ULL, 0xd77bd7f6acb321d7ULL,
+	0xc22fc25eed999cc2ULL, 0x2eb82e6d965c432eULL, 0x4b314b627a96294bULL,
+	0xfedffea321e15dfeULL, 0x5741578216aed557ULL, 0x155415a8412abd15ULL,
+	0x77c1779fb6eee877ULL, 0x37dc37a5eb6e9237ULL, 0xe5b3e57b56d79ee5ULL,
+	0x9f469f8cd923139fULL, 0xf0e7f0d317fd23f0ULL, 0x4a354a6a7f94204aULL,
+	0xda4fda9e95a944daULL, 0x587d58fa25b0a258ULL, 0xc903c906ca8fcfc9ULL,
+	0x29a429558d527c29ULL, 0x0a280a5022145a0aULL, 0xb1feb1e14f7f50b1ULL,
+	0xa0baa0691a5dc9a0ULL, 0x6bb16b7fdad6146bULL, 0x852e855cab17d985ULL,
+	0xbdcebd8173673cbdULL, 0x5d695dd234ba8f5dULL, 0x1040108050209010ULL,
+	0xf4f7f4f303f507f4ULL, 0xcb0bcb16c08bddcbULL, 0x3ef83eedc67cd33eULL,
+	0x05140528110a2d05ULL, 0x6781671fe6ce7867ULL, 0xe4b7e47353d597e4ULL,
+	0x279c2725bb4e0227ULL, 0x4119413258827341ULL, 0x8b168b2c9d0ba78bULL,
+	0xa7a6a7510153f6a7ULL, 0x7de97dcf94fab27dULL, 0x956e95dcfb374995ULL,
+	0xd847d88e9fad56d8ULL, 0xfbcbfb8b30eb70fbULL, 0xee9fee2371c1cdeeULL,
+	0x7ced7cc791f8bb7cULL, 0x66856617e3cc7166ULL, 0xdd53dda68ea77bddULL,
+	0x175c17b84b2eaf17ULL, 0x47014702468e4547ULL, 0x9e429e84dc211a9eULL,
+	0xca0fca1ec589d4caULL, 0x2db42d75995a582dULL, 0xbfc6bf9179632ebfULL,
+	0x071c07381b0e3f07ULL, 0xad8ead012347acadULL, 0x5a755aea2fb4b05aULL,
+	0x8336836cb51bef83ULL, 0x33cc3385ff66b633ULL, 0x6391633ff2c65c63ULL,
+	0x020802100a041202ULL, 0xaa92aa39384993aaULL, 0x71d971afa8e2de71ULL,
+	0xc807c80ecf8dc6c8ULL, 0x196419c87d32d119ULL, 0x4939497270923b49ULL,
+	0xd943d9869aaf5fd9ULL, 0xf2eff2c31df931f2ULL, 0xe3abe34b48dba8e3ULL,
+	0x5b715be22ab6b95bULL, 0x881a8834920dbc88ULL, 0x9a529aa4c8293e9aULL,
+	0x2698262dbe4c0b26ULL, 0x32c8328dfa64bf32ULL, 0xb0fab0e94a7d59b0ULL,
+	0xe983e91b6acff2e9ULL, 0x0f3c0f78331e770fULL, 0xd573d5e6a6b733d5ULL,
+	0x803a8074ba1df480ULL, 0xbec2be997c6127beULL, 0xcd13cd26de87ebcdULL,
+	0x34d034bde4688934ULL, 0x483d487a75903248ULL, 0xffdbffab24e354ffULL,
+	0x7af57af78ff48d7aULL, 0x907a90f4ea3d6490ULL, 0x5f615fc23ebe9d5fULL,
+	0x2080201da0403d20ULL, 0x68bd6867d5d00f68ULL, 0x1a681ad07234ca1aULL,
+	0xae82ae192c41b7aeULL, 0xb4eab4c95e757db4ULL, 0x544d549a19a8ce54ULL,
+	0x937693ece53b7f93ULL, 0x2288220daa442f22ULL, 0x648d6407e9c86364ULL,
+	0xf1e3f1db12ff2af1ULL, 0x73d173bfa2e6cc73ULL, 0x124812905a248212ULL,
+	0x401d403a5d807a40ULL, 0x0820084028104808ULL, 0xc32bc356e89b95c3ULL,
+	0xec97ec337bc5dfecULL, 0xdb4bdb9690ab4ddbULL, 0xa1bea1611f5fc0a1ULL,
+	0x8d0e8d1c8307918dULL, 0x3df43df5c97ac83dULL, 0x976697ccf1335b97ULL,
+	0x0000000000000000ULL, 0xcf1bcf36d483f9cfULL, 0x2bac2b4587566e2bULL,
+	0x76c57697b3ece176ULL, 0x82328264b019e682ULL, 0xd67fd6fea9b128d6ULL,
+	0x1b6c1bd87736c31bULL, 0xb5eeb5c15b7774b5ULL, 0xaf86af112943beafULL,
+	0x6ab56a77dfd41d6aULL, 0x505d50ba0da0ea50ULL, 0x450945124c8a5745ULL,
+	0xf3ebf3cb18fb38f3ULL, 0x30c0309df060ad30ULL, 0xef9bef2b74c3c4efULL,
+	0x3ffc3fe5c37eda3fULL, 0x554955921caac755ULL, 0xa2b2a2791059dba2ULL,
+	0xea8fea0365c9e9eaULL, 0x6589650fecca6a65ULL, 0xbad2bab9686903baULL,
+	0x2fbc2f65935e4a2fULL, 0xc027c04ee79d8ec0ULL, 0xde5fdebe81a160deULL,
+	0x1c701ce06c38fc1cULL, 0xfdd3fdbb2ee746fdULL, 0x4d294d52649a1f4dULL,
+	0x927292e4e0397692ULL, 0x75c9758fbceafa75ULL, 0x061806301e0c3606ULL,
+	0x8a128a249809ae8aULL, 0xb2f2b2f940794bb2ULL, 0xe6bfe66359d185e6ULL,
+	0x0e380e70361c7e0eULL, 0x1f7c1ff8633ee71fULL, 0x62956237f7c45562ULL,
+	0xd477d4eea3b53ad4ULL, 0xa89aa829324d81a8ULL, 0x966296c4f4315296ULL,
+	0xf9c3f99b3aef62f9ULL, 0xc533c566f697a3c5ULL, 0x25942535b14a1025ULL,
+	0x597959f220b2ab59ULL, 0x842a8454ae15d084ULL, 0x72d572b7a7e4c572ULL,
+	0x39e439d5dd72ec39ULL, 0x4c2d4c5a6198164cULL, 0x5e655eca3bbc945eULL,
+	0x78fd78e785f09f78ULL, 0x38e038ddd870e538ULL, 0x8c0a8c148605988cULL,
+	0xd163d1c6b2bf17d1ULL, 0xa5aea5410b57e4a5ULL, 0xe2afe2434dd9a1e2ULL,
+	0x6199612ff8c24e61ULL, 0xb3f6b3f1457b42b3ULL, 0x21842115a5423421ULL,
+	0x9c4a9c94d625089cULL, 0x1e781ef0663cee1eULL, 0x4311432252866143ULL,
+	0xc73bc776fc93b1c7ULL, 0xfcd7fcb32be54ffcULL, 0x0410042014082404ULL,
+	0x515951b208a2e351ULL, 0x995e99bcc72f2599ULL, 0x6da96d4fc4da226dULL,
+	0x0d340d68391a650dULL, 0xfacffa8335e979faULL, 0xdf5bdfb684a369dfULL,
+	0x7ee57ed79bfca97eULL, 0x2490243db4481924ULL, 0x3bec3bc5d776fe3bULL,
+	0xab96ab313d4b9aabULL, 0xce1fce3ed181f0ceULL, 0x1144118855229911ULL,
+	0x8f068f0c8903838fULL, 0x4e254e4a6b9c044eULL, 0xb7e6b7d1517366b7ULL,
+	0xeb8beb0b60cbe0ebULL, 0x3cf03cfdcc78c13cULL, 0x813e817cbf1ffd81ULL,
+	0x946a94d4fe354094ULL, 0xf7fbf7eb0cf31cf7ULL, 0xb9deb9a1676f18b9ULL,
+	0x134c13985f268b13ULL, 0x2cb02c7d9c58512cULL, 0xd36bd3d6b8bb05d3ULL,
+	0xe7bbe76b5cd38ce7ULL, 0x6ea56e57cbdc396eULL, 0xc437c46ef395aac4ULL,
+	0x030c03180f061b03ULL, 0x5645568a13acdc56ULL, 0x440d441a49885e44ULL,
+	0x7fe17fdf9efea07fULL, 0xa99ea921374f88a9ULL, 0x2aa82a4d8254672aULL,
+	0xbbd6bbb16d6b0abbULL, 0xc123c146e29f87c1ULL, 0x535153a202a6f153ULL,
+	0xdc57dcae8ba572dcULL, 0x0b2c0b582716530bULL, 0x9d4e9d9cd327019dULL,
+	0x6cad6c47c1d82b6cULL, 0x31c43195f562a431ULL, 0x74cd7487b9e8f374ULL,
+	0xf6fff6e309f115f6ULL, 0x4605460a438c4c46ULL, 0xac8aac092645a5acULL,
+	0x891e893c970fb589ULL, 0x145014a04428b414ULL, 0xe1a3e15b42dfbae1ULL,
+	0x165816b04e2ca616ULL, 0x3ae83acdd274f73aULL, 0x69b9696fd0d20669ULL,
+	0x092409482d124109ULL, 0x70dd70a7ade0d770ULL, 0xb6e2b6d954716fb6ULL,
+	0xd067d0ceb7bd1ed0ULL, 0xed93ed3b7ec7d6edULL, 0xcc17cc2edb85e2ccULL,
+	0x4215422a57846842ULL, 0x985a98b4c22d2c98ULL, 0xa4aaa4490e55eda4ULL,
+	0x28a0285d88507528ULL, 0x5c6d5cda31b8865cULL, 0xf8c7f8933fed6bf8ULL,
+	0x86228644a411c286ULL,
+};
+
+static const u64 rc[WHIRLPOOL_ROUNDS + 1] = {
+	0x0000000000000000ULL, 0x1823c6e887b8014fULL, 0x36a6d2f5796f9152ULL,
+	0x60bc9b8ea30c7b35ULL, 0x1de0d7c22e4bfe57ULL, 0x157737e59ff04adaULL,
+	0x58c9290ab1a06b85ULL, 0xbd5d10f4cb3e0567ULL, 0xe427418ba77d95d8ULL,
+	0xfbee7c66dd17479eULL, 0xca2dbf07ad5a8333ULL,
+};
+
+/**
+ * The core Whirlpool transform.
+ */
+
+static void wp512_process_buffer(struct wp512_ctx *wctx) {
+	int i, r;
+	u64 K[8];        /* the round key */
+	u64 block[8];    /* mu(buffer) */
+	u64 state[8];    /* the cipher state */
+	u64 L[8];
+	u8 *buffer = wctx->buffer;
+
+	for (i = 0; i < 8; i++, buffer += 8) {
+		block[i] =
+		(((u64)buffer[0]        ) << 56) ^
+		(((u64)buffer[1] & 0xffL) << 48) ^
+		(((u64)buffer[2] & 0xffL) << 40) ^
+		(((u64)buffer[3] & 0xffL) << 32) ^
+		(((u64)buffer[4] & 0xffL) << 24) ^
+		(((u64)buffer[5] & 0xffL) << 16) ^
+		(((u64)buffer[6] & 0xffL) <<  8) ^
+		(((u64)buffer[7] & 0xffL)      );
+	}
+
+	state[0] = block[0] ^ (K[0] = wctx->hash[0]);
+	state[1] = block[1] ^ (K[1] = wctx->hash[1]);
+	state[2] = block[2] ^ (K[2] = wctx->hash[2]);
+	state[3] = block[3] ^ (K[3] = wctx->hash[3]);
+	state[4] = block[4] ^ (K[4] = wctx->hash[4]);
+	state[5] = block[5] ^ (K[5] = wctx->hash[5]);
+	state[6] = block[6] ^ (K[6] = wctx->hash[6]);
+	state[7] = block[7] ^ (K[7] = wctx->hash[7]);
+
+	for (r = 1; r <= WHIRLPOOL_ROUNDS; r++) {
+
+		L[0] = C0[(int)(K[0] >> 56)       ] ^
+			   C1[(int)(K[7] >> 48) & 0xff] ^
+			   C2[(int)(K[6] >> 40) & 0xff] ^
+			   C3[(int)(K[5] >> 32) & 0xff] ^
+			   C4[(int)(K[4] >> 24) & 0xff] ^
+			   C5[(int)(K[3] >> 16) & 0xff] ^
+			   C6[(int)(K[2] >>  8) & 0xff] ^
+			   C7[(int)(K[1]      ) & 0xff] ^
+			   rc[r];
+
+		L[1] = C0[(int)(K[1] >> 56)       ] ^
+			   C1[(int)(K[0] >> 48) & 0xff] ^
+			   C2[(int)(K[7] >> 40) & 0xff] ^
+			   C3[(int)(K[6] >> 32) & 0xff] ^
+			   C4[(int)(K[5] >> 24) & 0xff] ^
+			   C5[(int)(K[4] >> 16) & 0xff] ^
+			   C6[(int)(K[3] >>  8) & 0xff] ^
+			   C7[(int)(K[2]      ) & 0xff];
+
+		L[2] = C0[(int)(K[2] >> 56)       ] ^
+			   C1[(int)(K[1] >> 48) & 0xff] ^
+			   C2[(int)(K[0] >> 40) & 0xff] ^
+			   C3[(int)(K[7] >> 32) & 0xff] ^
+			   C4[(int)(K[6] >> 24) & 0xff] ^
+			   C5[(int)(K[5] >> 16) & 0xff] ^
+			   C6[(int)(K[4] >>  8) & 0xff] ^
+			   C7[(int)(K[3]      ) & 0xff];
+
+		L[3] = C0[(int)(K[3] >> 56)       ] ^
+			   C1[(int)(K[2] >> 48) & 0xff] ^
+			   C2[(int)(K[1] >> 40) & 0xff] ^
+			   C3[(int)(K[0] >> 32) & 0xff] ^
+			   C4[(int)(K[7] >> 24) & 0xff] ^
+			   C5[(int)(K[6] >> 16) & 0xff] ^
+			   C6[(int)(K[5] >>  8) & 0xff] ^
+			   C7[(int)(K[4]      ) & 0xff];
+
+		L[4] = C0[(int)(K[4] >> 56)       ] ^
+			   C1[(int)(K[3] >> 48) & 0xff] ^
+			   C2[(int)(K[2] >> 40) & 0xff] ^
+			   C3[(int)(K[1] >> 32) & 0xff] ^
+			   C4[(int)(K[0] >> 24) & 0xff] ^
+			   C5[(int)(K[7] >> 16) & 0xff] ^
+			   C6[(int)(K[6] >>  8) & 0xff] ^
+			   C7[(int)(K[5]      ) & 0xff];
+
+		L[5] = C0[(int)(K[5] >> 56)       ] ^
+			   C1[(int)(K[4] >> 48) & 0xff] ^
+			   C2[(int)(K[3] >> 40) & 0xff] ^
+			   C3[(int)(K[2] >> 32) & 0xff] ^
+			   C4[(int)(K[1] >> 24) & 0xff] ^
+			   C5[(int)(K[0] >> 16) & 0xff] ^
+			   C6[(int)(K[7] >>  8) & 0xff] ^
+			   C7[(int)(K[6]      ) & 0xff];
+
+		L[6] = C0[(int)(K[6] >> 56)       ] ^
+			   C1[(int)(K[5] >> 48) & 0xff] ^
+			   C2[(int)(K[4] >> 40) & 0xff] ^
+			   C3[(int)(K[3] >> 32) & 0xff] ^
+			   C4[(int)(K[2] >> 24) & 0xff] ^
+			   C5[(int)(K[1] >> 16) & 0xff] ^
+			   C6[(int)(K[0] >>  8) & 0xff] ^
+			   C7[(int)(K[7]      ) & 0xff];
+
+		L[7] = C0[(int)(K[7] >> 56)       ] ^
+			   C1[(int)(K[6] >> 48) & 0xff] ^
+			   C2[(int)(K[5] >> 40) & 0xff] ^
+			   C3[(int)(K[4] >> 32) & 0xff] ^
+			   C4[(int)(K[3] >> 24) & 0xff] ^
+			   C5[(int)(K[2] >> 16) & 0xff] ^
+			   C6[(int)(K[1] >>  8) & 0xff] ^
+			   C7[(int)(K[0]      ) & 0xff];
+
+		K[0] = L[0];
+		K[1] = L[1];
+		K[2] = L[2];
+		K[3] = L[3];
+		K[4] = L[4];
+		K[5] = L[5];
+		K[6] = L[6];
+		K[7] = L[7];
+
+		L[0] = C0[(int)(state[0] >> 56)       ] ^
+			   C1[(int)(state[7] >> 48) & 0xff] ^
+			   C2[(int)(state[6] >> 40) & 0xff] ^
+			   C3[(int)(state[5] >> 32) & 0xff] ^
+			   C4[(int)(state[4] >> 24) & 0xff] ^
+			   C5[(int)(state[3] >> 16) & 0xff] ^
+			   C6[(int)(state[2] >>  8) & 0xff] ^
+			   C7[(int)(state[1]      ) & 0xff] ^
+			   K[0];
+
+		L[1] = C0[(int)(state[1] >> 56)       ] ^
+			   C1[(int)(state[0] >> 48) & 0xff] ^
+			   C2[(int)(state[7] >> 40) & 0xff] ^
+			   C3[(int)(state[6] >> 32) & 0xff] ^
+			   C4[(int)(state[5] >> 24) & 0xff] ^
+			   C5[(int)(state[4] >> 16) & 0xff] ^
+			   C6[(int)(state[3] >>  8) & 0xff] ^
+			   C7[(int)(state[2]      ) & 0xff] ^
+			   K[1];
+
+		L[2] = C0[(int)(state[2] >> 56)       ] ^
+			   C1[(int)(state[1] >> 48) & 0xff] ^
+			   C2[(int)(state[0] >> 40) & 0xff] ^
+			   C3[(int)(state[7] >> 32) & 0xff] ^
+			   C4[(int)(state[6] >> 24) & 0xff] ^
+			   C5[(int)(state[5] >> 16) & 0xff] ^
+			   C6[(int)(state[4] >>  8) & 0xff] ^
+			   C7[(int)(state[3]      ) & 0xff] ^
+			   K[2];
+
+		L[3] = C0[(int)(state[3] >> 56)       ] ^
+			   C1[(int)(state[2] >> 48) & 0xff] ^
+			   C2[(int)(state[1] >> 40) & 0xff] ^
+			   C3[(int)(state[0] >> 32) & 0xff] ^
+			   C4[(int)(state[7] >> 24) & 0xff] ^
+			   C5[(int)(state[6] >> 16) & 0xff] ^
+			   C6[(int)(state[5] >>  8) & 0xff] ^
+			   C7[(int)(state[4]      ) & 0xff] ^
+			   K[3];
+
+		L[4] = C0[(int)(state[4] >> 56)       ] ^
+			   C1[(int)(state[3] >> 48) & 0xff] ^
+			   C2[(int)(state[2] >> 40) & 0xff] ^
+			   C3[(int)(state[1] >> 32) & 0xff] ^
+			   C4[(int)(state[0] >> 24) & 0xff] ^
+			   C5[(int)(state[7] >> 16) & 0xff] ^
+			   C6[(int)(state[6] >>  8) & 0xff] ^
+			   C7[(int)(state[5]      ) & 0xff] ^
+			   K[4];
+
+		L[5] = C0[(int)(state[5] >> 56)       ] ^
+			   C1[(int)(state[4] >> 48) & 0xff] ^
+			   C2[(int)(state[3] >> 40) & 0xff] ^
+			   C3[(int)(state[2] >> 32) & 0xff] ^
+			   C4[(int)(state[1] >> 24) & 0xff] ^
+			   C5[(int)(state[0] >> 16) & 0xff] ^
+			   C6[(int)(state[7] >>  8) & 0xff] ^
+			   C7[(int)(state[6]      ) & 0xff] ^
+			   K[5];
+
+		L[6] = C0[(int)(state[6] >> 56)       ] ^
+			   C1[(int)(state[5] >> 48) & 0xff] ^
+			   C2[(int)(state[4] >> 40) & 0xff] ^
+			   C3[(int)(state[3] >> 32) & 0xff] ^
+			   C4[(int)(state[2] >> 24) & 0xff] ^
+			   C5[(int)(state[1] >> 16) & 0xff] ^
+			   C6[(int)(state[0] >>  8) & 0xff] ^
+			   C7[(int)(state[7]      ) & 0xff] ^
+			   K[6];
+
+		L[7] = C0[(int)(state[7] >> 56)       ] ^
+			   C1[(int)(state[6] >> 48) & 0xff] ^
+			   C2[(int)(state[5] >> 40) & 0xff] ^
+			   C3[(int)(state[4] >> 32) & 0xff] ^
+			   C4[(int)(state[3] >> 24) & 0xff] ^
+			   C5[(int)(state[2] >> 16) & 0xff] ^
+			   C6[(int)(state[1] >>  8) & 0xff] ^
+			   C7[(int)(state[0]      ) & 0xff] ^
+			   K[7];
+
+		state[0] = L[0];
+		state[1] = L[1];
+		state[2] = L[2];
+		state[3] = L[3];
+		state[4] = L[4];
+		state[5] = L[5];
+		state[6] = L[6];
+		state[7] = L[7];
+	}
+	/*
+	* apply the Miyaguchi-Preneel compression function:
+	*/
+	wctx->hash[0] ^= state[0] ^ block[0];
+	wctx->hash[1] ^= state[1] ^ block[1];
+	wctx->hash[2] ^= state[2] ^ block[2];
+	wctx->hash[3] ^= state[3] ^ block[3];
+	wctx->hash[4] ^= state[4] ^ block[4];
+	wctx->hash[5] ^= state[5] ^ block[5];
+	wctx->hash[6] ^= state[6] ^ block[6];
+	wctx->hash[7] ^= state[7] ^ block[7];
+
+}
+
+static void wp512_init (void *ctx) {
+	int i;
+	struct wp512_ctx *wctx = ctx;
+
+	memset(wctx->bitLength, 0, 32);
+	wctx->bufferBits = wctx->bufferPos = 0;
+	wctx->buffer[0] = 0;
+	for (i = 0; i < 8; i++) {
+		wctx->hash[i] = 0L;
+	}
+}
+
+static void wp512_update(void *ctx, const u8 *source, unsigned int len)
+{
+
+	struct wp512_ctx *wctx = ctx;
+	int sourcePos    = 0;
+	unsigned int bits_len = len * 8; // convert to number of bits
+	int sourceGap    = (8 - ((int)bits_len & 7)) & 7;
+	int bufferRem    = wctx->bufferBits & 7;
+	int i;
+	u32 b, carry;
+	u8 *buffer       = wctx->buffer;
+	u8 *bitLength    = wctx->bitLength;
+	int bufferBits   = wctx->bufferBits;
+	int bufferPos    = wctx->bufferPos;
+
+	u64 value = bits_len;
+	for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != 0ULL); i--) {
+		carry += bitLength[i] + ((u32)value & 0xff);
+		bitLength[i] = (u8)carry;
+		carry >>= 8;
+		value >>= 8;
+	}
+	while (bits_len > 8) {
+		b = ((source[sourcePos] << sourceGap) & 0xff) |
+		((source[sourcePos + 1] & 0xff) >> (8 - sourceGap));
+		buffer[bufferPos++] |= (u8)(b >> bufferRem);
+		bufferBits += 8 - bufferRem;
+		if (bufferBits == WP512_BLOCK_SIZE * 8) {
+			wp512_process_buffer(wctx);
+			bufferBits = bufferPos = 0;
+		}
+		buffer[bufferPos] = b << (8 - bufferRem);
+		bufferBits += bufferRem;
+		bits_len -= 8;
+		sourcePos++;
+	}
+	if (bits_len > 0) {
+		b = (source[sourcePos] << sourceGap) & 0xff;
+		buffer[bufferPos] |= b >> bufferRem;
+	} else {
+		b = 0;
+	}
+	if (bufferRem + bits_len < 8) {
+		bufferBits += bits_len;
+	} else {
+		bufferPos++;
+		bufferBits += 8 - bufferRem;
+		bits_len -= 8 - bufferRem;
+		if (bufferBits == WP512_BLOCK_SIZE * 8) {
+			wp512_process_buffer(wctx);
+			bufferBits = bufferPos = 0;
+		}
+		buffer[bufferPos] = b << (8 - bufferRem);
+		bufferBits += (int)bits_len;
+	}
+
+	wctx->bufferBits   = bufferBits;
+	wctx->bufferPos    = bufferPos;
+
+}
+
+static void wp512_final(void *ctx, u8 *out)
+{
+	struct wp512_ctx *wctx = ctx;
+	int i;
+   	u8 *buffer      = wctx->buffer;
+   	u8 *bitLength   = wctx->bitLength;
+   	int bufferBits  = wctx->bufferBits;
+   	int bufferPos   = wctx->bufferPos;
+   	u8 *digest      = out;
+
+   	buffer[bufferPos] |= 0x80U >> (bufferBits & 7);
+   	bufferPos++;
+   	if (bufferPos > WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
+   		if (bufferPos < WP512_BLOCK_SIZE) {
+	   	memset(&buffer[bufferPos], 0, WP512_BLOCK_SIZE - bufferPos);
+   		}
+   		wp512_process_buffer(wctx);
+   		bufferPos = 0;
+   	}
+   	if (bufferPos < WP512_BLOCK_SIZE - WP512_LENGTHBYTES) {
+   		memset(&buffer[bufferPos], 0,
+			  (WP512_BLOCK_SIZE - WP512_LENGTHBYTES) - bufferPos);
+   	}
+   	bufferPos = WP512_BLOCK_SIZE - WP512_LENGTHBYTES;
+   	memcpy(&buffer[WP512_BLOCK_SIZE - WP512_LENGTHBYTES],
+		   bitLength, WP512_LENGTHBYTES);
+   	wp512_process_buffer(wctx);
+   	for (i = 0; i < WP512_DIGEST_SIZE/8; i++) {
+		digest[0] = (u8)(wctx->hash[i] >> 56);
+		digest[1] = (u8)(wctx->hash[i] >> 48);
+		digest[2] = (u8)(wctx->hash[i] >> 40);
+		digest[3] = (u8)(wctx->hash[i] >> 32);
+		digest[4] = (u8)(wctx->hash[i] >> 24);
+		digest[5] = (u8)(wctx->hash[i] >> 16);
+		digest[6] = (u8)(wctx->hash[i] >>  8);
+		digest[7] = (u8)(wctx->hash[i]      );
+		digest += 8;
+   	}
+   	wctx->bufferBits   = bufferBits;
+   	wctx->bufferPos    = bufferPos;
+}
+
+static void wp384_final(void *ctx, u8 *out)
+{
+	struct wp512_ctx *wctx = ctx;
+	u8 D[64];
+
+	wp512_final (wctx, D);
+	memcpy (out, D, WP384_DIGEST_SIZE);
+	memset (D, 0, WP512_DIGEST_SIZE);
+}
+
+static void wp256_final(void *ctx, u8 *out)
+{
+	struct wp512_ctx *wctx = ctx;
+	u8 D[64];
+
+	wp512_final (wctx, D);
+	memcpy (out, D, WP256_DIGEST_SIZE);
+	memset (D, 0, WP512_DIGEST_SIZE);
+}
+
+static struct crypto_alg wp512 = {
+	.cra_name	=	"wp512",
+	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	=	WP512_BLOCK_SIZE,
+	.cra_ctxsize	=	sizeof(struct wp512_ctx),
+	.cra_module	=	THIS_MODULE,
+	.cra_list       =       LIST_HEAD_INIT(wp512.cra_list),	
+	.cra_u		=	{ .digest = {
+	.dia_digestsize	=	WP512_DIGEST_SIZE,
+	.dia_init   	= 	wp512_init,
+	.dia_update 	=	wp512_update,
+	.dia_final  	=	wp512_final } }
+};
+
+static struct crypto_alg wp384 = {
+	.cra_name	=	"wp384",
+	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	=	WP512_BLOCK_SIZE,
+	.cra_ctxsize	=	sizeof(struct wp512_ctx),
+	.cra_module	=	THIS_MODULE,
+	.cra_list       =       LIST_HEAD_INIT(wp384.cra_list),	
+	.cra_u		=	{ .digest = {
+	.dia_digestsize	=	WP384_DIGEST_SIZE,
+	.dia_init   	= 	wp512_init,
+	.dia_update 	=	wp512_update,
+	.dia_final  	=	wp384_final } }
+};
+
+static struct crypto_alg wp256 = {
+	.cra_name	=	"wp256",
+	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	=	WP512_BLOCK_SIZE,
+	.cra_ctxsize	=	sizeof(struct wp512_ctx),
+	.cra_module	=	THIS_MODULE,
+	.cra_list       =       LIST_HEAD_INIT(wp256.cra_list),	
+	.cra_u		=	{ .digest = {
+	.dia_digestsize	=	WP256_DIGEST_SIZE,
+	.dia_init   	= 	wp512_init,
+	.dia_update 	=	wp512_update,
+	.dia_final  	=	wp256_final } }
+};
+
+static int __init init(void)
+{
+	int ret = 0;
+
+	ret = crypto_register_alg(&wp512);
+
+	if (ret < 0)
+		goto out;
+
+	ret = crypto_register_alg(&wp384);
+	if (ret < 0)
+	{
+		crypto_unregister_alg(&wp512);
+		goto out;
+	}
+
+	ret = crypto_register_alg(&wp256);
+	if (ret < 0)
+	{
+		crypto_unregister_alg(&wp512);
+		crypto_unregister_alg(&wp384);
+	}
+out:
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&wp512);
+	crypto_unregister_alg(&wp384);
+	crypto_unregister_alg(&wp256);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Whirlpool Message Digest Algorithm");
diff -urN linux-2.4.28-pre3/drivers/atm/atmtcp.c linux-2.4.28-pre4/drivers/atm/atmtcp.c
--- linux-2.4.28-pre3/drivers/atm/atmtcp.c	2003-11-28 10:26:19.000000000 -0800
+++ linux-2.4.28-pre4/drivers/atm/atmtcp.c	2004-10-08 06:28:25.026233940 -0700
@@ -246,7 +246,7 @@
 	dev_data = PRIV(atmtcp_dev);
 	dev_data->vcc = NULL;
 	if (dev_data->persist) return;
-	PRIV(atmtcp_dev) = NULL;
+	atmtcp_dev->dev_data = NULL;
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
@@ -362,7 +362,7 @@
 	}
 	dev->ci_range.vpi_bits = MAX_VPI_BITS;
 	dev->ci_range.vci_bits = MAX_VCI_BITS;
-	PRIV(dev) = dev_data;
+	dev->dev_data = dev_data;
 	PRIV(dev)->vcc = NULL;
 	PRIV(dev)->persist = persist;
 	if (result) *result = dev;
diff -urN linux-2.4.28-pre3/drivers/atm/fore200e.c linux-2.4.28-pre4/drivers/atm/fore200e.c
--- linux-2.4.28-pre3/drivers/atm/fore200e.c	2004-10-08 06:28:21.354084541 -0700
+++ linux-2.4.28-pre4/drivers/atm/fore200e.c	2004-10-08 06:28:25.066235567 -0700
@@ -1621,7 +1621,7 @@
     set_bit(ATM_VF_PARTIAL,&vcc->flags);
     set_bit(ATM_VF_ADDR, &vcc->flags);
 
-    FORE200E_VCC(vcc) = fore200e_vcc;
+    vcc->dev_data = fore200e_vcc;
 
     if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) {
 
@@ -1630,7 +1630,7 @@
 	clear_bit(ATM_VF_ADDR, &vcc->flags);
 	clear_bit(ATM_VF_PARTIAL,&vcc->flags);
 
-	FORE200E_VCC(vcc) = NULL;
+	vcc->dev_data = NULL;
 
 	fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
 
@@ -1692,7 +1692,7 @@
     vcc->itf = vcc->vci = vcc->vpi = 0;
 
     fore200e_vcc = FORE200E_VCC(vcc);
-    FORE200E_VCC(vcc) = NULL;
+    vcc->dev_data = NULL;
 
     spin_unlock_irqrestore(&fore200e->q_lock, flags);
 
@@ -2739,7 +2739,7 @@
 	return -ENODEV;
     }
 
-    FORE200E_DEV(atm_dev) = fore200e;
+    atm_dev->dev_data = fore200e;
     fore200e->atm_dev = atm_dev;
 
     atm_dev->ci_range.vpi_bits = FORE200E_VPI_BITS;
diff -urN linux-2.4.28-pre3/drivers/atm/he.c linux-2.4.28-pre4/drivers/atm/he.c
--- linux-2.4.28-pre3/drivers/atm/he.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.28-pre4/drivers/atm/he.c	2004-10-08 06:28:25.070235730 -0700
@@ -378,7 +378,7 @@
 	he_dev->pci_dev = pci_dev;
 	he_dev->atm_dev = atm_dev;
 	he_dev->atm_dev->dev_data = he_dev;
-	HE_DEV(atm_dev) = he_dev;
+	atm_dev->dev_data = he_dev;
 	he_dev->number = atm_dev->number;
 	if (he_start(atm_dev)) {
 		he_stop(he_dev);
@@ -2347,7 +2347,7 @@
 	init_waitqueue_head(&he_vcc->rx_waitq);
 	init_waitqueue_head(&he_vcc->tx_waitq);
 
-	HE_VCC(vcc) = he_vcc;
+	vcc->dev_data = he_vcc;
 
 	if (vcc->qos.txtp.traffic_class != ATM_NONE) {
 		int pcr_goal;
diff -urN linux-2.4.28-pre3/drivers/atm/idt77105.c linux-2.4.28-pre4/drivers/atm/idt77105.c
--- linux-2.4.28-pre3/drivers/atm/idt77105.c	2003-06-13 07:51:32.000000000 -0700
+++ linux-2.4.28-pre4/drivers/atm/idt77105.c	2004-10-08 06:28:25.085236340 -0700
@@ -267,7 +267,7 @@
 {
 	unsigned long flags;
 
-	if (!(PRIV(dev) = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
+	if (!(dev->phy_data = kmalloc(sizeof(struct idt77105_priv),GFP_KERNEL)))
 		return -ENOMEM;
 	PRIV(dev)->dev = dev;
 	spin_lock_irqsave(&idt77105_priv_lock, flags);
@@ -345,7 +345,7 @@
                 else
                     idt77105_all = walk->next;
 	        dev->phy = NULL;
-                PRIV(dev) = NULL;
+                dev->phy_data = NULL;
                 kfree(walk);
                 break;
             }
diff -urN linux-2.4.28-pre3/drivers/atm/iphase.c linux-2.4.28-pre4/drivers/atm/iphase.c
--- linux-2.4.28-pre3/drivers/atm/iphase.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.28-pre4/drivers/atm/iphase.c	2004-10-08 06:28:25.104237113 -0700
@@ -1782,7 +1782,7 @@
                          (iadev->tx_buf_sz - sizeof(struct cpcs_trailer))){
            printk("IA:  SDU size over (%d) the configured SDU size %d\n",
 		  vcc->qos.txtp.max_sdu,iadev->tx_buf_sz);
-	   INPH_IA_VCC(vcc) = NULL;  
+	   vcc->dev_data = NULL;  
            kfree(ia_vcc);
            return -EINVAL; 
         }
@@ -2707,7 +2707,7 @@
         }
 	kfree(INPH_IA_VCC(vcc));  
         ia_vcc = NULL;
-        INPH_IA_VCC(vcc) = NULL;  
+        vcc->dev_data = NULL;  
         clear_bit(ATM_VF_ADDR,&vcc->flags);
         return;        
 }  
@@ -2720,7 +2720,7 @@
 	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))  
 	{  
 		IF_EVENT(printk("ia: not partially allocated resources\n");)  
-		INPH_IA_VCC(vcc) = NULL;  
+		vcc->dev_data = NULL;  
 	}  
 	iadev = INPH_IA_DEV(vcc->dev);  
 	error = atm_find_ci(vcc, &vpi, &vci);  
@@ -2744,7 +2744,7 @@
 	/* Device dependent initialization */  
 	ia_vcc = kmalloc(sizeof(*ia_vcc), GFP_KERNEL);  
 	if (!ia_vcc) return -ENOMEM;  
-	INPH_IA_VCC(vcc) = ia_vcc;  
+	vcc->dev_data = ia_vcc;  
   
 	if ((error = open_rx(vcc)))  
 	{  
@@ -3256,7 +3256,7 @@
 		ret = -ENOMEM;
 		goto err_out_disable_dev;
 	}
-	INPH_IA_DEV(dev) = iadev; 
+	dev->dev_data = iadev; 
 	IF_INIT(printk(DEV_LABEL "registered at (itf :%d)\n", dev->number);)
 	IF_INIT(printk("dev_id = 0x%x iadev->LineRate = %d \n", (u32)dev,
 		iadev->LineRate);)
diff -urN linux-2.4.28-pre3/drivers/atm/uPD98402.c linux-2.4.28-pre4/drivers/atm/uPD98402.c
--- linux-2.4.28-pre3/drivers/atm/uPD98402.c	2001-09-13 15:21:32.000000000 -0700
+++ linux-2.4.28-pre4/drivers/atm/uPD98402.c	2004-10-08 06:28:25.122237845 -0700
@@ -212,7 +212,7 @@
 static int uPD98402_start(struct atm_dev *dev)
 {
 	DPRINTK("phy_start\n");
-	if (!(PRIV(dev) = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
+	if (!(dev->phy_data = kmalloc(sizeof(struct uPD98402_priv),GFP_KERNEL)))
 		return -ENOMEM;
 	memset(&PRIV(dev)->sonet_stats,0,sizeof(struct k_sonet_stats));
 	(void) GET(PCR); /* clear performance events */
diff -urN linux-2.4.28-pre3/drivers/atm/zatm.c linux-2.4.28-pre4/drivers/atm/zatm.c
--- linux-2.4.28-pre3/drivers/atm/zatm.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.28-pre4/drivers/atm/zatm.c	2004-10-08 06:28:25.124237927 -0700
@@ -1565,7 +1565,7 @@
         DPRINTK("zatm_close: done waiting\n");
         /* deallocate memory */
         kfree(ZATM_VCC(vcc));
-        ZATM_VCC(vcc) = NULL;
+	vcc->dev_data = NULL;
 	clear_bit(ATM_VF_ADDR,&vcc->flags);
 }
 
@@ -1578,7 +1578,7 @@
 
 	DPRINTK(">zatm_open\n");
 	zatm_dev = ZATM_DEV(vcc->dev);
-	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) ZATM_VCC(vcc) = NULL;
+	if (!test_bit(ATM_VF_PARTIAL,&vcc->flags)) vcc->dev_data = NULL;
 	error = atm_find_ci(vcc,&vpi,&vci);
 	if (error) return error;
 	vcc->vpi = vpi;
@@ -1594,7 +1594,7 @@
 			clear_bit(ATM_VF_ADDR,&vcc->flags);
 			return -ENOMEM;
 		}
-		ZATM_VCC(vcc) = zatm_vcc;
+		vcc->dev_data = zatm_vcc;
 		ZATM_VCC(vcc)->tx_chan = 0; /* for zatm_close after open_rx */
 		if ((error = open_rx_first(vcc))) {
 	                zatm_close(vcc);
@@ -1828,7 +1828,7 @@
 			dev = atm_dev_register(DEV_LABEL,&ops,-1,NULL);
 			if (!dev) break;
 			zatm_dev->pci_dev = pci_dev;
-			ZATM_DEV(dev) = zatm_dev;
+			dev->dev_data = zatm_dev;
 			zatm_dev->copper = type;
 			if (zatm_init(dev) || zatm_start(dev)) {
 				atm_dev_deregister(dev);
diff -urN linux-2.4.28-pre3/drivers/block/cciss.c linux-2.4.28-pre4/drivers/block/cciss.c
--- linux-2.4.28-pre3/drivers/block/cciss.c	2004-10-08 06:28:21.357084663 -0700
+++ linux-2.4.28-pre4/drivers/block/cciss.c	2004-10-08 06:28:25.126238008 -0700
@@ -535,7 +535,7 @@
 static int cciss_ioctl32_big_passthru(unsigned int fd, unsigned cmd, unsigned long arg, 
 	struct file *file);
 
-typedef long (*handler type) (unsigned int, unsigned int, unsigned long,
+typedef long (*handler_type) (unsigned int, unsigned int, unsigned long,
 				struct file *);
 
 static struct ioctl32_map {
diff -urN linux-2.4.28-pre3/drivers/block/genhd.c linux-2.4.28-pre4/drivers/block/genhd.c
--- linux-2.4.28-pre3/drivers/block/genhd.c	2004-02-18 05:36:31.000000000 -0800
+++ linux-2.4.28-pre4/drivers/block/genhd.c	2004-10-08 06:28:25.130238171 -0700
@@ -49,8 +49,9 @@
 add_gendisk(struct gendisk *gp)
 {
 	struct gendisk *sgp;
+	unsigned long flags;
 
-	write_lock(&gendisk_lock);
+	write_lock_irqsave(&gendisk_lock, flags);
 
 	/*
  	 *	In 2.5 this will go away. Fix the drivers who rely on
@@ -70,7 +71,7 @@
 	gp->next = gendisk_head;
 	gendisk_head = gp;
 out:
-	write_unlock(&gendisk_lock);
+	write_unlock_irqrestore(&gendisk_lock, flags);
 }
 
 EXPORT_SYMBOL(add_gendisk);
@@ -87,15 +88,16 @@
 del_gendisk(struct gendisk *gp)
 {
 	struct gendisk **gpp;
+	unsigned long flags;
 
-	write_lock(&gendisk_lock);
+	write_lock_irqsave(&gendisk_lock, flags);
 	gendisk_array[gp->major] = NULL;
 	for (gpp = &gendisk_head; *gpp; gpp = &((*gpp)->next))
 		if (*gpp == gp)
 			break;
 	if (*gpp)
 		*gpp = (*gpp)->next;
-	write_unlock(&gendisk_lock);
+	write_unlock_irqrestore(&gendisk_lock, flags);
 }
 
 EXPORT_SYMBOL(del_gendisk);
@@ -113,8 +115,9 @@
 {
 	struct gendisk *gp = NULL;
 	int maj = MAJOR(dev);
+	unsigned long flags;
 
-	read_lock(&gendisk_lock);
+	read_lock_irqsave(&gendisk_lock, flags);
 	if ((gp = gendisk_array[maj]))
 		goto out;
 
@@ -123,7 +126,7 @@
 		if (gp->major == maj)
 			break;
 out:
-	read_unlock(&gendisk_lock);
+	read_unlock_irqrestore(&gendisk_lock, flags);
 	return gp;
 }
 
@@ -143,12 +146,13 @@
 {
 	struct gendisk *gp;
 	int error = 0;
+	unsigned long flags;
 
-	read_lock(&gendisk_lock);
+	read_lock_irqsave(&gendisk_lock, flags);
 	for (gp = gendisk_head; gp; gp = gp->next)
 		if ((error = walk(gp, data)))
 			break;
-	read_unlock(&gendisk_lock);
+	read_unlock_irqrestore(&gendisk_lock, flags);
 
 	return error;
 }
@@ -160,7 +164,7 @@
 	struct gendisk *gp;
 	loff_t pos = *ppos;
 
-	read_lock(&gendisk_lock);
+	read_lock_irq(&gendisk_lock);
 	for (gp = gendisk_head; gp; gp = gp->next)
 		if (!pos--)
 			return gp;
@@ -175,7 +179,7 @@
 
 static void part_stop(struct seq_file *s, void *v)
 {
-	read_unlock(&gendisk_lock);
+	read_unlock_irq(&gendisk_lock);
 }
 
 static int part_show(struct seq_file *s, void *v)
diff -urN linux-2.4.28-pre3/drivers/hotplug/Makefile linux-2.4.28-pre4/drivers/hotplug/Makefile
--- linux-2.4.28-pre3/drivers/hotplug/Makefile	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.28-pre4/drivers/hotplug/Makefile	2004-10-08 06:28:25.182240287 -0700
@@ -20,7 +20,6 @@
 
 cpqphp-objs		:=	cpqphp_core.o	\
 				cpqphp_ctrl.o	\
-				cpqphp_proc.o	\
 				cpqphp_pci.o
 
 ibmphp-objs		:=	ibmphp_core.o	\
@@ -64,6 +63,10 @@
 	cpqphp-objs += cpqphp_nvram.o
 endif
 
+ifeq ($(CONFIG_PROC_FS),y)
+	cpqphp-objs += cpqphp_proc.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 pci_hotplug.o: $(pci_hotplug-objs)
diff -urN linux-2.4.28-pre3/drivers/hotplug/ibmphp_hpc.c linux-2.4.28-pre4/drivers/hotplug/ibmphp_hpc.c
--- linux-2.4.28-pre3/drivers/hotplug/ibmphp_hpc.c	2003-11-28 10:26:20.000000000 -0800
+++ linux-2.4.28-pre4/drivers/hotplug/ibmphp_hpc.c	2004-10-08 06:28:25.185240409 -0700
@@ -184,14 +184,14 @@
 	}
 
 	wpg_data = swab32 (data);	// swap data before writing
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET;
+	wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
 	writel (wpg_data, wpg_addr);
 
 	//--------------------------------------------------------------------
 	// READ - step 2 : clear the message buffer
 	data = 0x00000000;
 	wpg_data = swab32 (data);
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET;
+	wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
 	writel (wpg_data, wpg_addr);
 
 	//--------------------------------------------------------------------
@@ -199,7 +199,7 @@
 	//                 2020 : [20] OR operation at [20] offset 0x20
 	data = WPG_I2CMCNTL_STARTOP_MASK;
 	wpg_data = swab32 (data);
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR;
+	wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR;
 	writel (wpg_data, wpg_addr);
 
 	//--------------------------------------------------------------------
@@ -207,7 +207,7 @@
 	i = CMD_COMPLETE_TOUT_SEC;
 	while (i) {
 		long_delay (1 * HZ / 100);
-		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET;
+		wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET;
 		wpg_data = readl (wpg_addr);
 		data = swab32 (wpg_data);
 		if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
@@ -223,7 +223,7 @@
 	i = CMD_COMPLETE_TOUT_SEC;
 	while (i) {
 		long_delay (1 * HZ / 100);
-		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET;
+		wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET;
 		wpg_data = readl (wpg_addr);
 		data = swab32 (wpg_data);
 		if (HPC_I2CSTATUS_CHECK (data))
@@ -237,7 +237,7 @@
 
 	//--------------------------------------------------------------------
 	// READ - step 6 : get DATA
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET;
+	wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
 	wpg_data = readl (wpg_addr);
 	data = swab32 (wpg_data);
 
@@ -295,14 +295,14 @@
 	}
 
 	wpg_data = swab32 (data);	// swap data before writing
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET;
+	wpg_addr = WPGBbar + WPG_I2CMOSUP_OFFSET;
 	writel (wpg_data, wpg_addr);
 
 	//--------------------------------------------------------------------
 	// WRITE - step 2 : clear the message buffer
 	data = 0x00000000 | (ulong) cmd;
 	wpg_data = swab32 (data);
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET;
+	wpg_addr = WPGBbar + WPG_I2CMBUFL_OFFSET;
 	writel (wpg_data, wpg_addr);
 
 	//--------------------------------------------------------------------
@@ -310,7 +310,7 @@
 	//                 2020 : [20] OR operation at [20] offset 0x20
 	data = WPG_I2CMCNTL_STARTOP_MASK;
 	wpg_data = swab32 (data);
-	(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR;
+	wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET + WPG_I2C_OR;
 	writel (wpg_data, wpg_addr);
 
 	//--------------------------------------------------------------------
@@ -318,7 +318,7 @@
 	i = CMD_COMPLETE_TOUT_SEC;
 	while (i) {
 		long_delay (1 * HZ / 100);
-		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET;
+		wpg_addr = WPGBbar + WPG_I2CMCNTL_OFFSET;
 		wpg_data = readl (wpg_addr);
 		data = swab32 (wpg_data);
 		if (!(data & WPG_I2CMCNTL_STARTOP_MASK))
@@ -335,7 +335,7 @@
 	i = CMD_COMPLETE_TOUT_SEC;
 	while (i) {
 		long_delay (1 * HZ / 100);
-		(ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET;
+		wpg_addr = WPGBbar + WPG_I2CSTAT_OFFSET;
 		wpg_data = readl (wpg_addr);
 		data = swab32 (wpg_data);
 		if (HPC_I2CSTATUS_CHECK (data))
diff -urN linux-2.4.28-pre3/drivers/isdn/eicon/eicon_idi.c linux-2.4.28-pre4/drivers/isdn/eicon/eicon_idi.c
--- linux-2.4.28-pre3/drivers/isdn/eicon/eicon_idi.c	2001-12-21 09:41:54.000000000 -0800
+++ linux-2.4.28-pre4/drivers/isdn/eicon/eicon_idi.c	2004-10-08 06:28:25.238242565 -0700
@@ -2054,7 +2054,8 @@
 				OutBuf.Len++;
 			} else {
 				*OutBuf.Next++ = 0;
-				*((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
+				*(__u16 *) OutBuf.Next = (__u16) LineBuf.Len;
+				OutBuf.Next += sizeof(__u16);
 				OutBuf.Len += 3;
 			}
 			memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
diff -urN linux-2.4.28-pre3/drivers/isdn/hisax/avm_pci.c linux-2.4.28-pre4/drivers/isdn/hisax/avm_pci.c
--- linux-2.4.28-pre3/drivers/isdn/hisax/avm_pci.c	2002-11-28 15:53:13.000000000 -0800
+++ linux-2.4.28-pre4/drivers/isdn/hisax/avm_pci.c	2004-10-08 06:28:25.239242606 -0700
@@ -291,7 +291,8 @@
 			debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
 		return;
 	}
-	ptr = (u_int *) p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
+	p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
+	ptr = (u_int *)p;
 	bcs->hw.hdlc.rcvidx += count;
 	if (cs->subtyp == AVM_FRITZ_PCI) {
 		outl(idx, cs->hw.avm.cfg_reg + 4);
@@ -352,7 +353,8 @@
 	}
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
 		debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
-	ptr = (u_int *) p = bcs->tx_skb->data;
+	p = bcs->tx_skb->data;
+	ptr = (u_int *)p;
 	skb_pull(bcs->tx_skb, count);
 	bcs->tx_cnt -= count;
 	bcs->hw.hdlc.count += count;
diff -urN linux-2.4.28-pre3/drivers/isdn/hisax/hfc_pci.c linux-2.4.28-pre4/drivers/isdn/hisax/hfc_pci.c
--- linux-2.4.28-pre3/drivers/isdn/hisax/hfc_pci.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.28-pre4/drivers/isdn/hisax/hfc_pci.c	2004-10-08 06:28:25.242242728 -0700
@@ -1746,7 +1746,7 @@
 			printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
 			return 0;
 		}
-		(ulong) cs->hw.hfcpci.fifos =
+		cs->hw.hfcpci.fifos = (void *)
 		    (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
 		pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
 				       cs->hw.hfcpci.pci_device_fn, 0x80,
diff -urN linux-2.4.28-pre3/drivers/isdn/hysdn/hysdn_proclog.c linux-2.4.28-pre4/drivers/isdn/hysdn/hysdn_proclog.c
--- linux-2.4.28-pre3/drivers/isdn/hysdn/hysdn_proclog.c	2004-08-07 16:26:04.000000000 -0700
+++ linux-2.4.28-pre4/drivers/isdn/hysdn/hysdn_proclog.c	2004-10-08 06:28:25.245242850 -0700
@@ -235,7 +235,7 @@
 		return (0);
 
 	inf->usage_cnt--;	/* new usage count */
-	(struct log_data **) file->private_data = &inf->next;	/* next structure */
+	file->private_data = &inf->next;	/* next structure */
 	if ((len = strlen(inf->log_start)) <= count) {
 		if (copy_to_user(buf, inf->log_start, len))
 			return -EFAULT;
@@ -278,9 +278,9 @@
 		cli();
 		pd->if_used++;
 		if (pd->log_head)
-			(struct log_data **) filep->private_data = &(pd->log_tail->next);
+			filep->private_data = &(pd->log_tail->next);
 		else
-			(struct log_data **) filep->private_data = &(pd->log_head);
+			filep->private_data = &(pd->log_head);
 		restore_flags(flags);
 	} else {		/* simultaneous read/write access forbidden ! */
 		unlock_kernel();
diff -urN linux-2.4.28-pre3/drivers/md/raid1.c linux-2.4.28-pre4/drivers/md/raid1.c
--- linux-2.4.28-pre3/drivers/md/raid1.c	2004-04-14 06:05:30.000000000 -0700
+++ linux-2.4.28-pre4/drivers/md/raid1.c	2004-10-08 06:28:25.255243257 -0700
@@ -325,18 +325,22 @@
 {
 	raid1_conf_t *conf = mddev_to_conf(mddev);
 	int i, disks = MD_SB_DISKS;
+	unsigned long flags;
 
 	/*
 	 * Later we do read balancing on the read side 
 	 * now we use the first available disk.
 	 */
 
+	md_spin_lock_irqsave(&conf->device_lock, flags);
 	for (i = 0; i < disks; i++) {
 		if (conf->mirrors[i].operational) {
 			*rdev = conf->mirrors[i].dev;
+			md_spin_unlock_irqrestore(&conf->device_lock, flags);
 			return (0);
 		}
 	}
+	md_spin_unlock_irqrestore(&conf->device_lock, flags);
 
 	printk (KERN_ERR "raid1_map(): huh, no more operational devices?\n");
 	return (-1);
@@ -592,6 +596,7 @@
 	int disks = MD_SB_DISKS;
 	int i, sum_bhs = 0;
 	struct mirror_info *mirror;
+	kdev_t dev;
 
 	if (!buffer_locked(bh))
 		BUG();
@@ -635,13 +640,16 @@
 		/*
 		 * read balancing logic:
 		 */
+		spin_lock_irq(&conf->device_lock);
 		mirror = conf->mirrors + raid1_read_balance(conf, bh);
+		dev = mirror->dev;
+		spin_unlock_irq(&conf->device_lock);
 
 		bh_req = &r1_bh->bh_req;
 		memcpy(bh_req, bh, sizeof(*bh));
 		bh_req->b_blocknr = bh->b_rsector;
-		bh_req->b_dev = mirror->dev;
-		bh_req->b_rdev = mirror->dev;
+		bh_req->b_dev = dev;
+		bh_req->b_rdev = dev;
 	/*	bh_req->b_rsector = bh->n_rsector; */
 		bh_req->b_end_io = raid1_end_request;
 		bh_req->b_private = r1_bh;
@@ -654,6 +662,7 @@
 	 */
 
 	bhl = raid1_alloc_bh(conf, conf->raid_disks);
+	spin_lock_irq(&conf->device_lock);
 	for (i = 0; i < disks; i++) {
 		struct buffer_head *mbh;
 		if (!conf->mirrors[i].operational) 
@@ -702,6 +711,7 @@
 		r1_bh->mirror_bh_list = mbh;
 		sum_bhs++;
 	}
+	spin_unlock_irq(&conf->device_lock);
 	if (bhl) raid1_free_bh(conf,bhl);
 	if (!sum_bhs) {
 		/* Gag - all mirrors non-operational.. */
@@ -771,6 +781,8 @@
 	mark_disk_inactive(sb->disks+mirror->number);
 	if (!mirror->write_only)
 		sb->active_disks--;
+	else
+		sb->spare_disks--;
 	sb->working_disks--;
 	sb->failed_disks++;
 	mddev->sb_dirty = 1;
@@ -787,6 +799,7 @@
 	struct mirror_info * mirrors = conf->mirrors;
 	int disks = MD_SB_DISKS;
 	int i;
+	unsigned long flags;
 
 	/* Find the drive.
 	 * If it is not operational, then we have already marked it as dead
@@ -808,7 +821,9 @@
 
 		return 1;
 	}
+	md_spin_lock_irqsave(&conf->device_lock, flags);
 	mark_disk_bad(mddev, i);
+	md_spin_unlock_irqrestore(&conf->device_lock, flags);
 	return 0;
 }
 
@@ -876,7 +891,6 @@
 	mdp_disk_t *failed_desc, *spare_desc, *added_desc;
 	mdk_rdev_t *spare_rdev, *failed_rdev;
 
-	print_raid1_conf(conf);
 
 	switch (state) {
 	case DISKOP_SPARE_ACTIVE:
@@ -887,6 +901,10 @@
 
 	md_spin_lock_irq(&conf->device_lock);
 	/*
+	 * Need the conf lock when printing out state else we get BUG()s
+	 */
+	print_raid1_conf(conf);
+	/*
 	 * find the disk ...
 	 */
 	switch (state) {
@@ -1136,12 +1154,12 @@
 		goto abort;
 	}
 abort:
+	print_raid1_conf(conf);
 	md_spin_unlock_irq(&conf->device_lock);
 	if (state == DISKOP_SPARE_ACTIVE || state == DISKOP_SPARE_INACTIVE)
 		/* should move to "END_REBUILD" when such exists */
 		raid1_shrink_buffers(conf);
 
-	print_raid1_conf(conf);
 	return err;
 }
 
@@ -1196,6 +1214,7 @@
 				
 				conf = mddev_to_conf(mddev);
 				bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */
+				spin_lock_irq(&conf->device_lock);
 				for (i = 0; i < disks ; i++) {
 					if (!conf->mirrors[i].operational)
 						continue;
@@ -1238,6 +1257,7 @@
 
 					sum_bhs++;
 				}
+				spin_unlock_irq(&conf->device_lock);
 				md_atomic_set(&r1_bh->remaining, sum_bhs);
 				if (bhl) raid1_free_bh(conf, bhl);
 				mbh = r1_bh->mirror_bh_list;
@@ -1373,6 +1393,7 @@
 	int disk;
 	int block_nr;
 	int buffs;
+	kdev_t dev;
 
 	if (!sector_nr) {
 		/* we want enough buffers to hold twice the window of 128*/
@@ -1426,6 +1447,7 @@
 	 * could dedicate one to rebuild and others to
 	 * service read requests ..
 	 */
+	spin_lock_irq(&conf->device_lock);
 	disk = conf->last_used;
 	/* make sure disk is operational */
 	while (!conf->mirrors[disk].operational) {
@@ -1437,6 +1459,8 @@
 	conf->last_used = disk;
 	
 	mirror = conf->mirrors+conf->last_used;
+	dev = mirror->dev;
+	spin_unlock_irq(&conf->device_lock);
 	
 	r1_bh = raid1_alloc_buf (conf);
 	r1_bh->master_bh = NULL;
@@ -1453,8 +1477,8 @@
 	}
 	bh->b_size = bsize;
 	bh->b_list = BUF_LOCKED;
-	bh->b_dev = mirror->dev;
-	bh->b_rdev = mirror->dev;
+	bh->b_dev = dev;
+	bh->b_rdev = dev;
 	bh->b_state = (1<<BH_Req) | (1<<BH_Mapped) | (1<<BH_Lock);
 	if (!bh->b_page)
 		BUG();
diff -urN linux-2.4.28-pre3/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.4.28-pre4/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.4.28-pre3/drivers/mtd/chips/cfi_cmdset_0001.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.28-pre4/drivers/mtd/chips/cfi_cmdset_0001.c	2004-10-08 06:28:25.302245169 -0700
@@ -1201,13 +1201,17 @@
 	/* Write data */
 	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
 		if (cfi_buswidth_is_1()) {
-			map->write8 (map, *((__u8*)buf)++, adr+z);
+			map->write8 (map, *(__u8*)buf, adr+z);
+			buf += sizeof(__u8);
 		} else if (cfi_buswidth_is_2()) {
-			map->write16 (map, *((__u16*)buf)++, adr+z);
+			map->write16 (map, *(__u16*)buf, adr+z);
+			buf += sizeof(__u16);
 		} else if (cfi_buswidth_is_4()) {
-			map->write32 (map, *((__u32*)buf)++, adr+z);
+			map->write32 (map, *(__u32*)buf, adr+z);
+			buf += sizeof(__u32);
 		} else if (cfi_buswidth_is_8()) {
-			map->write64 (map, *((__u64*)buf)++, adr+z);
+			map->write64 (map, *(__u64*)buf, adr+z);
+			buf += sizeof(__u64);
 		} else {
 			DISABLE_VPP(map);
 			ret = -EINVAL;
diff -urN linux-2.4.28-pre3/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.4.28-pre4/drivers/mtd/chips/cfi_cmdset_0020.c
--- linux-2.4.28-pre3/drivers/mtd/chips/cfi_cmdset_0020.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.28-pre4/drivers/mtd/chips/cfi_cmdset_0020.c	2004-10-08 06:28:25.305245291 -0700
@@ -540,11 +540,14 @@
 	/* Write data */
 	for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
 		if (cfi_buswidth_is_1()) {
-			map->write8 (map, *((__u8*)buf)++, adr+z);
+			map->write8 (map, *(__u8*)buf, adr+z);
+			buf += sizeof(__u8);
 		} else if (cfi_buswidth_is_2()) {
-			map->write16 (map, *((__u16*)buf)++, adr+z);
+			map->write16 (map, *(__u16*)buf, adr+z);
+			buf += sizeof(__u16);
 		} else if (cfi_buswidth_is_4()) {
-			map->write32 (map, *((__u32*)buf)++, adr+z);
+			map->write32 (map, *(__u32*)buf, adr+z);
+			buf += sizeof(__u32);
 		} else {
 			DISABLE_VPP(map);
 			return -EINVAL;
diff -urN linux-2.4.28-pre3/drivers/mtd/maps/elan-104nc.c linux-2.4.28-pre4/drivers/mtd/maps/elan-104nc.c
--- linux-2.4.28-pre3/drivers/mtd/maps/elan-104nc.c	2002-08-02 17:39:44.000000000 -0700
+++ linux-2.4.28-pre4/drivers/mtd/maps/elan-104nc.c	2004-10-08 06:28:25.307245372 -0700
@@ -147,7 +147,7 @@
 		elan_104nc_page(map, from);
 		memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
 		spin_unlock(&elan_104nc_spin);
-		(__u8*)to += thislen;
+		to += thislen;
 		from += thislen;
 		len -= thislen;
 	}
diff -urN linux-2.4.28-pre3/drivers/mtd/maps/sbc_gxx.c linux-2.4.28-pre4/drivers/mtd/maps/sbc_gxx.c
--- linux-2.4.28-pre3/drivers/mtd/maps/sbc_gxx.c	2003-06-13 07:51:34.000000000 -0700
+++ linux-2.4.28-pre4/drivers/mtd/maps/sbc_gxx.c	2004-10-08 06:28:25.307245372 -0700
@@ -155,7 +155,7 @@
 		sbc_gxx_page(map, from);
 		memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
 		spin_unlock(&sbc_gxx_spin);
-		(__u8*)to += thislen;
+		to += thislen;
 		from += thislen;
 		len -= thislen;
 	}
diff -urN linux-2.4.28-pre3/drivers/net/e100/e100.h linux-2.4.28-pre4/drivers/net/e100/e100.h
--- linux-2.4.28-pre3/drivers/net/e100/e100.h	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/e100/e100.h	2004-10-08 06:28:25.312245576 -0700
@@ -501,7 +501,7 @@
 	u8 scb_fc_thld;	/* Flow Control threshold */
 	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
 	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
-} d101_scb_ext __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) d101_scb_ext;
 
 /* Changed for 82559 enhancement */
 typedef struct _d101m_scb_ext_t {
@@ -517,7 +517,7 @@
 	u32 scb_function_event_mask;	/* Cardbus Function Mask */
 	u32 scb_function_present_state;	/* Cardbus Function state */
 	u32 scb_force_event;	/* Cardbus Force Event */
-} d101m_scb_ext __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) d101m_scb_ext;
 
 /* Changed for 82550 enhancement */
 typedef struct _d102_scb_ext_t {
@@ -536,7 +536,7 @@
 	u32 scb_function_event_mask;	/* Cardbus Function Mask */
 	u32 scb_function_present_state;	/* Cardbus Function state */
 	u32 scb_force_event;	/* Cardbus Force Event */
-} d102_scb_ext __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) d102_scb_ext;
 
 /*
  * 82557 status control block. this will be memory mapped & will hang of the
@@ -558,7 +558,7 @@
 		d101m_scb_ext d101m_scb;	/* 82559 specific fields */
 		d102_scb_ext d102_scb;
 	} scb_ext;
-} scb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) scb_t;
 
 /* Self test
  * This is used to dump results of the self test 
@@ -566,7 +566,7 @@
 typedef struct _self_test_t {
 	u32 st_sign;	/* Self Test Signature */
 	u32 st_result;	/* Self Test Results */
-} self_test_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) self_test_t;
 
 /* 
  *  Statistical Counters 
@@ -649,39 +649,39 @@
 	u16 cb_status;	/* Command Block Status */
 	u16 cb_cmd;	/* Command Block Command */
 	u32 cb_lnk_ptr;	/* Link To Next CB */
-} cb_header_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) cb_header_t;
 
 //* Individual Address Command Block (IA_CB)*/
 typedef struct _ia_cb_t {
 	cb_header_t ia_cb_hdr;
 	u8 ia_addr[ETH_ALEN];
-} ia_cb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) ia_cb_t;
 
 /* Configure Command Block (CONFIG_CB)*/
 typedef struct _config_cb_t {
 	cb_header_t cfg_cbhdr;
 	u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
-} config_cb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) config_cb_t;
 
 /* MultiCast Command Block (MULTICAST_CB)*/
 typedef struct _multicast_cb_t {
 	cb_header_t mc_cbhdr;
 	u16 mc_count;	/* Number of multicast addresses */
 	u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)];
-} mltcst_cb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) mltcst_cb_t;
 
 #define UCODE_MAX_DWORDS	134
 /* Load Microcode Command Block (LOAD_UCODE_CB)*/
 typedef struct _load_ucode_cb_t {
 	cb_header_t load_ucode_cbhdr;
 	u32 ucode_dword[UCODE_MAX_DWORDS];
-} load_ucode_cb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) load_ucode_cb_t;
 
 /* Load Programmable Filter Data*/
 typedef struct _filter_cb_t {
 	cb_header_t filter_cb_hdr;
 	u32 filter_data[MAX_FILTER];
-} filter_cb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) filter_cb_t;
 
 /* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block 
  */
@@ -693,7 +693,7 @@
 		mltcst_cb_t multicast;
 		filter_cb_t filter;
 	} ntcb;
-} nxmit_cb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) nxmit_cb_t;
 
 /*Block for queuing for postponed execution of the non-transmit commands*/
 typedef struct _nxmit_cb_entry_t {
@@ -724,7 +724,7 @@
 	u32 tbd_buf_addr;	/* Physical Transmit Buffer Address */
 	u16 tbd_buf_cnt;	/* Actual Count Of Bytes */
 	u16 padd;
-} tbd_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) tbd_t;
 
 /* d102 specific fields */
 typedef struct _tcb_ipcb_t {
@@ -743,7 +743,7 @@
 		u16 tbd_zero_size;
 	} tbd_sec_size;
 	u16 total_tcp_payload;
-} tcb_ipcb_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) tcb_ipcb_t;
 
 #define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS)
 
@@ -806,7 +806,7 @@
 	u32 rbd_rcb_addr;	/* Receive Buffer Address */
 	u16 rbd_sz;	/* Receive Buffer Size */
 	u16 rbd_filler1;
-} rbd_t __attribute__ ((__packed__));
+} __attribute__ ((__packed__)) rbd_t;
 
 /*
  * This structure is used to maintain a FIFO access to a resource that is 
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000.h linux-2.4.28-pre4/drivers/net/e1000/e1000.h
--- linux-2.4.28-pre3/drivers/net/e1000/e1000.h	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000.h	2004-10-08 06:28:25.316245738 -0700
@@ -49,6 +49,7 @@
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/pagemap.h>
@@ -78,6 +79,8 @@
 #define PCI_DMA_64BIT	0xffffffffffffffffULL
 #define PCI_DMA_32BIT	0x00000000ffffffffULL
 
+#define INTEL_E1000_ETHERNET_DEVICE(device_id) {\
+	PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
 
 struct e1000_adapter;
 
@@ -99,11 +102,12 @@
 
 #define E1000_MAX_INTR 10
 
-/* How many descriptors for TX and RX ? */
+/* TX/RX descriptor defines */
 #define E1000_DEFAULT_TXD                  256
 #define E1000_MAX_TXD                      256
 #define E1000_MIN_TXD                       80
 #define E1000_MAX_82544_TXD               4096
+
 #define E1000_DEFAULT_RXD                  256
 #define E1000_MAX_RXD                      256
 #define E1000_MIN_RXD                       80
@@ -124,14 +128,11 @@
 #define E1000_TX_HEAD_ADDR_SHIFT 7
 #define E1000_PBA_TX_MASK 0xFFFF0000
 
-/* Flow Control High-Watermark: 5688 bytes below Rx FIFO size */
-#define E1000_FC_HIGH_DIFF 0x1638
-
-/* Flow Control Low-Watermark: 5696 bytes below Rx FIFO size */
-#define E1000_FC_LOW_DIFF 0x1640
+/* Flow Control Watermarks */
+#define E1000_FC_HIGH_DIFF 0x1638  /* High: 5688 bytes below Rx FIFO size */
+#define E1000_FC_LOW_DIFF 0x1640   /* Low:  5696 bytes below Rx FIFO size */
 
-/* Flow Control Pause Time: 858 usec */
-#define E1000_FC_PAUSE_TIME 0x0680
+#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
 #define E1000_TX_QUEUE_WAKE	16
@@ -154,9 +155,9 @@
 struct e1000_buffer {
 	struct sk_buff *skb;
 	uint64_t dma;
-	unsigned long length;
 	unsigned long time_stamp;
-	unsigned int next_to_watch;
+	uint16_t length;
+	uint16_t next_to_watch;
 };
 
 struct e1000_desc_ring {
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000_ethtool.c linux-2.4.28-pre4/drivers/net/e1000/e1000_ethtool.c
--- linux-2.4.28-pre3/drivers/net/e1000/e1000_ethtool.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000_ethtool.c	2004-10-08 06:28:25.318245820 -0700
@@ -88,13 +88,13 @@
 	{ "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
 	{ "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
 	{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
+	{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
 	{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
-        { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
-	{ "rx_long_byte_count", E1000_STAT(stats.gorcl) }
+	{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
 };
 #define E1000_STATS_LEN	\
 	sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
-static char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
+static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register test  (offline)", "Eeprom test    (offline)",
 	"Interrupt test (offline)", "Loopback test  (offline)",
 	"Link test   (on/offline)"
@@ -170,7 +170,8 @@
 		ecmd->duplex = -1;
 	}
 
-	ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+	ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) ||
+			 hw->autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
 	return 0;
 }
 
@@ -192,6 +193,7 @@
 
 	if(netif_running(adapter->netdev)) {
 		e1000_down(adapter);
+		e1000_reset(adapter);
 		e1000_up(adapter);
 	} else
 		e1000_reset(adapter);
@@ -199,12 +201,13 @@
 	return 0;
 }
 
-static void 
+static void
 e1000_get_pauseparam(struct net_device *netdev,
-                    struct ethtool_pauseparam *pause)
+                     struct ethtool_pauseparam *pause)
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	struct e1000_hw *hw = &adapter->hw;
+
 	pause->autoneg = 
 		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
 	
@@ -218,9 +221,9 @@
 	}
 }
 
-static int 
+static int
 e1000_set_pauseparam(struct net_device *netdev,
-                    struct ethtool_pauseparam *pause)
+                     struct ethtool_pauseparam *pause)
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	struct e1000_hw *hw = &adapter->hw;
@@ -271,7 +274,7 @@
 		e1000_reset(adapter);
 	return 0;
 }
-
+	
 static uint32_t
 e1000_get_tx_csum(struct net_device *netdev)
 {
@@ -337,7 +340,7 @@
 
 static void
 e1000_get_regs(struct net_device *netdev,
-                    struct ethtool_regs *regs, void *p)
+	       struct ethtool_regs *regs, void *p)
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	struct e1000_hw *hw = &adapter->hw;
@@ -418,6 +421,10 @@
 	e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
 	regs_buff[24] = (uint32_t)phy_data;  /* phy local receiver status */
 	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
+	if(hw->mac_type >= e1000_82540 &&
+	   hw->media_type == e1000_media_type_copper) {
+		regs_buff[26] = E1000_READ_REG(hw, MANC);
+	}
 }
 
 static int
@@ -438,7 +445,7 @@
 	int ret_val = 0;
 	uint16_t i;
 
-	if(eeprom->len == 0) 
+	if(eeprom->len == 0)
 		return -EINVAL;
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
@@ -446,9 +453,9 @@
 	first_word = eeprom->offset >> 1;
 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
 
-	eeprom_buff = kmalloc(sizeof(uint16_t) * 
+	eeprom_buff = kmalloc(sizeof(uint16_t) *
 			(last_word - first_word + 1), GFP_KERNEL);
-	if (!eeprom_buff)
+	if(!eeprom_buff)
 		return -ENOMEM;
 
 	if(hw->eeprom.type == e1000_eeprom_spi)
@@ -466,9 +473,8 @@
 	for (i = 0; i < last_word - first_word + 1; i++)
 		le16_to_cpus(&eeprom_buff[i]);
 
-
-	memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset%2), 
-				eeprom->len);
+	memcpy(bytes, (uint8_t *)eeprom_buff + (eeprom->offset & 1),
+			eeprom->len);
 	kfree(eeprom_buff);
 
 	return ret_val;
@@ -520,6 +526,7 @@
 		le16_to_cpus(&eeprom_buff[i]);
 
 	memcpy(ptr, bytes, eeprom->len);
+
 	for (i = 0; i < last_word - first_word + 1; i++)
 		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
 
@@ -575,17 +582,16 @@
 e1000_set_ringparam(struct net_device *netdev,
                     struct ethtool_ringparam *ring)
 {
-	int err;
 	struct e1000_adapter *adapter = netdev->priv;
 	e1000_mac_type mac_type = adapter->hw.mac_type;
 	struct e1000_desc_ring *txdr = &adapter->tx_ring;
 	struct e1000_desc_ring *rxdr = &adapter->rx_ring;
-	struct e1000_desc_ring tx_old, tx_new;
-	struct e1000_desc_ring rx_old, rx_new;
+	struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new;
+	int err;
 
 	tx_old = adapter->tx_ring;
 	rx_old = adapter->rx_ring;
-	
+
 	if(netif_running(adapter->netdev))
 		e1000_down(adapter);
 
@@ -600,15 +606,15 @@
 	E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); 
 
 	if(netif_running(adapter->netdev)) {
-		/* try to get new resources before deleting old */
+		/* Try to get new resources before deleting old */
 		if((err = e1000_setup_rx_resources(adapter)))
 			goto err_setup_rx;
 		if((err = e1000_setup_tx_resources(adapter)))
 			goto err_setup_tx;
 
 		/* save the new, restore the old in order to free it,
-		 * then restore the new back again */	
-	
+		 * then restore the new back again */
+
 		rx_new = adapter->rx_ring;
 		tx_new = adapter->tx_ring;
 		adapter->rx_ring = rx_old;
@@ -620,6 +626,7 @@
 		if((err = e1000_up(adapter)))
 			return err;
 	}
+
 	return 0;
 err_setup_tx:
 	e1000_free_rx_resources(adapter);
@@ -630,7 +637,6 @@
 	return err;
 }
 
-
 #define REG_PATTERN_TEST(R, M, W)                                              \
 {                                                                              \
 	uint32_t pat, value;                                                   \
@@ -766,13 +772,15 @@
 e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
 {
 	struct net_device *netdev = adapter->netdev;
-	uint32_t icr, mask, i=0;
+ 	uint32_t icr, mask, i=0, shared_int = TRUE;
+ 	uint32_t irq = adapter->pdev->irq;
 
 	*data = 0;
 
 	/* Hook up test interrupt handler just for this test */
-	if(request_irq(adapter->pdev->irq, &e1000_test_intr, SA_SHIRQ,
-	   netdev->name, netdev)) {
+ 	if(!request_irq(irq, &e1000_test_intr, 0, netdev->name, netdev)) {
+ 		shared_int = FALSE;
+ 	} else if(request_irq(irq, &e1000_test_intr, SA_SHIRQ, netdev->name, netdev)){
 		*data = 1;
 		return -1;
 	}
@@ -802,20 +810,22 @@
 		/* Interrupt to test */
 		mask = 1 << i;
 
-		/* Disable the interrupt to be reported in
-		 * the cause register and then force the same
-		 * interrupt and see if one gets posted.  If
-		 * an interrupt was posted to the bus, the
-		 * test failed.
-		 */
-		adapter->test_icr = 0;
-		E1000_WRITE_REG(&adapter->hw, IMC, mask);
-		E1000_WRITE_REG(&adapter->hw, ICS, mask);
-		msec_delay(10);
-
-		if(adapter->test_icr & mask) {
-			*data = 3;
-			break;
+ 		if(!shared_int) {
+ 			/* Disable the interrupt to be reported in
+ 			 * the cause register and then force the same
+ 			 * interrupt and see if one gets posted.  If
+ 			 * an interrupt was posted to the bus, the
+ 			 * test failed.
+ 			 */
+ 			adapter->test_icr = 0;
+ 			E1000_WRITE_REG(&adapter->hw, IMC, mask);
+ 			E1000_WRITE_REG(&adapter->hw, ICS, mask);
+ 			msec_delay(10);
+ 
+ 			if(adapter->test_icr & mask) {
+ 				*data = 3;
+ 				break;
+ 			}
 		}
 
 		/* Enable the interrupt to be reported in
@@ -834,20 +844,22 @@
 			break;
 		}
 
-		/* Disable the other interrupts to be reported in
-		 * the cause register and then force the other
-		 * interrupts and see if any get posted.  If
-		 * an interrupt was posted to the bus, the
-		 * test failed.
-		 */
-		adapter->test_icr = 0;
-		E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
-		E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
-		msec_delay(10);
+ 		if(!shared_int) {
+			/* Disable the other interrupts to be reported in
+			 * the cause register and then force the other
+			 * interrupts and see if any get posted.  If
+			 * an interrupt was posted to the bus, the
+			 * test failed.
+			 */
+			adapter->test_icr = 0;
+			E1000_WRITE_REG(&adapter->hw, IMC, ~mask);
+			E1000_WRITE_REG(&adapter->hw, ICS, ~mask);
+			msec_delay(10);
 
-		if(adapter->test_icr) {
-			*data = 5;
-			break;
+			if(adapter->test_icr) {
+				*data = 5;
+				break;
+			}
 		}
 	}
 
@@ -856,7 +868,7 @@
 	msec_delay(10);
 
 	/* Unhook test interrupt handler */
-	free_irq(adapter->pdev->irq, netdev);
+	free_irq(irq, netdev);
 
 	return *data;
 }
@@ -1020,7 +1032,7 @@
 
 	return 0;
 
-      err_nomem:
+err_nomem:
 	e1000_free_desc_rings(adapter);
 	return ret_val;
 }
@@ -1356,7 +1368,7 @@
 }
 
 static void
-e1000_diag_test(struct net_device *netdev, 
+e1000_diag_test(struct net_device *netdev,
 		   struct ethtool_test *eth_test, uint64_t *data)
 {
 	struct e1000_adapter *adapter = netdev->priv;
@@ -1367,7 +1379,7 @@
 
 		/* save speed, duplex, autoneg settings */
 		uint16_t autoneg_advertised = adapter->hw.autoneg_advertised;
-    		uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex;
+		uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex;
 		uint8_t autoneg = adapter->hw.autoneg;
 
 		/* Link test performed before hardware reset so autoneg doesn't
@@ -1395,10 +1407,11 @@
 		if(e1000_loopback_test(adapter, &data[3]))
 			eth_test->flags |= ETH_TEST_FL_FAILED;
 
-		/* restore Autoneg/speed/duplex settings */
+		/* restore speed, duplex, autoneg settings */
 		adapter->hw.autoneg_advertised = autoneg_advertised;
-    		adapter->hw.forced_speed_duplex = forced_speed_duplex;
-    		adapter->hw.autoneg = autoneg;
+		adapter->hw.forced_speed_duplex = forced_speed_duplex;
+		adapter->hw.autoneg = autoneg;
+
 		e1000_reset(adapter);
 		if(if_running)
 			e1000_up(adapter);
@@ -1426,6 +1439,9 @@
 	case E1000_DEV_ID_82543GC_FIBER:
 	case E1000_DEV_ID_82543GC_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
+	case E1000_DEV_ID_82546EB_QUAD_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+	case E1000_DEV_ID_82545EM_COPPER:
 		wol->supported = 0;
 		wol->wolopts   = 0;
 		return;
@@ -1468,6 +1484,7 @@
 	case E1000_DEV_ID_82543GC_FIBER:
 	case E1000_DEV_ID_82543GC_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
+	case E1000_DEV_ID_82546EB_QUAD_COPPER:
 		return wol->wolopts ? -EOPNOTSUPP : 0;
 
 	case E1000_DEV_ID_82546EB_FIBER:
@@ -1570,8 +1587,8 @@
 	e1000_update_stats(adapter);
 	for(i = 0; i < E1000_STATS_LEN; i++) {
 		char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;	
-		data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) 
-			? *(uint64_t *)p : *(uint32_t *)p;
+		data[i] = (e1000_gstrings_stats[i].sizeof_stat == 
+			sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p;
 	}
 }
 
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000_hw.c linux-2.4.28-pre4/drivers/net/e1000/e1000_hw.c
--- linux-2.4.28-pre3/drivers/net/e1000/e1000_hw.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000_hw.c	2004-10-08 06:28:25.323246023 -0700
@@ -65,6 +65,7 @@
 static void e1000_standby_eeprom(struct e1000_hw *hw);
 static int32_t e1000_id_led_init(struct e1000_hw * hw);
 static int32_t e1000_set_vco_speed(struct e1000_hw *hw);
+static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw);
 static int32_t e1000_set_phy_mode(struct e1000_hw *hw);
 
 /* IGP cable length table */
@@ -124,6 +125,7 @@
 {
     DEBUGFUNC("e1000_phy_init_script");
 
+    
     if(hw->phy_init_script) {
         msec_delay(20);
 
@@ -251,6 +253,7 @@
         break;
     case E1000_DEV_ID_82541ER:
     case E1000_DEV_ID_82541GI:
+    case E1000_DEV_ID_82541GI_LF:
     case E1000_DEV_ID_82541GI_MOBILE:
         hw->mac_type = e1000_82541_rev_2;
         break;
@@ -920,7 +923,8 @@
     if(ret_val)
         return ret_val;
 
-    if(hw->mac_type == e1000_82545_rev_3) {
+    if((hw->mac_type == e1000_82545_rev_3) ||
+       (hw->mac_type == e1000_82546_rev_3)) {
         ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
         phy_data |= 0x00000008;
         ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
@@ -1388,6 +1392,7 @@
     DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
 
     ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+    
     if(ret_val)
         return ret_val;
 
@@ -1592,6 +1597,15 @@
         ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
         if(ret_val)
             return ret_val;
+
+        if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
+           (!hw->autoneg) &&
+           (hw->forced_speed_duplex == e1000_10_full ||
+            hw->forced_speed_duplex == e1000_10_half)) {
+            ret_val = e1000_polarity_reversal_workaround(hw);
+            if(ret_val)
+                return ret_val;
+        }
     }
     return E1000_SUCCESS;
 }
@@ -1981,6 +1995,7 @@
     uint32_t ctrl;
     uint32_t status;
     uint32_t rctl;
+    uint32_t icr;
     uint32_t signal = 0;
     int32_t ret_val;
     uint16_t phy_data;
@@ -2030,6 +2045,25 @@
              * link-up */
             e1000_check_downshift(hw);
 
+            /* If we are on 82544 or 82543 silicon and speed/duplex
+             * are forced to 10H or 10F, then we will implement the polarity
+             * reversal workaround.  We disable interrupts first, and upon
+             * returning, place the devices interrupt state to its previous
+             * value except for the link status change interrupt which will
+             * happen due to the execution of this workaround.
+             */
+
+            if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
+               (!hw->autoneg) &&
+               (hw->forced_speed_duplex == e1000_10_full ||
+                hw->forced_speed_duplex == e1000_10_half)) {
+                E1000_WRITE_REG(hw, IMC, 0xffffffff);
+                ret_val = e1000_polarity_reversal_workaround(hw);
+                icr = E1000_READ_REG(hw, ICR);
+                E1000_WRITE_REG(hw, ICS, (icr & ~E1000_ICS_LSC));
+                E1000_WRITE_REG(hw, IMS, IMS_ENABLE_MASK);
+            }
+
         } else {
             /* No link detected */
             e1000_config_dsp_after_link_change(hw, FALSE);
@@ -2434,6 +2468,7 @@
 
     DEBUGFUNC("e1000_read_phy_reg");
 
+
     if(hw->phy_type == e1000_phy_igp &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -2538,6 +2573,7 @@
 
     DEBUGFUNC("e1000_write_phy_reg");
 
+
     if(hw->phy_type == e1000_phy_igp &&
        (reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
         ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
@@ -3057,16 +3093,6 @@
         }
         break;
     default:
-        eeprom->type = e1000_eeprom_spi;
-        eeprom->opcode_bits = 8;
-        eeprom->delay_usec = 1;
-        if (eecd & E1000_EECD_ADDR_BITS) {
-            eeprom->page_size = 32;
-            eeprom->address_bits = 16;
-        } else {
-            eeprom->page_size = 8;
-            eeprom->address_bits = 8;
-        }
         break;
     }
 
@@ -3453,7 +3479,6 @@
     uint32_t i = 0;
 
     DEBUGFUNC("e1000_read_eeprom");
-
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
@@ -3516,6 +3541,7 @@
     return E1000_SUCCESS;
 }
 
+
 /******************************************************************************
  * Verifies that the EEPROM has a valid checksum
  *
@@ -3602,6 +3628,7 @@
 
     DEBUGFUNC("e1000_write_eeprom");
 
+
     /* A check for invalid values:  offset too large, too many words, and not
      * enough words.
      */
@@ -5224,3 +5251,89 @@
     }
     return FALSE;
 }
+
+static int32_t
+e1000_polarity_reversal_workaround(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t i;
+
+    /* Polarity reversal workaround for forced 10F/10H links. */
+
+    /* Disable the transmitter on the PHY */
+
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+    if(ret_val)
+        return ret_val;
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    /* This loop will early-out if the NO link condition has been met. */
+    for(i = PHY_FORCE_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Link Status bit
+         * to be clear.
+         */
+
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+        msec_delay_irq(100);
+    }
+
+    /* Recommended delay time after link has been lost */
+    msec_delay_irq(1000);
+
+    /* Now we will re-enable th transmitter on the PHY */
+
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
+    if(ret_val)
+        return ret_val;
+    msec_delay_irq(50);
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
+    if(ret_val)
+        return ret_val;
+
+    /* This loop will early-out if the link condition has been met. */
+    for(i = PHY_FORCE_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Link Status bit
+         * to be set.
+         */
+
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
+        if(ret_val)
+            return ret_val;
+
+        if(mii_status_reg & MII_SR_LINK_STATUS) break;
+        msec_delay_irq(100);
+    }
+    return E1000_SUCCESS;
+}
+
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000_hw.h linux-2.4.28-pre4/drivers/net/e1000/e1000_hw.h
--- linux-2.4.28-pre3/drivers/net/e1000/e1000_hw.h	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000_hw.h	2004-10-08 06:28:25.325246105 -0700
@@ -36,6 +36,7 @@
 #include "e1000_osdep.h"
 
 
+
 /* Forward declarations of structures used by the shared code */
 struct e1000_hw;
 struct e1000_hw_stats;
@@ -357,11 +358,11 @@
 #define E1000_DEV_ID_82547GI             0x1075
 #define E1000_DEV_ID_82541GI             0x1076
 #define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
 #define E1000_DEV_ID_82546GB_COPPER      0x1079
 #define E1000_DEV_ID_82546GB_FIBER       0x107A
 #define E1000_DEV_ID_82546GB_SERDES      0x107B
 #define E1000_DEV_ID_82547EI             0x1019
-
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
 
@@ -1043,7 +1044,6 @@
 
 #define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
 #define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
-
 /* Register Bit Masks */
 /* Device Control */
 #define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000_main.c linux-2.4.28-pre4/drivers/net/e1000/e1000_main.c
--- linux-2.4.28-pre3/drivers/net/e1000/e1000_main.c	2004-10-08 06:28:21.474089424 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000_main.c	2004-10-08 06:28:25.330246308 -0700
@@ -27,73 +27,69 @@
 *******************************************************************************/
 
 #include "e1000.h"
-#include <linux/rtnetlink.h>
 
 /* Change Log
+ * 5.3.12	6/7/04
+ * - kcompat NETIF_MSG for older kernels (2.4.9) <sean.p.mcdermott@intel.com>
+ * - if_mii support and associated kcompat for older kernels
+ * - More errlogging support from Jon Mason <jonmason@us.ibm.com>
+ * - Fix TSO issues on PPC64 machines -- Jon Mason <jonmason@us.ibm.com>
  *
- * 5.2.51   5/14/04
- *   o set default configuration to 'NAPI disabled'. NAPI enabled driver
- *     causes kernel panic when the interface is shutdown while data is being
- *     transferred.
- * 5.2.47   5/04/04
- *   o fixed ethtool -t implementation
- * 5.2.45   4/29/04
- *   o fixed ethtool -e implementation
- *   o Support for ethtool ops [Stephen Hemminger (shemminger@osdl.org)]
- * 5.2.42   4/26/04
- *   o Added support for the DPRINTK macro for enhanced error logging.  Some
- *     parts of the patch were supplied by Jon Mason.
- *   o Move the register_netdevice() donw in the probe routine due to a 
- *     loading/unloading test issue.
- *   o Added a long RX byte count the the extra ethtool data members for BER
- *     testing purposes.
- * 5.2.39	3/12/04
+ * 5.3.11	6/4/04
+ * - ethtool register dump reads MANC register conditionally.
+ *
+ * 5.3.10	6/1/04
  */
 
 char e1000_driver_name[] = "e1000";
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-char e1000_driver_version[] = "5.2.52-k3";
+#ifndef CONFIG_E1000_NAPI
+#define DRIVERNAPI
+#else
+#define DRIVERNAPI "-NAPI"
+#endif
+char e1000_driver_version[] = "5.4.11-k1"DRIVERNAPI;
 char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
  *
- * Wildcard entries (PCI_ANY_ID) should come last
  * Last entry must be all 0s
  *
- * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
- *   Class, Class Mask, private data (not used) }
+ * Macro expands to...
+ *   {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)}
  */
 static struct pci_device_id e1000_pci_tbl[] = {
-	{0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x101D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1026, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1027, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1075, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1076, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1077, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1078, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x1079, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x107A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{0x8086, 0x107B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	INTEL_E1000_ETHERNET_DEVICE(0x1000),
+	INTEL_E1000_ETHERNET_DEVICE(0x1001),
+	INTEL_E1000_ETHERNET_DEVICE(0x1004),
+	INTEL_E1000_ETHERNET_DEVICE(0x1008),
+	INTEL_E1000_ETHERNET_DEVICE(0x1009),
+	INTEL_E1000_ETHERNET_DEVICE(0x100C),
+	INTEL_E1000_ETHERNET_DEVICE(0x100D),
+	INTEL_E1000_ETHERNET_DEVICE(0x100E),
+	INTEL_E1000_ETHERNET_DEVICE(0x100F),
+	INTEL_E1000_ETHERNET_DEVICE(0x1010),
+	INTEL_E1000_ETHERNET_DEVICE(0x1011),
+	INTEL_E1000_ETHERNET_DEVICE(0x1012),
+	INTEL_E1000_ETHERNET_DEVICE(0x1013),
+	INTEL_E1000_ETHERNET_DEVICE(0x1015),
+	INTEL_E1000_ETHERNET_DEVICE(0x1016),
+	INTEL_E1000_ETHERNET_DEVICE(0x1017),
+	INTEL_E1000_ETHERNET_DEVICE(0x1018),
+	INTEL_E1000_ETHERNET_DEVICE(0x1019),
+	INTEL_E1000_ETHERNET_DEVICE(0x101D),
+	INTEL_E1000_ETHERNET_DEVICE(0x101E),
+	INTEL_E1000_ETHERNET_DEVICE(0x1026),
+	INTEL_E1000_ETHERNET_DEVICE(0x1027),
+	INTEL_E1000_ETHERNET_DEVICE(0x1028),
+	INTEL_E1000_ETHERNET_DEVICE(0x1075),
+	INTEL_E1000_ETHERNET_DEVICE(0x1076),
+	INTEL_E1000_ETHERNET_DEVICE(0x1077),
+	INTEL_E1000_ETHERNET_DEVICE(0x1078),
+	INTEL_E1000_ETHERNET_DEVICE(0x1079),
+	INTEL_E1000_ETHERNET_DEVICE(0x107A),
+	INTEL_E1000_ETHERNET_DEVICE(0x107B),
+	INTEL_E1000_ETHERNET_DEVICE(0x107C),
 	/* required last entry */
 	{0,}
 };
@@ -172,7 +168,7 @@
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /* for netdump / net console */
-static void e1000_netpoll (struct net_device *dev);
+static void e1000_netpoll (struct net_device *netdev);
 #endif
 
 struct notifier_block e1000_notifier_reboot = {
@@ -185,7 +181,6 @@
 
 extern void e1000_check_options(struct e1000_adapter *adapter);
 
-
 static struct pci_driver e1000_driver = {
 	.name     = e1000_driver_name,
 	.id_table = e1000_pci_tbl,
@@ -202,7 +197,7 @@
 MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
 MODULE_LICENSE("GPL");
 
-static int debug = 3;
+static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
@@ -248,34 +243,6 @@
 module_exit(e1000_exit_module);
 
 
-/**
- * e1000_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- **/
-
-static inline void
-e1000_irq_enable(struct e1000_adapter *adapter)
-{
-	if(atomic_dec_and_test(&adapter->irq_sem)) {
-		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
-		E1000_WRITE_FLUSH(&adapter->hw);
-	}
-}
-
-/**
- * e1000_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-
-static inline void
-e1000_irq_disable(struct e1000_adapter *adapter)
-{
-	atomic_inc(&adapter->irq_sem);
-	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
-	E1000_WRITE_FLUSH(&adapter->hw);
-	synchronize_irq();
-}
-
 int
 e1000_up(struct e1000_adapter *adapter)
 {
@@ -284,6 +251,14 @@
 
 	/* hardware has been reset, we need to reload some things */
 
+	/* Reset the PHY if it was previously powered down */
+	if(adapter->hw.media_type == e1000_media_type_copper) {
+		uint16_t mii_reg;
+		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+		if(mii_reg & MII_CR_POWER_DOWN)
+			e1000_phy_reset(&adapter->hw);
+	}
+
 	e1000_set_multi(netdev);
 
 	e1000_restore_vlan(adapter);
@@ -322,12 +297,22 @@
 	e1000_reset(adapter);
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
+
+	/* If WoL is not enabled
+	 * Power down the PHY so no link is implied when interface is down */
+	if(!adapter->wol && adapter->hw.media_type == e1000_media_type_copper) {
+		uint16_t mii_reg;
+		e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+		mii_reg |= MII_CR_POWER_DOWN;
+		e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+	}
 }
 
 void
 e1000_reset(struct e1000_adapter *adapter)
 {
-	uint32_t pba, manc;
+	uint32_t pba;
+
 	/* Repartition Pba for greater than 9k mtu
 	 * To take effect CTRL.RST is required.
 	 */
@@ -351,10 +336,10 @@
 	E1000_WRITE_REG(&adapter->hw, PBA, pba);
 
 	/* flow control settings */
-	adapter->hw.fc_high_water =
-		(pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_HIGH_DIFF;
-	adapter->hw.fc_low_water =
-		(pba << E1000_PBA_BYTES_SHIFT) - E1000_FC_LOW_DIFF;
+	adapter->hw.fc_high_water = (pba << E1000_PBA_BYTES_SHIFT) -
+				    E1000_FC_HIGH_DIFF;
+	adapter->hw.fc_low_water = (pba << E1000_PBA_BYTES_SHIFT) -
+				   E1000_FC_LOW_DIFF;
 	adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME;
 	adapter->hw.fc_send_xon = 1;
 	adapter->hw.fc = adapter->hw.original_fc;
@@ -362,19 +347,14 @@
 	e1000_reset_hw(&adapter->hw);
 	if(adapter->hw.mac_type >= e1000_82544)
 		E1000_WRITE_REG(&adapter->hw, WUC, 0);
-	e1000_init_hw(&adapter->hw);
+	if(e1000_init_hw(&adapter->hw))
+		DPRINTK(PROBE, ERR, "Hardware Error\n");
 
 	/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
 	E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
 
 	e1000_reset_adaptive(&adapter->hw);
 	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
-
-	if(adapter->en_mng_pt) {
-		manc = E1000_READ_REG(&adapter->hw, MANC);
-		manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
-		E1000_WRITE_REG(&adapter->hw, MANC, manc);
-	}
 }
 
 /**
@@ -437,11 +417,6 @@
 	adapter->hw.back = adapter;
 	adapter->msg_enable = (1 << debug) - 1;
 
-	rtnl_lock();
-	/* we need to set the name early since the DPRINTK macro needs it set */
-	if (dev_alloc_name(netdev, netdev->name) < 0) 
-		goto err_free_unlock;
-
 	mmio_start = pci_resource_start(pdev, BAR_0);
 	mmio_len = pci_resource_len(pdev, BAR_0);
 
@@ -481,6 +456,7 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	netdev->poll_controller = e1000_netpoll;
 #endif
+	strcpy(netdev->name, pci_name(pdev));
 
 	netdev->mem_start = mmio_start;
 	netdev->mem_end = mmio_start + mmio_len;
@@ -504,7 +480,6 @@
 	}
 
 #ifdef NETIF_F_TSO
-#ifdef BROKEN_ON_NON_IA_ARCHS
 	/* Disbaled for now until root-cause is found for
 	 * hangs reported against non-IA archs.  TSO can be
 	 * enabled using ethtool -K eth<x> tso on */
@@ -512,13 +487,9 @@
 	   (adapter->hw.mac_type != e1000_82547))
 		netdev->features |= NETIF_F_TSO;
 #endif
-#endif
-
 	if(pci_using_dac)
 		netdev->features |= NETIF_F_HIGHDMA;
 
-	adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
-
 	/* before reading the EEPROM, reset the controller to 
 	 * put the device in a known good starting state */
 	
@@ -534,10 +505,12 @@
 
 	/* copy the MAC address out of the EEPROM */
 
-	e1000_read_mac_addr(&adapter->hw);
+	if (e1000_read_mac_addr(&adapter->hw))
+		DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
 	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 
 	if(!is_valid_ether_addr(netdev->dev_addr)) {
+		DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
 		err = -EIO;
 		goto err_eeprom;
 	}
@@ -566,7 +539,6 @@
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
-	DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n");
 	e1000_check_options(adapter);
 
 	/* Initial Wake on LAN setting
@@ -597,15 +569,15 @@
 		adapter->wol |= E1000_WUFC_MAG;
 
 	/* reset the hardware with the new settings */
-
 	e1000_reset(adapter);
 
-	/* since we are holding the rtnl lock already, call the no-lock version */
-	if((err = register_netdevice(netdev)))
+	strcpy(netdev->name, "eth%d");
+	if((err = register_netdev(netdev)))
 		goto err_register;
 
+	DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n");
+
 	cards_found++;
-	rtnl_unlock();
 	return 0;
 
 err_register:
@@ -613,8 +585,6 @@
 err_eeprom:
 	iounmap(adapter->hw.hw_addr);
 err_ioremap:
-err_free_unlock:
-	rtnl_unlock();
 	free_netdev(netdev);
 err_alloc_etherdev:
 	pci_release_regions(pdev);
@@ -691,7 +661,7 @@
 
 	/* identify the MAC */
 
-	if (e1000_set_mac_type(hw)) {
+	if(e1000_set_mac_type(hw)) {
 		DPRINTK(PROBE, ERR, "Unknown MAC Type\n");
 		return -EIO;
 	}
@@ -700,19 +670,19 @@
 
 	e1000_init_eeprom_params(hw);
 
-	if((hw->mac_type == e1000_82541) ||
-	   (hw->mac_type == e1000_82547) ||
-	   (hw->mac_type == e1000_82541_rev_2) ||
-	   (hw->mac_type == e1000_82547_rev_2))
+	switch(hw->mac_type) {
+	default:
+		break;
+	case e1000_82541:
+	case e1000_82547:
+	case e1000_82541_rev_2:
+	case e1000_82547_rev_2:
 		hw->phy_init_script = 1;
+		break;
+	}
 
 	e1000_set_media_type(hw);
 
-	if(hw->mac_type < e1000_82543)
-		hw->report_tx_early = 0;
-	else
-		hw->report_tx_early = 1;
-
 	hw->wait_autoneg_complete = FALSE;
 	hw->tbi_compatibility_en = TRUE;
 	hw->adaptive_ifs = TRUE;
@@ -764,7 +734,7 @@
 	if((err = e1000_up(adapter)))
 		goto err_up;
 
-	return 0;
+	return E1000_SUCCESS;
 
 err_up:
 	e1000_free_rx_resources(adapter);
@@ -816,8 +786,10 @@
 	int size;
 
 	size = sizeof(struct e1000_buffer) * txdr->count;
-	txdr->buffer_info = kmalloc(size, GFP_KERNEL);
+	txdr->buffer_info = vmalloc(size);
 	if(!txdr->buffer_info) {
+		DPRINTK(PROBE, ERR, 
+		"Unable to Allocate Memory for the Transmit descriptor ring\n");
 		return -ENOMEM;
 	}
 	memset(txdr->buffer_info, 0, size);
@@ -829,7 +801,9 @@
 
 	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
 	if(!txdr->desc) {
-		kfree(txdr->buffer_info);
+		DPRINTK(PROBE, ERR, 
+		"Unable to Allocate Memory for the Transmit descriptor ring\n");
+		vfree(txdr->buffer_info);
 		return -ENOMEM;
 	}
 	memset(txdr->desc, 0, txdr->size);
@@ -906,10 +880,10 @@
 	adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP |
 		E1000_TXD_CMD_IFCS;
 
-	if(adapter->hw.report_tx_early == 1)
-		adapter->txd_cmd |= E1000_TXD_CMD_RS;
-	else
+	if(adapter->hw.mac_type < e1000_82543)
 		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
+	else
+		adapter->txd_cmd |= E1000_TXD_CMD_RS;
 
 	/* Cache if we're 82544 running in PCI-X because we'll
 	 * need this to apply a workaround later in the send path. */
@@ -933,8 +907,10 @@
 	int size;
 
 	size = sizeof(struct e1000_buffer) * rxdr->count;
-	rxdr->buffer_info = kmalloc(size, GFP_KERNEL);
+	rxdr->buffer_info = vmalloc(size);
 	if(!rxdr->buffer_info) {
+		DPRINTK(PROBE, ERR, 
+		"Unable to Allocate Memory for the Recieve descriptor ring\n");
 		return -ENOMEM;
 	}
 	memset(rxdr->buffer_info, 0, size);
@@ -947,7 +923,9 @@
 	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
 
 	if(!rxdr->desc) {
-		kfree(rxdr->buffer_info);
+		DPRINTK(PROBE, ERR, 
+		"Unable to Allocate Memory for the Recieve descriptor ring\n");
+		vfree(rxdr->buffer_info);
 		return -ENOMEM;
 	}
 	memset(rxdr->desc, 0, rxdr->size);
@@ -981,7 +959,9 @@
 	else
 		rctl &= ~E1000_RCTL_SBP;
 
+	/* Setup buffer sizes */
 	rctl &= ~(E1000_RCTL_SZ_4096);
+	rctl |= (E1000_RCTL_BSEX | E1000_RCTL_LPE);
 	switch (adapter->rx_buffer_len) {
 	case E1000_RXBUFFER_2048:
 	default:
@@ -989,13 +969,13 @@
 		rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
 		break;
 	case E1000_RXBUFFER_4096:
-		rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		rctl |= E1000_RCTL_SZ_4096;
 		break;
 	case E1000_RXBUFFER_8192:
-		rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		rctl |= E1000_RCTL_SZ_8192;
 		break;
 	case E1000_RXBUFFER_16384:
-		rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+		rctl |= E1000_RCTL_SZ_16384;
 		break;
 	}
 
@@ -1017,13 +997,11 @@
 	uint32_t rctl;
 	uint32_t rxcsum;
 
-	/* make sure receives are disabled while setting up the descriptors */
-
+	/* disable receives while setting up the descriptors */
 	rctl = E1000_READ_REG(&adapter->hw, RCTL);
 	E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
 
 	/* set the Receive Delay Timer Register */
-
 	E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
 
 	if(adapter->hw.mac_type >= e1000_82540) {
@@ -1034,7 +1012,6 @@
 	}
 
 	/* Setup the Base and Length of the Rx Descriptor Ring */
-
 	E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL));
 	E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
 
@@ -1053,7 +1030,6 @@
 	}
 
 	/* Enable Receives */
-
 	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 }
 
@@ -1071,7 +1047,7 @@
 
 	e1000_clean_tx_ring(adapter);
 
-	kfree(adapter->tx_ring.buffer_info);
+	vfree(adapter->tx_ring.buffer_info);
 	adapter->tx_ring.buffer_info = NULL;
 
 	pci_free_consistent(pdev, adapter->tx_ring.size,
@@ -1101,9 +1077,9 @@
 		if(buffer_info->skb) {
 
 			pci_unmap_page(pdev,
-			               buffer_info->dma,
-			               buffer_info->length,
-			               PCI_DMA_TODEVICE);
+				       buffer_info->dma,
+				       buffer_info->length,
+				       PCI_DMA_TODEVICE);
 
 			dev_kfree_skb(buffer_info->skb);
 
@@ -1140,7 +1116,7 @@
 
 	e1000_clean_rx_ring(adapter);
 
-	kfree(rx_ring->buffer_info);
+	vfree(rx_ring->buffer_info);
 	rx_ring->buffer_info = NULL;
 
 	pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
@@ -1169,12 +1145,11 @@
 		if(buffer_info->skb) {
 
 			pci_unmap_single(pdev,
-			                 buffer_info->dma,
-			                 buffer_info->length,
-			                 PCI_DMA_FROMDEVICE);
+					 buffer_info->dma,
+					 buffer_info->length,
+					 PCI_DMA_FROMDEVICE);
 
 			dev_kfree_skb(buffer_info->skb);
-
 			buffer_info->skb = NULL;
 		}
 	}
@@ -1340,7 +1315,8 @@
 		e1000_leave_82542_rst(adapter);
 }
 
-/* need to wait a few seconds after link up to get diagnostic information from the phy */
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy */
 
 static void
 e1000_update_phy_info(unsigned long data)
@@ -1448,7 +1424,7 @@
 	adapter->tpt_old = adapter->stats.tpt;
 	adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old;
 	adapter->colc_old = adapter->stats.colc;
-	
+
 	adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
 	adapter->gorcl_old = adapter->stats.gorcl;
 	adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
@@ -1505,8 +1481,9 @@
 #ifdef NETIF_F_TSO
 	struct e1000_context_desc *context_desc;
 	unsigned int i;
-	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
+	uint32_t cmd_length = 0;
 	uint16_t ipcse, tucse, mss;
+	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
 
 	if(skb_shinfo(skb)->tso_size) {
 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
@@ -1525,6 +1502,10 @@
 		tucso = (void *)&(skb->h.th->check) - (void *)skb->data;
 		tucse = 0;
 
+		cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
+			       E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
+			       (skb->len - (hdr_len)));
+
 		i = adapter->tx_ring.next_to_use;
 		context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
 
@@ -1536,10 +1517,7 @@
 		context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
 		context_desc->tcp_seg_setup.fields.mss     = cpu_to_le16(mss);
 		context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
-		context_desc->cmd_and_length = cpu_to_le32(
-			E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
-			E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP |
-			(skb->len - (hdr_len)));
+		context_desc->cmd_and_length = cpu_to_le32(cmd_length);
 
 		if(++i == adapter->tx_ring.count) i = 0;
 		adapter->tx_ring.next_to_use = i;
@@ -1556,22 +1534,21 @@
 {
 	struct e1000_context_desc *context_desc;
 	unsigned int i;
-	uint8_t css, cso;
+	uint8_t css;
 
-	if(skb->ip_summed == CHECKSUM_HW) {
+	if(likely(skb->ip_summed == CHECKSUM_HW)) {
 		css = skb->h.raw - skb->data;
-		cso = (skb->h.raw + skb->csum) - skb->data;
 
 		i = adapter->tx_ring.next_to_use;
 		context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
 
 		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso = cso;
+		context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
 		context_desc->upper_setup.tcp_fields.tucse = 0;
 		context_desc->tcp_seg_setup.data = 0;
 		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
 
-		if(++i == adapter->tx_ring.count) i = 0;
+		if(unlikely(++i == adapter->tx_ring.count)) i = 0;
 		adapter->tx_ring.next_to_use = i;
 
 		return TRUE;
@@ -1595,7 +1572,6 @@
 	unsigned int f;
 	len -= skb->data_len;
 
-
 	i = tx_ring->next_to_use;
 
 	while(len) {
@@ -1604,14 +1580,14 @@
 #ifdef NETIF_F_TSO
 		/* Workaround for premature desc write-backs
 		 * in TSO mode.  Append 4-byte sentinel desc */
-		if(mss && !nr_frags && size == len && size > 8)
+		if(unlikely(mss && !nr_frags && size == len && size > 8))
 			size -= 4;
 #endif
 		/* Workaround for potential 82544 hang in PCI-X.  Avoid
 		 * terminating buffers within evenly-aligned dwords. */
-		if(adapter->pcix_82544 &&
+		if(unlikely(adapter->pcix_82544 &&
 		   !((unsigned long)(skb->data + offset + size - 1) & 4) &&
-		   size > 4)
+		   size > 4))
 			size -= 4;
 
 		buffer_info->length = size;
@@ -1625,7 +1601,7 @@
 		len -= size;
 		offset += size;
 		count++;
-		if(++i == tx_ring->count) i = 0;
+		if(unlikely(++i == tx_ring->count)) i = 0;
 	}
 
 	for(f = 0; f < nr_frags; f++) {
@@ -1641,15 +1617,15 @@
 #ifdef NETIF_F_TSO
 			/* Workaround for premature desc write-backs
 			 * in TSO mode.  Append 4-byte sentinel desc */
-			if(mss && f == (nr_frags-1) && size == len && size > 8)
+			if(unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
 				size -= 4;
 #endif
 			/* Workaround for potential 82544 hang in PCI-X.
 			 * Avoid terminating buffers within evenly-aligned
 			 * dwords. */
-			if(adapter->pcix_82544 &&
+			if(unlikely(adapter->pcix_82544 &&
 			   !((unsigned long)(frag->page+offset+size-1) & 4) &&
-			   size > 4)
+			   size > 4))
 				size -= 4;
 
 			buffer_info->length = size;
@@ -1664,13 +1640,14 @@
 			len -= size;
 			offset += size;
 			count++;
-			if(++i == tx_ring->count) i = 0;
+			if(unlikely(++i == tx_ring->count)) i = 0;
 		}
 	}
+
 	i = (i == 0) ? tx_ring->count - 1 : i - 1;
 	tx_ring->buffer_info[i].skb = skb;
 	tx_ring->buffer_info[first].next_to_watch = i;
-	
+
 	return count;
 }
 
@@ -1683,18 +1660,18 @@
 	uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
 	unsigned int i;
 
-	if(tx_flags & E1000_TX_FLAGS_TSO) {
+	if(likely(tx_flags & E1000_TX_FLAGS_TSO)) {
 		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
 		             E1000_TXD_CMD_TSE;
 		txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8;
 	}
 
-	if(tx_flags & E1000_TX_FLAGS_CSUM) {
+	if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) {
 		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
 		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
 	}
 
-	if(tx_flags & E1000_TX_FLAGS_VLAN) {
+	if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) {
 		txd_lower |= E1000_TXD_CMD_VLE;
 		txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
 	}
@@ -1708,7 +1685,7 @@
 		tx_desc->lower.data =
 			cpu_to_le32(txd_lower | buffer_info->length);
 		tx_desc->upper.data = cpu_to_le32(txd_upper);
-		if(++i == tx_ring->count) i = 0;
+		if(unlikely(++i == tx_ring->count)) i = 0;
 	}
 
 	tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
@@ -1761,7 +1738,7 @@
 	return 0;
 }
 
-#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 ) 
+#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
 static int
 e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
@@ -1769,22 +1746,23 @@
 	unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
 	unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
 	unsigned int tx_flags = 0;
-	unsigned long flags;
 	unsigned int len = skb->len;
-	int count = 0;
-	unsigned int mss = 0;
+	unsigned long flags;
 	unsigned int nr_frags = 0;
+	unsigned int mss = 0;
+	int count = 0;
 	unsigned int f;
 	nr_frags = skb_shinfo(skb)->nr_frags;
 	len -= skb->data_len;
-	if(skb->len <= 0) {
+
+	if(unlikely(skb->len <= 0)) {
 		dev_kfree_skb_any(skb);
 		return 0;
 	}
 
 #ifdef NETIF_F_TSO
 	mss = skb_shinfo(skb)->tso_size;
-	/* The controller does a simple calculation to 
+	/* The controller does a simple calculation to
 	 * make sure there is enough room in the FIFO before
 	 * initiating the DMA for each buffer.  The calc is:
 	 * 4 = ceil(buffer len/mss).  To make sure we don't
@@ -1794,57 +1772,60 @@
 		max_per_txd = min(mss << 2, max_per_txd);
 		max_txd_pwr = fls(max_per_txd) - 1;
 	}
+
 	if((mss) || (skb->ip_summed == CHECKSUM_HW))
 		count++;
-	count++;	/*for sentinel desc*/
+	count++;	/* for sentinel desc */
 #else
 	if(skb->ip_summed == CHECKSUM_HW)
 		count++;
 #endif
-
 	count += TXD_USE_COUNT(len, max_txd_pwr);
+
 	if(adapter->pcix_82544)
 		count++;
 
 	nr_frags = skb_shinfo(skb)->nr_frags;
 	for(f = 0; f < nr_frags; f++)
 		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
-		                       max_txd_pwr);
+				       max_txd_pwr);
 	if(adapter->pcix_82544)
 		count += nr_frags;
-	
+
 	spin_lock_irqsave(&adapter->tx_lock, flags);
-	/* need: count +  2 desc gap to keep tail from touching 
+
+	/* need: count + 2 desc gap to keep tail from touching
 	 * head, otherwise try next time */
-	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2 ) {
+	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2) {
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&adapter->tx_lock, flags);
 		return 1;
 	}
+
 	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 
-	if(adapter->hw.mac_type == e1000_82547) {
-		if(e1000_82547_fifo_workaround(adapter, skb)) {
+	if(unlikely(adapter->hw.mac_type == e1000_82547)) {
+		if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
 			netif_stop_queue(netdev);
 			mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
 			return 1;
 		}
 	}
 
-	if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
+	if(unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
 		tx_flags |= E1000_TX_FLAGS_VLAN;
 		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
 	}
 
 	first = adapter->tx_ring.next_to_use;
 	
-	if(e1000_tso(adapter, skb))
+	if(likely(e1000_tso(adapter, skb)))
 		tx_flags |= E1000_TX_FLAGS_TSO;
-	else if(e1000_tx_csum(adapter, skb))
+	else if(likely(e1000_tx_csum(adapter, skb)))
 		tx_flags |= E1000_TX_FLAGS_CSUM;
 
-	e1000_tx_queue(adapter, 
-		e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss), 
+	e1000_tx_queue(adapter,
+		e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss),
 		tx_flags);
 
 	netdev->trans_start = jiffies;
@@ -1871,10 +1852,8 @@
 {
 	struct e1000_adapter *adapter = netdev->priv;
 
-	netif_device_detach(netdev);
 	e1000_down(adapter);
 	e1000_up(adapter);
-	netif_device_attach(netdev);
 }
 
 /**
@@ -1933,7 +1912,6 @@
 	}
 
 	if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
-
 		e1000_down(adapter);
 		e1000_up(adapter);
 	}
@@ -1979,8 +1957,6 @@
 	adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
 	adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
 
-	/* the rest of the counters are only modified here */
-
 	adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
 	adapter->stats.mpc += E1000_READ_REG(hw, MPC);
 	adapter->stats.scc += E1000_READ_REG(hw, SCC);
@@ -2083,6 +2059,34 @@
 }
 
 /**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_disable(struct e1000_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+	E1000_WRITE_FLUSH(&adapter->hw);
+	synchronize_irq();
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_enable(struct e1000_adapter *adapter)
+{
+	if(likely(atomic_dec_and_test(&adapter->irq_sem))) {
+		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
+		E1000_WRITE_FLUSH(&adapter->hw);
+	}
+}
+
+/**
  * e1000_intr - Interrupt Handler
  * @irq: interrupt number
  * @data: pointer to a network interface device structure
@@ -2095,21 +2099,21 @@
 	struct net_device *netdev = data;
 	struct e1000_adapter *adapter = netdev->priv;
 	struct e1000_hw *hw = &adapter->hw;
-	uint32_t icr = E1000_READ_REG(&adapter->hw, ICR);
+	uint32_t icr = E1000_READ_REG(hw, ICR);
 #ifndef CONFIG_E1000_NAPI
 	unsigned int i;
 #endif
 
-	if(!icr)
+	if(unlikely(!icr))
 		return IRQ_NONE;  /* Not our interrupt */
 
-	if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+	if(unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) {
 		hw->get_link_status = 1;
 		mod_timer(&adapter->watchdog_timer, jiffies);
 	}
 
 #ifdef CONFIG_E1000_NAPI
-	if(netif_rx_schedule_prep(netdev)) {
+	if(likely(netif_rx_schedule_prep(netdev))) {
 
 		/* Disable interrupts and register for poll. The flush 
 		  of the posted write is intentionally left out.
@@ -2121,8 +2125,8 @@
 	}
 #else
 	for(i = 0; i < E1000_MAX_INTR; i++)
-		if(!e1000_clean_rx_irq(adapter) &
-		   !e1000_clean_tx_irq(adapter))
+		if(unlikely(!e1000_clean_rx_irq(adapter) &
+		   !e1000_clean_tx_irq(adapter)))
 			break;
 #endif
 
@@ -2140,15 +2144,18 @@
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	int work_to_do = min(*budget, netdev->quota);
+	int tx_cleaned;
 	int work_done = 0;
 	
-	e1000_clean_tx_irq(adapter);
+	tx_cleaned = e1000_clean_tx_irq(adapter);
 	e1000_clean_rx_irq(adapter, &work_done, work_to_do);
 
 	*budget -= work_done;
 	netdev->quota -= work_done;
 	
-	if(work_done < work_to_do || !netif_running(netdev)) {
+	/* if no Rx and Tx cleanup work was done, exit the polling mode */
+	if(!tx_cleaned || (work_done < work_to_do) || 
+				!netif_running(netdev)) {
 		netif_rx_complete(netdev);
 		e1000_irq_enable(adapter);
 		return 0;
@@ -2156,8 +2163,8 @@
 
 	return (work_done >= work_to_do);
 }
-#endif
 
+#endif
 /**
  * e1000_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
@@ -2174,19 +2181,16 @@
 	unsigned int i, eop;
 	boolean_t cleaned = FALSE;
 
-
 	i = tx_ring->next_to_clean;
 	eop = tx_ring->buffer_info[i].next_to_watch;
 	eop_desc = E1000_TX_DESC(*tx_ring, eop);
 
 	while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
-
 		for(cleaned = FALSE; !cleaned; ) {
 			tx_desc = E1000_TX_DESC(*tx_ring, i);
 			buffer_info = &tx_ring->buffer_info[i];
 
-			if(buffer_info->dma) {
-
+			if(likely(buffer_info->dma)) {
 				pci_unmap_page(pdev,
 					       buffer_info->dma,
 					       buffer_info->length,
@@ -2196,9 +2200,7 @@
 			}
 
 			if(buffer_info->skb) {
-
 				dev_kfree_skb_any(buffer_info->skb);
-
 				buffer_info->skb = NULL;
 			}
 
@@ -2207,7 +2209,7 @@
 			tx_desc->upper.data = 0;
 
 			cleaned = (i == eop);
-			if(++i == tx_ring->count) i = 0;
+			if(unlikely(++i == tx_ring->count)) i = 0;
 		}
 		
 		eop = tx_ring->buffer_info[i].next_to_watch;
@@ -2218,7 +2220,8 @@
 
 	spin_lock(&adapter->tx_lock);
 
-	if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev))
+	if(unlikely(cleaned && netif_queue_stopped(netdev) &&
+		    netif_carrier_ok(netdev)))
 		netif_wake_queue(netdev);
 
 	spin_unlock(&adapter->tx_lock);
@@ -2227,42 +2230,7 @@
 }
 
 /**
- * e1000_rx_checksum - Receive Checksum Offload for 82543
- * @adapter: board private structure
- * @rx_desc: receive descriptor
- * @sk_buff: socket buffer with received data
- **/
-
-static inline void
-e1000_rx_checksum(struct e1000_adapter *adapter,
-                  struct e1000_rx_desc *rx_desc,
-                  struct sk_buff *skb)
-{
-	/* 82543 or newer only */
-	if((adapter->hw.mac_type < e1000_82543) ||
-	/* Ignore Checksum bit is set */
-	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
-	/* TCP Checksum has not been calculated */
-	(!(rx_desc->status & E1000_RXD_STAT_TCPCS))) {
-		skb->ip_summed = CHECKSUM_NONE;
-		return;
-	}
-
-	/* At this point we know the hardware did the TCP checksum */
-	/* now look at the TCP checksum error bit */
-	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
-		/* let the stack verify checksum errors */
-		skb->ip_summed = CHECKSUM_NONE;
-		adapter->hw_csum_err++;
-	} else {
-	/* TCP checksum is good */
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		adapter->hw_csum_good++;
-	}
-}
-
-/**
- * e1000_clean_rx_irq - Send received data up the network stack,
+ * e1000_clean_rx_irq - Send received data up the network stack
  * @adapter: board private structure
  **/
 
@@ -2291,14 +2259,11 @@
 
 	while(rx_desc->status & E1000_RXD_STAT_DD) {
 		buffer_info = &rx_ring->buffer_info[i];
-
 #ifdef CONFIG_E1000_NAPI
 		if(*work_done >= work_to_do)
 			break;
-
 		(*work_done)++;
 #endif
-
 		cleaned = TRUE;
 
 		pci_unmap_single(pdev,
@@ -2309,49 +2274,28 @@
 		skb = buffer_info->skb;
 		length = le16_to_cpu(rx_desc->length);
 
-		if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
-
+		if(unlikely(!(rx_desc->status & E1000_RXD_STAT_EOP))) {
 			/* All receives must fit into a single buffer */
-
-			E1000_DBG("%s: Receive packet consumed multiple buffers\n",
-				netdev->name);
-
+			E1000_DBG("%s: Receive packet consumed multiple"
+				  " buffers\n", netdev->name);
 			dev_kfree_skb_irq(skb);
-			rx_desc->status = 0;
-			buffer_info->skb = NULL;
-
-			if(++i == rx_ring->count) i = 0;
-
-			rx_desc = E1000_RX_DESC(*rx_ring, i);
-			continue;
+			goto next_desc;
 		}
 
-		if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
-
+		if(unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
 			last_byte = *(skb->data + length - 1);
-
 			if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
 			              rx_desc->errors, length, last_byte)) {
-
 				spin_lock_irqsave(&adapter->stats_lock, flags);
-
 				e1000_tbi_adjust_stats(&adapter->hw,
 				                       &adapter->stats,
 				                       length, skb->data);
-
 				spin_unlock_irqrestore(&adapter->stats_lock,
 				                       flags);
 				length--;
 			} else {
-
 				dev_kfree_skb_irq(skb);
-				rx_desc->status = 0;
-				buffer_info->skb = NULL;
-
-				if(++i == rx_ring->count) i = 0;
-
-				rx_desc = E1000_RX_DESC(*rx_ring, i);
-				continue;
+				goto next_desc;
 			}
 		}
 
@@ -2363,28 +2307,30 @@
 
 		skb->protocol = eth_type_trans(skb, netdev);
 #ifdef CONFIG_E1000_NAPI
-		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+		if(unlikely(adapter->vlgrp &&
+			    (rx_desc->status & E1000_RXD_STAT_VP))) {
 			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
-				le16_to_cpu(rx_desc->special &
-					E1000_RXD_SPC_VLAN_MASK));
+					le16_to_cpu(rx_desc->special) &
+					E1000_RXD_SPC_VLAN_MASK);
 		} else {
 			netif_receive_skb(skb);
 		}
 #else /* CONFIG_E1000_NAPI */
-		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+		if(unlikely(adapter->vlgrp &&
+			    (rx_desc->status & E1000_RXD_STAT_VP))) {
 			vlan_hwaccel_rx(skb, adapter->vlgrp,
-				le16_to_cpu(rx_desc->special &
-					E1000_RXD_SPC_VLAN_MASK));
+					le16_to_cpu(rx_desc->special) &
+					E1000_RXD_SPC_VLAN_MASK);
 		} else {
 			netif_rx(skb);
 		}
 #endif /* CONFIG_E1000_NAPI */
 		netdev->last_rx = jiffies;
 
+next_desc:
 		rx_desc->status = 0;
 		buffer_info->skb = NULL;
-
-		if(++i == rx_ring->count) i = 0;
+		if(unlikely(++i == rx_ring->count)) i = 0;
 
 		rx_desc = E1000_RX_DESC(*rx_ring, i);
 	}
@@ -2417,11 +2363,10 @@
 	buffer_info = &rx_ring->buffer_info[i];
 
 	while(!buffer_info->skb) {
-		rx_desc = E1000_RX_DESC(*rx_ring, i);
 
 		skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len);
 
-		if(!skb) {
+		if(unlikely(!skb)) {
 			/* Better luck next round */
 			break;
 		}
@@ -2436,15 +2381,15 @@
 
 		buffer_info->skb = skb;
 		buffer_info->length = adapter->rx_buffer_len;
-		buffer_info->dma =
-			pci_map_single(pdev,
-			               skb->data,
-			               adapter->rx_buffer_len,
-			               PCI_DMA_FROMDEVICE);
+		buffer_info->dma = pci_map_single(pdev,
+						  skb->data,
+						  adapter->rx_buffer_len,
+						  PCI_DMA_FROMDEVICE);
 
+		rx_desc = E1000_RX_DESC(*rx_ring, i);
 		rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
 
-		if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) {
+		if(unlikely((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i)) {
 			/* Force memory writes to complete before letting h/w
 			 * know there are new descriptors to fetch.  (Only
 			 * applicable for weak-ordered memory model archs,
@@ -2454,7 +2399,7 @@
 			E1000_WRITE_REG(&adapter->hw, RDT, i);
 		}
 
-		if(++i == rx_ring->count) i = 0;
+		if(unlikely(++i == rx_ring->count)) i = 0;
 		buffer_info = &rx_ring->buffer_info[i];
 	}
 
@@ -2573,22 +2518,24 @@
 			return -EFAULT;
 		mii_reg = data->val_in;
 		if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
-					data->val_in))
+					mii_reg))
 			return -EIO;
 		if (adapter->hw.phy_type == e1000_phy_m88) {
 			switch (data->reg_num) {
 			case PHY_CTRL:
-				if(data->val_in & MII_CR_AUTO_NEG_EN) {
+				if(mii_reg & MII_CR_POWER_DOWN)
+					break;
+				if(mii_reg & MII_CR_AUTO_NEG_EN) {
 					adapter->hw.autoneg = 1;
 					adapter->hw.autoneg_advertised = 0x2F;
 				} else {
-					if (data->val_in & 0x40)
+					if (mii_reg & 0x40)
 						spddplx = SPEED_1000;
-					else if (data->val_in & 0x2000)
+					else if (mii_reg & 0x2000)
 						spddplx = SPEED_100;
 					else
 						spddplx = SPEED_10;
-					spddplx += (data->val_in & 0x100)
+					spddplx += (mii_reg & 0x100)
 						   ? FULL_DUPLEX :
 						   HALF_DUPLEX;
 					retval = e1000_set_spd_dplx(adapter,
@@ -2608,6 +2555,18 @@
 					return -EIO;
 				break;
 			}
+		} else {
+			switch (data->reg_num) {
+			case PHY_CTRL:
+				if(mii_reg & MII_CR_POWER_DOWN)
+					break;
+				if(netif_running(adapter->netdev)) {
+					e1000_down(adapter);
+					e1000_up(adapter);
+				} else
+					e1000_reset(adapter);
+				break;
+			}
 		}
 		break;
 	default:
@@ -2616,12 +2575,48 @@
 	return E1000_SUCCESS;
 }
 
+/**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @rx_desc: receive descriptor
+ * @sk_buff: socket buffer with received data
+ **/
+
+static inline void
+e1000_rx_checksum(struct e1000_adapter *adapter,
+                  struct e1000_rx_desc *rx_desc,
+                  struct sk_buff *skb)
+{
+	/* 82543 or newer only */
+	if(unlikely((adapter->hw.mac_type < e1000_82543) ||
+	/* Ignore Checksum bit is set */
+	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
+	/* TCP Checksum has not been calculated */
+	(!(rx_desc->status & E1000_RXD_STAT_TCPCS)))) {
+		skb->ip_summed = CHECKSUM_NONE;
+		return;
+	}
+
+	/* At this point we know the hardware did the TCP checksum */
+	/* now look at the TCP checksum error bit */
+	if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
+		/* let the stack verify checksum errors */
+		skb->ip_summed = CHECKSUM_NONE;
+		adapter->hw_csum_err++;
+	} else {
+		/* TCP checksum is good */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		adapter->hw_csum_good++;
+	}
+}
+
 void
 e1000_pci_set_mwi(struct e1000_hw *hw)
 {
 	struct e1000_adapter *adapter = hw->back;
 
-	pci_set_mwi(adapter->pdev);
+	int ret;
+	ret = pci_set_mwi(adapter->pdev);
 }
 
 void
@@ -2671,26 +2666,22 @@
 
 	if(grp) {
 		/* enable VLAN tag insert/strip */
-
 		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
 		ctrl |= E1000_CTRL_VME;
 		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
 
 		/* enable VLAN receive filtering */
-
 		rctl = E1000_READ_REG(&adapter->hw, RCTL);
 		rctl |= E1000_RCTL_VFE;
 		rctl &= ~E1000_RCTL_CFIEN;
 		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 	} else {
 		/* disable VLAN tag insert/strip */
-
 		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
 		ctrl &= ~E1000_CTRL_VME;
 		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
 
 		/* disable VLAN filtering */
-
 		rctl = E1000_READ_REG(&adapter->hw, RCTL);
 		rctl &= ~E1000_RCTL_VFE;
 		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
@@ -2706,7 +2697,6 @@
 	uint32_t vfta, index;
 
 	/* add VID to filter table */
-
 	index = (vid >> 5) & 0x7F;
 	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
 	vfta |= (1 << (vid & 0x1F));
@@ -2726,8 +2716,7 @@
 
 	e1000_irq_enable(adapter);
 
-	/* remove VID from filter table*/
-
+	/* remove VID from filter table */
 	index = (vid >> 5) & 0x7F;
 	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
 	vfta &= ~(1 << (vid & 0x1F));
@@ -2773,6 +2762,8 @@
 		break;
 	case SPEED_1000 + DUPLEX_HALF: /* not supported */
 	default:
+		DPRINTK(PROBE, ERR, 
+			"Unsupported Speed/Duplexity configuration\n");
 		return -EINVAL;
 	}
 	return 0;
@@ -2866,6 +2857,8 @@
 		}
 	}
 
+	pci_disable_device(pdev);
+
 	state = (state > 0) ? 3 : 0;
 	pci_set_power_state(pdev, state);
 
@@ -2878,8 +2871,9 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
 	struct e1000_adapter *adapter = netdev->priv;
-	uint32_t manc;
+	uint32_t manc, ret;
 
+	ret = pci_enable_device(pdev);
 	pci_set_power_state(pdev, 0);
 	pci_restore_state(pdev, adapter->pci_state);
 
@@ -2911,12 +2905,12 @@
  * without having to re-enable interrupts. It's not called while
  * the interrupt routine is executing.
  */
-
-static void e1000_netpoll (struct net_device *dev)
+static void
+e1000_netpoll (struct net_device *netdev)
 {
-	struct e1000_adapter *adapter = dev->priv;
+	struct e1000_adapter *adapter = netdev->priv;
 	disable_irq(adapter->pdev->irq);
-	e1000_intr (adapter->pdev->irq, dev, NULL);
+	e1000_intr(adapter->pdev->irq, netdev, NULL);
 	enable_irq(adapter->pdev->irq);
 }
 #endif
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000_osdep.h linux-2.4.28-pre4/drivers/net/e1000/e1000_osdep.h
--- linux-2.4.28-pre3/drivers/net/e1000/e1000_osdep.h	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000_osdep.h	2004-10-08 06:28:25.330246308 -0700
@@ -49,6 +49,12 @@
 				set_current_state(TASK_UNINTERRUPTIBLE); \
 				schedule_timeout((x * HZ)/1000 + 2); \
 			} } while(0)
+/* Some workarounds require millisecond delays and are run during interrupt
+ * context.  Most notably, when establishing link, the phy may need tweaking
+ * but cannot process phy register reads/writes faster than millisecond
+ * intervals...and we establish link due to a "link status change" interrupt.
+ */
+#define msec_delay_irq(x) mdelay(x)
 #endif
 
 #define PCI_COMMAND_REGISTER   PCI_COMMAND
diff -urN linux-2.4.28-pre3/drivers/net/e1000/e1000_param.c linux-2.4.28-pre4/drivers/net/e1000/e1000_param.c
--- linux-2.4.28-pre3/drivers/net/e1000/e1000_param.c	2004-10-08 06:28:21.475089464 -0700
+++ linux-2.4.28-pre4/drivers/net/e1000/e1000_param.c	2004-10-08 06:28:25.332246389 -0700
@@ -34,10 +34,16 @@
 
 #define E1000_MAX_NIC 32
 
-#define OPTION_UNSET    -1
+#define OPTION_UNSET   -1
 #define OPTION_DISABLED 0
 #define OPTION_ENABLED  1
 
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
 /* Module Parameters are always initialized to -1, so that the driver
  * can tell the difference between no user specified value or the
  * user asking for the default value.
@@ -48,17 +54,10 @@
  * "Extensions to the C Language Family" of the GCC documentation.
  */
 
-#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
-
-/* All parameters are treated the same, as an integer array of values.
- * This macro just reduces the need to repeat the same declaration code
- * over and over (plus this helps to avoid typo bugs).
- */
-
-#define E1000_PARAM(X, S) \
-static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \
-MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
-MODULE_PARM_DESC(X, S);
+#define E1000_PARAM(X, desc) \
+	static const int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
+	MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
+	MODULE_PARM_DESC(X, desc);
 
 /* Transmit Descriptor Count
  *
@@ -212,7 +211,7 @@
 #define MAX_TXABSDELAY            0xFFFF
 #define MIN_TXABSDELAY                 0
 
-#define DEFAULT_ITR                 8000
+#define DEFAULT_ITR                 8000 
 #define MAX_ITR                   100000
 #define MIN_ITR                      100
 
@@ -235,7 +234,7 @@
 
 static int __devinit
 e1000_validate_option(int *value, struct e1000_option *opt,
-	struct e1000_adapter *adapter)
+		struct e1000_adapter *adapter)
 {
 	if(*value == OPTION_UNSET) {
 		*value = opt->def;
@@ -256,7 +255,7 @@
 	case range_option:
 		if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
 			DPRINTK(PROBE, INFO,
-				"%s set to %i\n", opt->name, *value);
+					"%s set to %i\n", opt->name, *value);
 			return 0;
 		}
 		break;
@@ -322,9 +321,10 @@
 		opt.arg.r.max = mac_type < e1000_82544 ?
 			E1000_MAX_TXD : E1000_MAX_82544_TXD;
 
-		tx_ring->count = TxDescriptors[bd];
-		e1000_validate_option(&tx_ring->count, &opt, adapter);
-		E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+			tx_ring->count = TxDescriptors[bd];
+			e1000_validate_option(&tx_ring->count, &opt, adapter);
+			E1000_ROUNDUP(tx_ring->count, 
+						REQ_TX_DESCRIPTOR_MULTIPLE);
 	}
 	{ /* Receive Descriptor Count */
 		struct e1000_option opt = {
@@ -340,9 +340,10 @@
 		opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
 			E1000_MAX_82544_RXD;
 
-		rx_ring->count = RxDescriptors[bd];
-		e1000_validate_option(&rx_ring->count, &opt, adapter);
-		E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+			rx_ring->count = RxDescriptors[bd];
+			e1000_validate_option(&rx_ring->count, &opt, adapter);
+			E1000_ROUNDUP(rx_ring->count, 
+						REQ_RX_DESCRIPTOR_MULTIPLE);
 	}
 	{ /* Checksum Offload Enable/Disable */
 		struct e1000_option opt = {
@@ -352,9 +353,9 @@
 			.def  = OPTION_ENABLED
 		};
 
-		int rx_csum = XsumRX[bd];
-		e1000_validate_option(&rx_csum, &opt, adapter);
-		adapter->rx_csum = rx_csum;
+			int rx_csum = XsumRX[bd];
+			e1000_validate_option(&rx_csum, &opt, adapter);
+			adapter->rx_csum = rx_csum;
 	}
 	{ /* Flow Control */
 
@@ -374,9 +375,9 @@
 					 .p = fc_list }}
 		};
 
-		int fc = FlowControl[bd];
-		e1000_validate_option(&fc, &opt, adapter);
-		adapter->hw.fc = adapter->hw.original_fc = fc;
+			int fc = FlowControl[bd];
+			e1000_validate_option(&fc, &opt, adapter);
+			adapter->hw.fc = adapter->hw.original_fc = fc;
 	}
 	{ /* Transmit Interrupt Delay */
 		struct e1000_option opt = {
@@ -388,8 +389,9 @@
 					 .max = MAX_TXDELAY }}
 		};
 
-		adapter->tx_int_delay = TxIntDelay[bd];
-		e1000_validate_option(&adapter->tx_int_delay, &opt, adapter);
+			adapter->tx_int_delay = TxIntDelay[bd];
+			e1000_validate_option(&adapter->tx_int_delay, &opt, 
+								adapter);
 	}
 	{ /* Transmit Absolute Interrupt Delay */
 		struct e1000_option opt = {
@@ -401,8 +403,9 @@
 					 .max = MAX_TXABSDELAY }}
 		};
 
-		adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
-		e1000_validate_option(&adapter->tx_abs_int_delay, &opt, adapter);
+			adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+			e1000_validate_option(&adapter->tx_abs_int_delay, &opt, 
+								adapter);
 	}
 	{ /* Receive Interrupt Delay */
 		struct e1000_option opt = {
@@ -414,8 +417,9 @@
 					 .max = MAX_RXDELAY }}
 		};
 
-		adapter->rx_int_delay = RxIntDelay[bd];
-		e1000_validate_option(&adapter->rx_int_delay, &opt, adapter);
+			adapter->rx_int_delay = RxIntDelay[bd];
+			e1000_validate_option(&adapter->rx_int_delay, &opt, 
+								adapter);
 	}
 	{ /* Receive Absolute Interrupt Delay */
 		struct e1000_option opt = {
@@ -427,8 +431,9 @@
 					 .max = MAX_RXABSDELAY }}
 		};
 
-		adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
-		e1000_validate_option(&adapter->rx_abs_int_delay, &opt, adapter);
+			adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+			e1000_validate_option(&adapter->rx_abs_int_delay, &opt, 
+								adapter);
 	}
 	{ /* Interrupt Throttling Rate */
 		struct e1000_option opt = {
@@ -440,22 +445,24 @@
 					 .max = MAX_ITR }}
 		};
 
-		adapter->itr = InterruptThrottleRate[bd];
-		switch(adapter->itr) {
-		case -1:
-			adapter->itr = 1;
-			break;
-		case 0:
-			DPRINTK(PROBE, INFO, "%s turned off\n", opt.name);
-			break;
-		case 1:
-			DPRINTK(PROBE, INFO,
-				"%s set to dynamic mode\n", opt.name);
-			break;
-		default:
-			e1000_validate_option(&adapter->itr, &opt, adapter);
-			break;
-		}
+			adapter->itr = InterruptThrottleRate[bd];
+			switch(adapter->itr) {
+			case -1:
+				adapter->itr = 1;
+				break;
+			case 0:
+				DPRINTK(PROBE, INFO, "%s turned off\n", 
+					opt.name);
+				break;
+			case 1:
+				DPRINTK(PROBE, INFO, "%s set to dynamic mode\n", 
+					opt.name);
+				break;
+			default:
+				e1000_validate_option(&adapter->itr, &opt, 
+					adapter);
+				break;
+			}
 	}
 
 	switch(adapter->hw.media_type) {
@@ -483,18 +490,20 @@
 {
 	int bd = adapter->bd_number;
 	bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
-
 	if((Speed[bd] != OPTION_UNSET)) {
 		DPRINTK(PROBE, INFO, "Speed not valid for fiber adapters, "
 		       "parameter ignored\n");
 	}
+
 	if((Duplex[bd] != OPTION_UNSET)) {
 		DPRINTK(PROBE, INFO, "Duplex not valid for fiber adapters, "
 		       "parameter ignored\n");
 	}
+
 	if((AutoNeg[bd] != OPTION_UNSET) && (AutoNeg[bd] != 0x20)) {
-		DPRINTK(PROBE, INFO, "AutoNeg other than Full/1000 is "
-		       "not valid for fiber adapters, parameter ignored\n");
+		DPRINTK(PROBE, INFO, "AutoNeg other than 1000/Full is "
+				 "not valid for fiber adapters, "
+				 "parameter ignored\n");
 	}
 }
 
@@ -527,8 +536,8 @@
 					 .p = speed_list }}
 		};
 
-		speed = Speed[bd];
-		e1000_validate_option(&speed, &opt, adapter);
+			speed = Speed[bd];
+			e1000_validate_option(&speed, &opt, adapter);
 	}
 	{ /* Duplex */
 		struct e1000_opt_list dplx_list[] = {{           0, "" },
@@ -544,8 +553,8 @@
 					 .p = dplx_list }}
 		};
 
-		dplx = Duplex[bd];
-		e1000_validate_option(&dplx, &opt, adapter);
+			dplx = Duplex[bd];
+			e1000_validate_option(&dplx, &opt, adapter);
 	}
 
 	if(AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) {
@@ -611,24 +620,24 @@
 		break;
 	case HALF_DUPLEX:
 		DPRINTK(PROBE, INFO, "Half Duplex specified without Speed\n");
-		DPRINTK(PROBE, INFO,
-			"Using Autonegotiation at Half Duplex only\n");
+		DPRINTK(PROBE, INFO, "Using Autonegotiation at "
+			"Half Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
 		                                 ADVERTISE_100_HALF;
 		break;
 	case FULL_DUPLEX:
 		DPRINTK(PROBE, INFO, "Full Duplex specified without Speed\n");
-		DPRINTK(PROBE, INFO,
-			"Using Autonegotiation at Full Duplex only\n");
+		DPRINTK(PROBE, INFO, "Using Autonegotiation at "
+			"Full Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
 		                                 ADVERTISE_100_FULL |
 		                                 ADVERTISE_1000_FULL;
 		break;
 	case SPEED_10:
-		DPRINTK(PROBE, INFO,
-			"10 Mbps Speed specified without Duplex\n");
+		DPRINTK(PROBE, INFO, "10 Mbps Speed specified "
+			"without Duplex\n");
 		DPRINTK(PROBE, INFO, "Using Autonegotiation at 10 Mbps only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
@@ -647,10 +656,10 @@
 		adapter->hw.autoneg_advertised = 0;
 		break;
 	case SPEED_100:
-		DPRINTK(PROBE, INFO,
-			"100 Mbps Speed specified without Duplex\n");
-		DPRINTK(PROBE, INFO,
-			"Using Autonegotiation at 100 Mbps only\n");
+		DPRINTK(PROBE, INFO, "100 Mbps Speed specified "
+			"without Duplex\n");
+		DPRINTK(PROBE, INFO, "Using Autonegotiation at "
+			"100 Mbps only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
 		                                 ADVERTISE_100_FULL;
@@ -668,10 +677,11 @@
 		adapter->hw.autoneg_advertised = 0;
 		break;
 	case SPEED_1000:
+		DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
+			"Duplex\n");
 		DPRINTK(PROBE, INFO,
-			"1000 Mbps Speed specified without Duplex\n");
-		DPRINTK(PROBE, INFO,
-		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+			"Using Autonegotiation at 1000 Mbps "
+			"Full Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
 		break;
@@ -679,7 +689,8 @@
 		DPRINTK(PROBE, INFO,
 			"Half Duplex is not supported at 1000 Mbps\n");
 		DPRINTK(PROBE, INFO,
-		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+			"Using Autonegotiation at 1000 Mbps "
+			"Full Duplex only\n");
 		adapter->hw.autoneg = adapter->fc_autoneg = 1;
 		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
 		break;
@@ -696,8 +707,8 @@
 	/* Speed, AutoNeg and MDI/MDI-X must all play nice */
 	if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
 		DPRINTK(PROBE, INFO,
-		       "Speed, AutoNeg and MDI-X specifications are "
-		       "incompatible. Setting MDI-X to a compatible value.\n");
+			"Speed, AutoNeg and MDI-X specifications are "
+			"incompatible. Setting MDI-X to a compatible value.\n");
 	}
 }
 
diff -urN linux-2.4.28-pre3/drivers/net/pcnet32.c linux-2.4.28-pre4/drivers/net/pcnet32.c
--- linux-2.4.28-pre3/drivers/net/pcnet32.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/net/pcnet32.c	2004-10-08 06:28:25.349247081 -0700
@@ -22,8 +22,8 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.30c"
-#define DRV_RELDATE	"05.25.2004"
+#define DRV_VERSION	"1.30h"
+#define DRV_RELDATE	"06.24.2004"
 #define PFX		DRV_NAME ": "
 
 static const char *version =
@@ -137,6 +137,7 @@
 #define MAX_UNITS 8	/* More are supported, limit only on options */
 static int options[MAX_UNITS];
 static int full_duplex[MAX_UNITS];
+static int homepna[MAX_UNITS];
 
 /*
  *				Theory of Operation
@@ -245,6 +246,14 @@
  * v1.30b  24 May 2004 Don Fry fix bogus tx carrier errors with 79c973,
  *	   assisted by Bruce Penrod <bmpenrod@endruntechnologies.com>.
  * v1.30c  25 May 2004 Don Fry added netif_wake_queue after pcnet32_restart.
+ * v1.30d  01 Jun 2004 Don Fry discard oversize rx packets.
+ * v1.30e  11 Jun 2004 Don Fry recover after fifo error and rx hang.
+ * v1.30f  16 Jun 2004 Don Fry cleanup IRQ to allow 0 and 1 for PCI,
+ * 	   expanding on suggestions from Ralf Baechle <ralf@linux-mips.org>,
+ * 	   and Brian Murphy <brian@murphy.dk>.
+ * v1.30g  22 Jun 2004 Patrick Simmons <psimmons@flash.net> added option
+ *	   homepna for selecting HomePNA mode for PCNet/Home 79C978.
+ * v1.30h  24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32.
  */
 
 
@@ -360,7 +369,7 @@
 
 static void pcnet32_probe_vlbus(void);
 static int  pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
-static int  pcnet32_probe1(unsigned long, unsigned int, int, struct pci_dev *);
+static int  pcnet32_probe1(unsigned long, int, struct pci_dev *);
 static int  pcnet32_open(struct net_device *);
 static int  pcnet32_init_ring(struct net_device *);
 static int  pcnet32_start_xmit(struct sk_buff *, struct net_device *);
@@ -957,7 +966,7 @@
 	if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) {
 	    /* check if there is really a pcnet chip on that ioaddr */
 	    if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) {
-		pcnet32_probe1(ioaddr, 0, 0, NULL);
+		pcnet32_probe1(ioaddr, 0, NULL);
 	    } else {
 		release_region(ioaddr, PCNET32_TOTAL_SIZE);
 	    }
@@ -998,7 +1007,7 @@
 	return -EBUSY;
     }
 
-    return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev);
+    return pcnet32_probe1(ioaddr, 1, pdev);
 }
 
 
@@ -1007,8 +1016,7 @@
  *  pdev will be NULL when called from pcnet32_probe_vlbus.
  */
 static int __devinit
-pcnet32_probe1(unsigned long ioaddr, unsigned int irq_line, int shared,
-		struct pci_dev *pdev)
+pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
 {
     struct pcnet32_private *lp;
     dma_addr_t lp_dma_addr;
@@ -1079,15 +1087,17 @@
 	fdx = 1;
 	/*
 	 * This is based on specs published at www.amd.com.  This section
-	 * assumes that a card with a 79C978 wants to go into 1Mb HomePNA
-	 * mode.  The 79C978 can also go into standard ethernet, and there
-	 * probably should be some sort of module option to select the
-	 * mode by which the card should operate
+	 * assumes that a card with a 79C978 wants to go into standard
+	 * ethernet mode.  The 79C978 can also go into 1Mb HomePNA mode,
+	 * and the module option homepna=1 can select this instead.
 	 */
-	/* switch to home wiring mode */
 	media = a->read_bcr(ioaddr, 49);
+	media &= ~3;		/* default to 10Mb ethernet */
+	if (cards_found < MAX_UNITS && homepna[cards_found])
+	    media |= 1; 	/* switch to home wiring mode */
 	if (pcnet32_debug & NETIF_MSG_PROBE)
-	    printk(KERN_DEBUG PFX "media reset to %#x.\n",  media);
+	    printk(KERN_DEBUG PFX "media set to %dMbit mode.\n", 
+		    (media & 1) ? 1 : 10);
 	a->write_bcr(ioaddr, 49, media);
 	break;
     case 0x2627:
@@ -1269,11 +1279,8 @@
     a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private,
 		    init_block)) >> 16);
 
-    if (irq_line) {
-	dev->irq = irq_line;
-    }
-
-    if (dev->irq >= 2) {
+    if (pdev) {		/* use the IRQ provided by PCI */
+	dev->irq = pdev->irq;
 	if (pcnet32_debug & NETIF_MSG_PROBE)
 	    printk(" assigned IRQ %d.\n", dev->irq);
     } else {
@@ -1361,8 +1368,7 @@
     int rc;
     unsigned long flags;
 
-    if (dev->irq == 0 ||
-	request_irq(dev->irq, &pcnet32_interrupt,
+    if (request_irq(dev->irq, &pcnet32_interrupt,
 		    lp->shared_irq ? SA_SHIRQ : 0, dev->name, (void *)dev)) {
 	return -EAGAIN;
     }
@@ -1416,9 +1422,13 @@
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
 
+    /* 24 Jun 2004 according AMD, in order to change the PHY,
+     * DANAS (or DISPM for 79C976) must be set; then select the speed,
+     * duplex, and/or enable auto negotiation, and clear DANAS */
     if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
+	lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
 	/* disable Auto Negotiation, set 10Mpbs, HD */
-	val = lp->a.read_bcr (ioaddr, 32) & ~0x38;
+	val = lp->a.read_bcr(ioaddr, 32) & ~0xb8;
 	if (lp->options & PCNET32_PORT_FD)
 	    val |= 0x10;
 	if (lp->options & PCNET32_PORT_100)
@@ -1426,6 +1436,7 @@
 	lp->a.write_bcr (ioaddr, 32, val);
     } else {
 	if (lp->options & PCNET32_PORT_ASEL) {
+	    lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
 	    /* enable auto negotiate, setup, disable fd */
 	    val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
 	    val |= 0x20;
@@ -1530,13 +1541,15 @@
     int i;
 
     for (i = 0; i < TX_RING_SIZE; i++) {
+	lp->tx_ring[i].status = 0;	/* CPU owns buffer */
+	wmb();	/* Make sure adapter sees owner change */
 	if (lp->tx_skbuff[i]) {
 	    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
 		    lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);
 	    dev_kfree_skb_any(lp->tx_skbuff[i]);
-	    lp->tx_skbuff[i] = NULL;
-	    lp->tx_dma_addr[i] = 0;
 	}
+	lp->tx_skbuff[i] = NULL;
+	lp->tx_dma_addr[i] = 0;
     }
 }
 
@@ -1565,21 +1578,23 @@
 	    skb_reserve (rx_skbuff, 2);
 	}
 
+	rmb();
 	if (lp->rx_dma_addr[i] == 0)
 	    lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail,
 		    PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
 	lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
 	lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
+	wmb();	/* Make sure owner changes after all others are visible */
 	lp->rx_ring[i].status = le16_to_cpu(0x8000);
     }
     /* The Tx buffer address is filled in as needed, but we do need to clear
      * the upper ownership bit. */
     for (i = 0; i < TX_RING_SIZE; i++) {
+	lp->tx_ring[i].status = 0;	/* CPU owns buffer */
+	wmb();	/* Make sure adapter sees owner change */
 	lp->tx_ring[i].base = 0;
-	lp->tx_ring[i].status = 0;
 	lp->tx_dma_addr[i] = 0;
     }
-    wmb(); /* Make sure all changes are visible */
 
     lp->init_block.tlen_rlen = le16_to_cpu(TX_RING_LEN_BITS | RX_RING_LEN_BITS);
     for (i = 0; i < 6; i++)
@@ -1588,9 +1603,14 @@
 	    offsetof(struct pcnet32_private, rx_ring));
     lp->init_block.tx_ring = (u32)le32_to_cpu(lp->dma_addr +
 	    offsetof(struct pcnet32_private, tx_ring));
+    wmb();	/* Make sure all changes are visible */
     return 0;
 }
 
+/* the pcnet32 has been issued a stop or reset.  Wait for the stop bit
+ * then flush the pending transmit operations, re-initialize the ring,
+ * and tell the chip to initialize.
+ */
 static void
 pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
 {
@@ -1598,6 +1618,15 @@
     unsigned long ioaddr = dev->base_addr;
     int i;
 
+    /* wait for stop */
+    for (i=0; i<100; i++)
+	if (lp->a.read_csr(ioaddr, 0) & 0x0004)
+	   break;
+
+    if (i >= 100 && netif_msg_drv(lp))
+	printk(KERN_ERR "%s: pcnet32_restart timed out waiting for stop.\n",
+		dev->name);
+
     pcnet32_purge_tx_ring(dev);
     if (pcnet32_init_ring(dev))
 	return;
@@ -1734,7 +1763,7 @@
     spin_lock(&lp->lock);
 
     rap = lp->a.read_rap(ioaddr);
-    while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
+    while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) {
 	if (csr0 == 0xffff) {
 	    break;			/* PCMCIA remove happened */
 	}
@@ -1856,15 +1885,16 @@
 	}
 
 	if (must_restart) {
-	    /* stop the chip to clear the error condition, then restart */
-	    lp->a.write_csr (ioaddr, 0, 0x0004);
+	    /* reset the chip to clear the error condition, then restart */
+	    lp->a.reset(ioaddr);
+	    lp->a.write_csr(ioaddr, 4, 0x0915);
 	    pcnet32_restart(dev, 0x0002);
 	    netif_wake_queue(dev);
 	}
     }
 
-    /* Clear any other interrupt, and set interrupt enable. */
-    lp->a.write_csr (ioaddr, 0, 0x7940);
+    /* Set interrupt enable. */
+    lp->a.write_csr (ioaddr, 0, 0x0040);
     lp->a.write_rap (ioaddr,rap);
 
     if (netif_msg_intr(lp))
@@ -1904,7 +1934,13 @@
 	    short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
 	    struct sk_buff *skb;
 
-	    if (pkt_len < 60) {
+	    /* Discard oversize frames. */
+	    if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+		if (netif_msg_drv(lp))
+		    printk(KERN_ERR "%s: Impossible packet size %d!\n",
+			    dev->name, pkt_len);
+		lp->stats.rx_errors++;
+	    } else if (pkt_len < 60) {
 		if (netif_msg_rx_err(lp))
 		    printk(KERN_ERR "%s: Runt packet!\n", dev->name);
 		lp->stats.rx_errors++;
@@ -2230,6 +2266,9 @@
 MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)");
+/* Module Parameter for HomePNA cards added by Patrick Simmons, 2004 */
+MODULE_PARM(homepna,"1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(homepna, DRV_NAME " mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet");
 
 MODULE_AUTHOR("Thomas Bogendoerfer");
 MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");
diff -urN linux-2.4.28-pre3/drivers/net/tg3.c linux-2.4.28-pre4/drivers/net/tg3.c
--- linux-2.4.28-pre3/drivers/net/tg3.c	2004-10-08 06:28:21.554092679 -0700
+++ linux-2.4.28-pre4/drivers/net/tg3.c	2004-10-08 06:28:25.362247610 -0700
@@ -59,8 +59,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.9"
-#define DRV_MODULE_RELDATE	"August 30, 2004"
+#define DRV_MODULE_VERSION	"3.10"
+#define DRV_MODULE_RELDATE	"September 14, 2004"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -1121,29 +1121,33 @@
 	u32 old_rx_mode = tp->rx_mode;
 	u32 old_tx_mode = tp->tx_mode;
 
-	if (local_adv & ADVERTISE_PAUSE_CAP) {
-		if (local_adv & ADVERTISE_PAUSE_ASYM) {
-			if (remote_adv & LPA_PAUSE_CAP)
-				new_tg3_flags |=
-					(TG3_FLAG_RX_PAUSE |
-					 TG3_FLAG_TX_PAUSE);
-			else if (remote_adv & LPA_PAUSE_ASYM)
-				new_tg3_flags |=
-					(TG3_FLAG_RX_PAUSE);
-		} else {
-			if (remote_adv & LPA_PAUSE_CAP)
-				new_tg3_flags |=
-					(TG3_FLAG_RX_PAUSE |
-					 TG3_FLAG_TX_PAUSE);
+	if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) {
+		if (local_adv & ADVERTISE_PAUSE_CAP) {
+			if (local_adv & ADVERTISE_PAUSE_ASYM) {
+				if (remote_adv & LPA_PAUSE_CAP)
+					new_tg3_flags |=
+						(TG3_FLAG_RX_PAUSE |
+					 	TG3_FLAG_TX_PAUSE);
+				else if (remote_adv & LPA_PAUSE_ASYM)
+					new_tg3_flags |=
+						(TG3_FLAG_RX_PAUSE);
+			} else {
+				if (remote_adv & LPA_PAUSE_CAP)
+					new_tg3_flags |=
+						(TG3_FLAG_RX_PAUSE |
+					 	TG3_FLAG_TX_PAUSE);
+			}
+		} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
+			if ((remote_adv & LPA_PAUSE_CAP) &&
+		    	(remote_adv & LPA_PAUSE_ASYM))
+				new_tg3_flags |= TG3_FLAG_TX_PAUSE;
 		}
-	} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
-		if ((remote_adv & LPA_PAUSE_CAP) &&
-		    (remote_adv & LPA_PAUSE_ASYM))
-			new_tg3_flags |= TG3_FLAG_TX_PAUSE;
-	}
 
-	tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
-	tp->tg3_flags |= new_tg3_flags;
+		tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
+		tp->tg3_flags |= new_tg3_flags;
+	} else {
+		new_tg3_flags = tp->tg3_flags;
+	}
 
 	if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
 		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
@@ -2167,7 +2171,7 @@
 					else
 						val |= 0x4010880;
 
-					tw32_f(MAC_SERDES_CFG, serdes_cfg);
+					tw32_f(MAC_SERDES_CFG, val);
 				}
 
 				tw32_f(SG_DIG_CTRL, 0x01388400);
@@ -2954,6 +2958,7 @@
 			dma_addr_t mapping, int len, u32 flags,
 			u32 mss_and_is_end)
 {
+	struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
 	int is_end = (mss_and_is_end & 0x1);
 	u32 mss = (mss_and_is_end >> 1);
 	u32 vlan_tag = 0;
@@ -2965,35 +2970,11 @@
 		flags &= 0xffff;
 	}
 	vlan_tag |= (mss << TXD_MSS_SHIFT);
-	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-		struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
-
-		txd->addr_hi = ((u64) mapping >> 32);
-		txd->addr_lo = ((u64) mapping & 0xffffffff);
-		txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
-		txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
-	} else {
-		struct tx_ring_info *txr = &tp->tx_buffers[entry];
-		unsigned long txd;
 
-		txd = (tp->regs +
-		       NIC_SRAM_WIN_BASE +
-		       NIC_SRAM_TX_BUFFER_DESC);
-		txd += (entry * TXD_SIZE);
-
-		/* Save some PIOs */
-		if (sizeof(dma_addr_t) != sizeof(u32))
-			writel(((u64) mapping >> 32),
-			       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
-
-		writel(((u64) mapping & 0xffffffff),
-		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
-		writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS);
-		if (txr->prev_vlan_tag != vlan_tag) {
-			writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
-			txr->prev_vlan_tag = vlan_tag;
-		}
-	}
+	txd->addr_hi = ((u64) mapping >> 32);
+	txd->addr_lo = ((u64) mapping & 0xffffffff);
+	txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
+	txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
 }
 
 static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
@@ -3182,19 +3163,7 @@
 	}
 
 	/* Packets are ready, update Tx producer idx local and on card. */
-	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-		tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 +
-			      TG3_64BIT_REG_LOW), entry);
-	} else {
-		/* First, make sure tg3 sees last descriptor fully
-		 * in SRAM.
-		 */
-		if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
-			tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW);
-
-		tw32_tx_mbox((MAILBOX_SNDNIC_PROD_IDX_0 +
-			      TG3_64BIT_REG_LOW), entry);
-	}
+	tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
 
 	tp->tx_prod = entry;
 	if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
@@ -3333,7 +3302,6 @@
  */
 static void tg3_init_rings(struct tg3 *tp)
 {
-	unsigned long start, end;
 	u32 i;
 
 	/* Free up all the SKBs. */
@@ -3343,21 +3311,7 @@
 	memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
 	memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
 	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp));
-
-	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-		memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
-	} else {
-		start = (tp->regs +
-			 NIC_SRAM_WIN_BASE +
-			 NIC_SRAM_TX_BUFFER_DESC);
-		end = start + TG3_TX_RING_BYTES;
-		while (start < end) {
-			writel(0, start);
-			start += 4;
-		}
-		for (i = 0; i < TG3_TX_RING_SIZE; i++)
-			tp->tx_buffers[i].prev_vlan_tag = 0;
-	}
+	memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
 
 	/* Initialize invariants of the rings, we only set this
 	 * stuff once.  This works because the card does not
@@ -3488,15 +3442,10 @@
 	if (!tp->rx_rcb)
 		goto err_out;
 
-	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-		tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES,
-						   &tp->tx_desc_mapping);
-		if (!tp->tx_ring)
-			goto err_out;
-	} else {
-		tp->tx_ring = NULL;
-		tp->tx_desc_mapping = 0;
-	}
+	tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES,
+					   &tp->tx_desc_mapping);
+	if (!tp->tx_ring)
+		goto err_out;
 
 	tp->hw_status = pci_alloc_consistent(tp->pdev,
 					     TG3_HW_STATUS_SIZE,
@@ -3747,7 +3696,7 @@
 	u32 flags_save;
 	int i;
 
-	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_5704))
+	if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
 		tg3_nvram_lock(tp);
 
 	/*
@@ -3878,7 +3827,7 @@
 		udelay(10);
 	}
 	if (i >= 100000 &&
-	    !(tp->tg3_flags2 & TG3_FLG2_SUN_5704)) {
+	    !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
 		printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
 		       "firmware will not restart magic=%08x\n",
 		       tp->dev->name, val);
@@ -4960,10 +4909,7 @@
 			  GRC_MODE_4X_NIC_SEND_RINGS |
 			  GRC_MODE_NO_TX_PHDR_CSUM |
 			  GRC_MODE_NO_RX_PHDR_CSUM);
-	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS)
-		tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
-	else
-		tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS;
+	tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
 	if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM)
 		tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
 	if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM)
@@ -5116,18 +5062,11 @@
 	tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
 	tw32_tx_mbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
 
-	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
-		tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
-			       tp->tx_desc_mapping,
-			       (TG3_TX_RING_SIZE <<
-				BDINFO_FLAGS_MAXLEN_SHIFT),
-			       NIC_SRAM_TX_BUFFER_DESC);
-	} else {
-		tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
-			       0,
-			       BDINFO_FLAGS_DISABLED,
-			       NIC_SRAM_TX_BUFFER_DESC);
-	}
+	tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
+		       tp->tx_desc_mapping,
+		       (TG3_TX_RING_SIZE <<
+			BDINFO_FLAGS_MAXLEN_SHIFT),
+		       NIC_SRAM_TX_BUFFER_DESC);
 
 	/* There is only one receive return ring on 5705/5750, no need
 	 * to explicitly disable the others.
@@ -5673,8 +5612,8 @@
 	spin_unlock(&tp->tx_lock);
 	spin_unlock_irq(&tp->lock);
 
-	/* If you move this call, make sure TG3_FLAG_HOST_TXDS in
-	 * tp->tg3_flags is accurate at that new place.
+	/* The placement of this call is tied
+	 * to the setup and use of Host TX descriptors.
 	 */
 	err = tg3_alloc_consistent(tp);
 	if (err)
@@ -6642,8 +6581,8 @@
 	struct tg3 *tp = netdev_priv(dev);
   
 	epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
-	epause->rx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_RX) != 0;
-	epause->tx_pause = (tp->tg3_flags & TG3_FLAG_PAUSE_TX) != 0;
+	epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
+	epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
 }
   
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -6658,13 +6597,13 @@
 	else
 		tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
 	if (epause->rx_pause)
-		tp->tg3_flags |= TG3_FLAG_PAUSE_RX;
+		tp->tg3_flags |= TG3_FLAG_RX_PAUSE;
 	else
-		tp->tg3_flags &= ~TG3_FLAG_PAUSE_RX;
+		tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE;
 	if (epause->tx_pause)
-		tp->tg3_flags |= TG3_FLAG_PAUSE_TX;
+		tp->tg3_flags |= TG3_FLAG_TX_PAUSE;
 	else
-		tp->tg3_flags &= ~TG3_FLAG_PAUSE_TX;
+		tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE;
 	tg3_halt(tp);
 	tg3_init_hw(tp);
 	tg3_netif_start(tp);
@@ -6856,7 +6795,7 @@
 {
 	int j;
 
-	if (tp->tg3_flags2 & TG3_FLG2_SUN_5704)
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_570X)
 		return;
 
 	tw32_f(GRC_EEPROM_ADDR,
@@ -6943,8 +6882,8 @@
 {
 	int i;
 
-	if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) {
-		printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 5704\n");
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+		printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n");
 		return -EINVAL;
 	}
 
@@ -7279,11 +7218,11 @@
 	unsigned char vpd_data[256];
 	int i;
 
-	if (tp->tg3_flags2 & TG3_FLG2_SUN_5704) {
+	if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
 		/* Sun decided not to put the necessary bits in the
 		 * NVRAM of their onboard tg3 parts :(
 		 */
-		strcpy(tp->board_part_number, "Sun 5704");
+		strcpy(tp->board_part_number, "Sun 570X");
 		return;
 	}
 
@@ -7344,27 +7283,21 @@
 }
 
 #ifdef CONFIG_SPARC64
-static int __devinit tg3_is_sun_5704(struct tg3 *tp)
+static int __devinit tg3_is_sun_570X(struct tg3 *tp)
 {
 	struct pci_dev *pdev = tp->pdev;
 	struct pcidev_cookie *pcp = pdev->sysdata;
 
 	if (pcp != NULL) {
 		int node = pcp->prom_node;
-		u32 venid, devid;
+		u32 venid;
 		int err;
 
 		err = prom_getproperty(node, "subsystem-vendor-id",
 				       (char *) &venid, sizeof(venid));
 		if (err == 0 || err == -1)
 			return 0;
-		err = prom_getproperty(node, "subsystem-id",
-				       (char *) &devid, sizeof(devid));
-		if (err == 0 || err == -1)
-			return 0;
-
-		if (venid == PCI_VENDOR_ID_SUN &&
-		    devid == PCI_DEVICE_ID_TIGON3_5704)
+		if (venid == PCI_VENDOR_ID_SUN)
 			return 1;
 	}
 	return 0;
@@ -7381,8 +7314,8 @@
 	int err;
 
 #ifdef CONFIG_SPARC64
-	if (tg3_is_sun_5704(tp))
-		tp->tg3_flags2 |= TG3_FLG2_SUN_5704;
+	if (tg3_is_sun_570X(tp))
+		tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
 #endif
 
 	/* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write
@@ -7627,23 +7560,6 @@
 	udelay(50);
 	tg3_nvram_init(tp);
 
-	/* Always use host TXDs, it performs better in particular
-	 * with multi-frag packets.  The tests below are kept here
-	 * as documentation should we change this decision again
-	 * in the future.
-	 */
-	tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
-
-#if 0
-	/* Determine if TX descriptors will reside in
-	 * main memory or in the chip SRAM.
-	 */
-	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
-		tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
-#endif
-
 	grc_misc_cfg = tr32(GRC_MISC_CFG);
 	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
 
@@ -7781,7 +7697,7 @@
 
 	mac_offset = 0x7c;
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
-	    !(tp->tg3_flags & TG3_FLG2_SUN_5704)) {
+	    !(tp->tg3_flags & TG3_FLG2_SUN_570X)) {
 		if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
 			mac_offset = 0xcc;
 		if (tg3_nvram_lock(tp))
@@ -7803,7 +7719,7 @@
 		dev->dev_addr[5] = (lo >>  0) & 0xff;
 	}
 	/* Next, try NVRAM. */
-	else if (!(tp->tg3_flags & TG3_FLG2_SUN_5704) &&
+	else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) &&
 		 !tg3_nvram_read(tp, mac_offset + 0, &hi) &&
 		 !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
 		dev->dev_addr[0] = ((hi >> 16) & 0xff);
@@ -8408,6 +8324,9 @@
 	if (tp->tg3_flags2 & TG3_FLG2_IS_5788)
 		dev->features &= ~NETIF_F_HIGHDMA;
 
+	/* flow control autonegotiation is default behavior */
+	tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+
 	err = register_netdev(dev);
 	if (err) {
 		printk(KERN_ERR PFX "Cannot register net device, "
@@ -8439,11 +8358,10 @@
 		printk("%2.2x%c", dev->dev_addr[i],
 		       i == 5 ? '\n' : ':');
 
-	printk(KERN_INFO "%s: HostTXDS[%d] RXcsums[%d] LinkChgREG[%d] "
+	printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] "
 	       "MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] "
 	       "TSOcap[%d] \n",
 	       dev->name,
-	       (tp->tg3_flags & TG3_FLAG_HOST_TXDS) != 0,
 	       (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
 	       (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
 	       (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
diff -urN linux-2.4.28-pre3/drivers/net/tg3.h linux-2.4.28-pre4/drivers/net/tg3.h
--- linux-2.4.28-pre3/drivers/net/tg3.h	2004-10-08 06:28:21.556092760 -0700
+++ linux-2.4.28-pre4/drivers/net/tg3.h	2004-10-08 06:28:25.364247691 -0700
@@ -1549,7 +1549,7 @@
  * exist only in the cards on-chip SRAM.  All 16 send bds are under
  * the same mode, they may not be configured individually.
  *
- * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags.
+ * This driver always uses host memory TX descriptors.
  *
  * To use host memory TX descriptors:
  *	1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register.
@@ -2005,7 +2005,6 @@
 
 	spinlock_t			tx_lock;
 
-	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
 	struct tg3_tx_buffer_desc	*tx_ring;
 	struct tx_ring_info		*tx_buffers;
 	dma_addr_t			tx_desc_mapping;
@@ -2041,7 +2040,6 @@
 
 	u32				rx_offset;
 	u32				tg3_flags;
-#define TG3_FLAG_HOST_TXDS		0x00000001
 #define TG3_FLAG_TXD_MBOX_HWBUG		0x00000002
 #define TG3_FLAG_RX_CHECKSUMS		0x00000004
 #define TG3_FLAG_USE_LINKCHG_REG	0x00000008
@@ -2071,15 +2069,13 @@
 #define TG3_FLAG_JUMBO_ENABLE		0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
-#define TG3_FLAG_PAUSE_RX		0x04000000
-#define TG3_FLAG_PAUSE_TX		0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
 #define TG3_FLAG_GOT_SERDES_FLOWCTL	0x20000000
 #define TG3_FLAG_SPLIT_MODE		0x40000000
 #define TG3_FLAG_INIT_COMPLETE		0x80000000
 	u32				tg3_flags2;
 #define TG3_FLG2_RESTART_TIMER		0x00000001
-#define TG3_FLG2_SUN_5704		0x00000002
+#define TG3_FLG2_SUN_570X		0x00000002
 #define TG3_FLG2_NO_ETH_WIRE_SPEED	0x00000004
 #define TG3_FLG2_IS_5788		0x00000008
 #define TG3_FLG2_MAX_RXPEND_64		0x00000010
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_38xx.c linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_38xx.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_38xx.c	2004-10-08 06:28:21.606094794 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_38xx.c	2004-10-08 06:28:25.372248017 -0700
@@ -133,8 +133,8 @@
 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
 		udelay(ISL38XX_WRITEIO_DELAY);
 
-		if (reg = readl(device_base + ISL38XX_INT_IDENT_REG),
-		    reg == 0xabadface) {
+		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
+		if (reg == 0xabadface) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
 			do_gettimeofday(&current_time);
 			DEBUG(SHOW_TRACING,
@@ -192,10 +192,8 @@
 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");
+	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
 #endif
 
 	/* load the address of the control block in the device */
@@ -203,8 +201,7 @@
 	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);
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);
 
 	/* enable the interrupt for detecting initialization */
@@ -212,9 +209,7 @@
 	/* 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);
+	isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
 }
 
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_38xx.h linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_38xx.h
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_38xx.h	2004-10-08 06:28:21.607094835 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_38xx.h	2004-10-08 06:28:25.373248058 -0700
@@ -95,6 +95,10 @@
 #define ISL38XX_INT_SOURCES                     0x001E
 
 /* Control/Status register bits */
+/* Looks like there are other meaningful bits
+    0x20004400 seen in normal operation,
+    0x200044db at 'timeout waiting for mgmt response'
+*/
 #define ISL38XX_CTRL_STAT_SLEEPMODE             0x00000200
 #define	ISL38XX_CTRL_STAT_CLKRUN		0x00800000
 #define ISL38XX_CTRL_STAT_RESET                 0x10000000
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_ioctl.c linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_ioctl.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_ioctl.c	2004-10-08 06:28:21.611094998 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_ioctl.c	2004-10-08 06:28:25.377248220 -0700
@@ -36,38 +36,6 @@
 
 #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
@@ -141,36 +109,34 @@
 void
 prism54_mib_init(islpci_private *priv)
 {
-	u32 t;
+	u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
 	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);
-
+	channel = CARD_DEFAULT_CHANNEL;
+	authen = CARD_DEFAULT_AUTHEN;
+	wep = CARD_DEFAULT_WEP;
+	filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
+	dot1x = CARD_DEFAULT_DOT1X; 
+	mlme = CARD_DEFAULT_MLME_MODE;
+	conformance = CARD_DEFAULT_CONFORMANCE;
+	power = 127;
+	mode = CARD_DEFAULT_IW_MODE;
+
+	mgt_set(priv, DOT11_OID_CHANNEL, &channel);
+	mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
+	mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &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;
-	}
+	mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
+	mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
+	mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
+	mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
+
 	/* This sets all of the mode-dependent values */
-	prism54_mib_mode_helper(priv, init_mode);
+	prism54_mib_mode_helper(priv, mode);
 }
 
 /* this will be executed outside of atomic context thanks to
@@ -374,7 +340,10 @@
 
 	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
 
-	mgt_commit(priv);
+	if (mgt_commit(priv)) {
+		up_write(&priv->mib_sem);
+		return -EIO;
+	}
 	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
 	    ? priv->monitor_type : ARPHRD_ETHER;
 	up_write(&priv->mib_sem);
@@ -485,6 +454,15 @@
 	/* txpower is supported in dBm's */
 	range->txpower_capa = IW_TXPOW_DBM;
 
+#if WIRELESS_EXT > 16
+	/* Event capability (kernel + driver) */
+	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+	IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+	IW_EVENT_CAPA_MASK(SIOCGIWAP));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+	range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
+#endif /* WIRELESS_EXT > 16 */
+
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
 		return 0;
 
@@ -629,8 +607,8 @@
 	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.u.freq.m = bss->channel;
+	iwe.u.freq.e = 6;
 	iwe.cmd = SIOCGIWFREQ;
 	current_ev =
 	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
@@ -690,19 +668,33 @@
 	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.
-	 */
+	/* Ask the device for a list of known bss.
+	* The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
+	* The new API, using SIOCGIWSCAN, is only limited by the buffer size.
+	* WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
+	* Starting with WE-17, the buffer can be as big as needed.
+	* 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++)
+	for (i = 0; i < (int) bsslist->nr; i++) {
 		current_ev = prism54_translate_bss(ndev, current_ev,
-						   extra + IW_SCAN_MAX_DATA,
+						   extra + dwrq->length,
 						   &(bsslist->bsslist[i]),
 						   noise);
+#if WIRELESS_EXT > 16
+		/* Check if there is space for one more entry */
+		if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
+			/* Ask user space to try again with a bigger buffer */
+			rvalue = -E2BIG;
+			break;
+		}
+#endif /* WIRELESS_EXT > 16 */
+	}
+
 	kfree(bsslist);
 	dwrq->length = (current_ev - extra);
 	dwrq->flags = 0;	/* todo */
@@ -1412,7 +1404,10 @@
 		mlmeautolevel = DOT11_MLME_EXTENDED;
 	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
 	/* restart the card with our new policy */
-	mgt_commit(priv);
+	if (mgt_commit(priv)) {
+		up_write(&priv->mib_sem);
+		return -EIO;
+	}
 	up_write(&priv->mib_sem);
 
 	return 0;
@@ -1746,11 +1741,13 @@
 			    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;
+	struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
+	struct obj_mlmeex *confirm;
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	int wpa_ie_len;
+	size_t len = 0; /* u16, better? */
+	u8 *payload = 0, *pos = 0;
+	int ret;
 
 	/* I think all trapable objects are listed here.
 	 * Some oids have a EX version. The difference is that they are emitted
@@ -1760,9 +1757,14 @@
 	 * suited. We use the more flexible custom event facility.
 	 */
 
+	if (oid >= DOT11_OID_BEACON) {
+		len = mlmeex->size;
+		payload = pos = mlmeex->data;
+	}
+
 	/* 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,
+		prism54_process_bss_data(priv, oid, mlmeex->address,
 					 payload, len);
 
 	mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
@@ -1822,21 +1824,134 @@
 
 	case DOT11_OID_AUTHENTICATEEX:
 		handle_request(priv, mlme, oid);
-		send_formatted_event(priv, "Authenticate request", mlme, 1);
+		send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
+
+		if (priv->iw_mode != IW_MODE_MASTER 
+				&& mlmeex->state != DOT11_STATE_AUTHING)
+			break;
+
+		confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
+
+		if (!confirm) 
+			break;
+
+		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+		printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+				mlmeex->address[0],
+				mlmeex->address[1],
+				mlmeex->address[2],
+				mlmeex->address[3],
+				mlmeex->address[4],
+				mlmeex->address[5]
+				);
+		confirm->id = -1; /* or mlmeex->id ? */
+		confirm->state = 0; /* not used */
+		confirm->code = 0;
+		confirm->size = 6;
+		confirm->data[0] = 0x00;
+		confirm->data[1] = 0x00;
+		confirm->data[2] = 0x02;
+		confirm->data[3] = 0x00;
+		confirm->data[4] = 0x00;
+		confirm->data[5] = 0x00;
+
+		ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
+
+		kfree(confirm);
+		if (ret)
+			return ret;
 		break;
 
 	case DOT11_OID_DISASSOCIATEEX:
-		send_formatted_event(priv, "Disassociate request", mlme, 0);
+		send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
 		break;
 
 	case DOT11_OID_ASSOCIATEEX:
 		handle_request(priv, mlme, oid);
-		send_formatted_event(priv, "Associate request", mlme, 1);
+		send_formatted_event(priv, "Associate request (ex)", mlme, 1);
+
+		if (priv->iw_mode != IW_MODE_MASTER 
+				&& mlmeex->state != DOT11_STATE_AUTHING)
+			break;
+		
+		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+
+		if (!confirm)
+			break;
+
+		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+
+		confirm->id = ((struct obj_mlmeex *)mlme)->id;
+		confirm->state = 0; /* not used */
+		confirm->code = 0;
+
+		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+
+		if (!wpa_ie_len) {
+			printk(KERN_DEBUG "No WPA IE found from "
+					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+				mlmeex->address[0],
+				mlmeex->address[1],
+				mlmeex->address[2],
+				mlmeex->address[3],
+				mlmeex->address[4],
+				mlmeex->address[5]
+				);
+			kfree(confirm);
+			break;
+		}
+
+		confirm->size = wpa_ie_len;
+		memcpy(&confirm->data, wpa_ie, wpa_ie_len);
+
+		mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
+
+		kfree(confirm);
+		
 		break;
 
 	case DOT11_OID_REASSOCIATEEX:
 		handle_request(priv, mlme, oid);
-		send_formatted_event(priv, "Reassociate request", mlme, 1);
+		send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
+
+		if (priv->iw_mode != IW_MODE_MASTER 
+				&& mlmeex->state != DOT11_STATE_ASSOCING)
+			break;
+
+		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+
+		if (!confirm)
+			break;
+
+		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+
+		confirm->id = mlmeex->id;
+		confirm->state = 0; /* not used */
+		confirm->code = 0;
+
+		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+
+		if (!wpa_ie_len) {
+			printk(KERN_DEBUG "No WPA IE found from "
+					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+				mlmeex->address[0],
+				mlmeex->address[1],
+				mlmeex->address[2],
+				mlmeex->address[3],
+				mlmeex->address[4],
+				mlmeex->address[5]
+				);
+			kfree(confirm);
+			break;
+		}
+
+		confirm->size = wpa_ie_len; 
+		memcpy(&confirm->data, wpa_ie, wpa_ie_len);
+
+		mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
+
+		kfree(confirm);
+		
 		break;
 
 	default:
@@ -1879,23 +1994,367 @@
 	return ret;
 }
 
+/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
+ * support. This is to be replaced with Linux wireless extensions once they
+ * get WPA support. */
+
+/* Note II: please leave all this together as it will be easier to remove later,
+ * once wireless extensions add WPA support -mcgrof */
+
+/* PRISM54_HOSTAPD ioctl() cmd: */
+enum {
+	PRISM2_SET_ENCRYPTION = 6,
+	PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+	PRISM2_HOSTAPD_MLME = 13,
+	PRISM2_HOSTAPD_SCAN_REQ = 14,
+};
+
+#define PRISM54_SET_WPA			SIOCIWFIRSTPRIV+12
+#define PRISM54_HOSTAPD			SIOCIWFIRSTPRIV+25
+#define PRISM54_DROP_UNENCRYPTED	SIOCIWFIRSTPRIV+26
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) 
+ * used in ioctl() */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+	
+struct prism2_hostapd_param {
+	u32 cmd;
+	u8 sta_addr[ETH_ALEN];
+	union {
+	       struct {
+		       u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+		       u32 flags;
+		       u32 err;
+		       u8 idx;
+		       u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+		       u16 key_len;
+		       u8 key[0];
+		       } crypt;
+               struct {
+                       u8 len;
+                       u8 data[0];
+               } generic_elem;
+               struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+                       u16 cmd;
+                       u16 reason_code;
+               } mlme;
+               struct {
+                       u8 ssid_len;
+                       u8 ssid[32];
+               } scan_req;
+       } u;
+};
+
+
+static int
+prism2_ioctl_set_encryption(struct net_device *dev,
+	struct prism2_hostapd_param *param,
+	int param_len)
+{
+	islpci_private *priv = netdev_priv(dev);
+	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 (param->u.crypt.key_len > 0) {
+		/* we have a key to set */
+		int index = param->u.crypt.idx;
+		int current_index;
+		struct obj_key key = { DOT11_PRIV_TKIP, 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 (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
+			key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
+			    sizeof (param->u.crypt.key) : param->u.crypt.key_len;
+			memcpy(key.key, param->u.crypt.key, 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 = (param->u.crypt.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 (!param->u.crypt.flags & IW_ENCODE_MODE) {
+				/* we cannot do anything. Complain. */
+				return -EINVAL;
+			}
+		}
+	}
+	/* now read the flags */
+	if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
+		/* Encoding disabled, 
+		 * authen = DOT11_AUTH_OS;
+		 * invoke = 0;
+		 * exunencrypt = 0; */
+	}
+	if (param->u.crypt.flags & IW_ENCODE_OPEN)
+		/* Encode but accept non-encoded packets. No auth */
+		invoke = 1;
+	if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
+		/* Refuse non-encoded packets. Auth */
+		authen = DOT11_AUTH_BOTH;
+		invoke = 1;
+		exunencrypt = 1;
+	}
+	/* do the change if requested  */
+	if ((param->u.crypt.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
+prism2_ioctl_set_generic_element(struct net_device *ndev,
+	struct prism2_hostapd_param *param,
+	int param_len)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       int max_len, len, alen, ret=0;
+       struct obj_attachment *attach;
+
+       len = param->u.generic_elem.len;
+       max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+       if (max_len < 0 || max_len < len)
+               return -EINVAL;
+
+       alen = sizeof(*attach) + len;
+       attach = kmalloc(alen, GFP_KERNEL);
+       if (attach == NULL)
+               return -ENOMEM;
+
+       memset(attach, 0, alen);
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+       /* Note: endianness is covered by mgt_set_varlen */
+
+       attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+               (WLAN_FC_STYPE_ASSOC_REQ << 4);
+       attach->id = -1;
+       attach->size = len;
+       memcpy(attach->data, param->u.generic_elem.data, len);
+
+       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
+
+       if (ret == 0) {
+               attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+                       (WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+	       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
+
+	       if (ret == 0) 
+		       printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+				       ndev->name);
+       }
+
+       kfree(attach);
+       return ret;
+
+}
+
+static int
+prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+prism2_ioctl_scan_req(struct net_device *ndev,
+                     struct prism2_hostapd_param *param)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int i, rvalue;
+	struct obj_bsslist *bsslist;
+	u32 noise = 0;
+	char *extra = "";
+	char *current_ev = "foo";
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT) {
+		/* device is not ready, fail gently */
+		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);
+
+	return rvalue;
+}
+
+static int
+prism54_hostapd(struct net_device *ndev, struct iw_point *p)
+{
+       struct prism2_hostapd_param *param;
+       int ret = 0;
+       u32 uwrq;
+
+       printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
+       if (p->length < sizeof(struct prism2_hostapd_param) ||
+           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
+               return -EINVAL;
+
+       param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, p->pointer, p->length)) {
+               kfree(param);
+               return -EFAULT;
+       }
+
+       switch (param->cmd) {
+       case PRISM2_SET_ENCRYPTION:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
+			       ndev->name);
+               ret = prism2_ioctl_set_encryption(ndev, param, p->length);
+               break;
+       case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
+			       ndev->name);
+               ret = prism2_ioctl_set_generic_element(ndev, param,
+                                                      p->length);
+               break;
+       case PRISM2_HOSTAPD_MLME:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
+			       ndev->name);
+               ret = prism2_ioctl_mlme(ndev, param);
+               break;
+       case PRISM2_HOSTAPD_SCAN_REQ:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
+			       ndev->name);
+               ret = prism2_ioctl_scan_req(ndev, param);
+               break;
+	case PRISM54_SET_WPA:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
+			       ndev->name);
+	       uwrq = 1;
+	       ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
+	       break;
+	case PRISM54_DROP_UNENCRYPTED:
+	       printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
+			       ndev->name);
+#if 0
+	       uwrq = 0x01;
+	       mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
+	       down_write(&priv->mib_sem);
+	       mgt_commit(priv);
+	       up_write(&priv->mib_sem);
+#endif
+	       /* Not necessary, as set_wpa does it, should we just do it here though? */
+	       ret = 0;
+	       break;
+       default:
+	       printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
+			       ndev->name);
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+               ret = -EFAULT;
+
+       kfree(param);
+
+       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);
+	u32 mlme, authen, dot1x, filter, wep;
 
-	down_write(&priv->mib_sem);
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	wep = 1; /* For privacy invoked */
+	filter = 1; /* Filter out all unencrypted frames */
+	dot1x = 0x01; /* To enable eap filter */
+	mlme = DOT11_MLME_EXTENDED;
+	authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
 
+	down_write(&priv->mib_sem);
 	priv->wpa = *uwrq;
-	if (priv->wpa) {
-		u32 l = DOT11_MLME_EXTENDED;
-		mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l);
+
+	switch (priv->wpa) {
+		default:
+		case 0: /* Clears/disables WPA and friends */
+			wep = 0;
+			filter = 0; /* Do not filter un-encrypted data */
+			dot1x = 0;
+			mlme = DOT11_MLME_AUTO;
+			printk("%s: Disabling WPA\n", ndev->name);
+			break;
+		case 2: 
+		case 1: /* WPA */
+			printk("%s: Enabling WPA\n", ndev->name);
+			break;
 	}
-	/* restart the card with new level. Needed ? */
-	mgt_commit(priv);
 	up_write(&priv->mib_sem);
 
+	mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+	mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
+	mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
+	mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+	mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
+
 	return 0;
 }
 
@@ -1947,7 +2406,7 @@
 		      struct iw_point *data, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	struct islpci_mgmtframe *response = NULL;
+	struct islpci_mgmtframe *response;
 	int ret = -EIO;
 
 	printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
@@ -1983,7 +2442,7 @@
 		      struct iw_point *data, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	struct islpci_mgmtframe *response = NULL;
+	struct islpci_mgmtframe *response;
 	int ret = 0, response_op = PIMFOR_OP_ERROR;
 
 	printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
@@ -2256,14 +2715,24 @@
 	.standard = (iw_handler *) prism54_handler,
 	.private = (iw_handler *) prism54_private_handler,
 	.private_args = (struct iw_priv_args *) prism54_private_args,
+#if WIRELESS_EXT == 16
 	.spy_offset = offsetof(islpci_private, spy_data),
+#endif /* WIRELESS_EXT == 16 */
 };
 
-/* For ioctls that don't work with the new API */
+/* For wpa_supplicant */
 
 int
 prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 {
-
+	struct iwreq *wrq = (struct iwreq *) rq;
+	int ret = -1;
+	switch (cmd) {
+		case PRISM54_HOSTAPD:
+		if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+		ret = prism54_hostapd(ndev, &wrq->u.data);
+		return ret;
+	}
 	return -EOPNOTSUPP;
 }
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_ioctl.h linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_ioctl.h
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_ioctl.h	2004-10-08 06:28:21.612095038 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_ioctl.h	2004-10-08 06:28:25.378248261 -0700
@@ -48,6 +48,8 @@
 int prism54_set_mac_address(struct net_device *, void *);
 
 int prism54_ioctl(struct net_device *, struct ifreq *, int);
+int prism54_set_wpa(struct net_device *, struct iw_request_info *, 
+			__u32 *, char *);
 
 extern const struct iw_handler_def prism54_handler_def;
 
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_oid.h linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_oid.h
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/isl_oid.h	2004-10-08 06:28:21.613095079 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/isl_oid.h	2004-10-08 06:28:25.380248342 -0700
@@ -91,6 +91,14 @@
 	u16 mhz[0];
 } __attribute__ ((packed));
 
+struct obj_attachment {
+	char type;
+	char reserved;
+	short id;
+	short size;
+	char data[0];
+} __attribute__((packed));
+
 /* 
  * in case everything's ok, the inlined function below will be
  * optimized away by the compiler...
@@ -472,6 +480,7 @@
 #define OID_TYPE_MLMEEX		0x09
 #define OID_TYPE_ADDR		0x0A
 #define OID_TYPE_RAW		0x0B
+#define OID_TYPE_ATTACH		0x0C
 
 /* OID_TYPE_MLMEEX is special because of a variable size field when sending.
  * Not yet implemented (not used in driver anyway).
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_dev.c linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_dev.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_dev.c	2004-10-08 06:28:21.615095160 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_dev.c	2004-10-08 06:28:25.382248424 -0700
@@ -105,7 +105,7 @@
 			       "%s: firmware '%s' size is not multiple of 32bit, aborting!\n",
 			       "prism54", priv->firmware);
 			release_firmware(fw_entry);
-			return EILSEQ; /* Illegal byte sequence  */;
+			return -EILSEQ; /* Illegal byte sequence  */;
 		}
 
 		while (fw_len > 0) {
@@ -142,6 +142,10 @@
 
 		BUG_ON(fw_len != 0);
 
+		/* Firmware version is at offset 40 (also for "newmac") */
+		printk(KERN_DEBUG "%s: firmware version: %.8s\n",
+		       priv->ndev->name, fw_entry->data + 40);
+
 		release_firmware(fw_entry);
 	}
 
@@ -375,8 +379,6 @@
 	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) {
@@ -462,8 +464,7 @@
 		return rc;
 	}
 
-	printk(KERN_DEBUG
-	       "%s: firmware uploaded done, now triggering reset...\n",
+	printk(KERN_DEBUG "%s: firmware upload complete\n",
 	       priv->ndev->name);
 
 	islpci_set_state(priv, PRV_STATE_POSTBOOT);
@@ -489,6 +490,7 @@
 		/* The software reset acknowledge needs about 220 msec here.
 		 * Be conservative and wait for up to one second. */
 	
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		remaining = schedule_timeout(HZ);
 
 		if(remaining > 0) {
@@ -499,15 +501,16 @@
 		/* 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);
-
+		printk(KERN_ERR "%s: no 'reset complete' IRQ seen - retrying\n",
+			priv->ndev->name);
 	}
 
 	finish_wait(&priv->reset_done, &wait);
 
-	if(result)
+	if (result) {
+		printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
 		return result;
+	}
 
 	islpci_set_state(priv, PRV_STATE_INIT);
 
@@ -519,11 +522,17 @@
 	isl38xx_enable_common_interrupts(priv->device_base);
 
 	down_write(&priv->mib_sem);
-	mgt_commit(priv);
+	result = mgt_commit(priv);
+	if (result) {
+		printk(KERN_ERR "%s: interface reset failure\n", priv->ndev->name);
+		up_write(&priv->mib_sem);
+		return result;
+	}
 	up_write(&priv->mib_sem);
 
 	islpci_set_state(priv, PRV_STATE_READY);
 
+	printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name);
 	return 0;
 }
 
@@ -584,18 +593,18 @@
 	/* now that the data structures are cleaned up, upload
 	 * firmware and reset interface */
 		rc = islpci_upload_fw(priv);
-		if (rc) 
+		if (rc) {
+			printk(KERN_ERR "%s: islpci_reset: failure\n",
+				priv->ndev->name);
 			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");
+	if (rc)
+		printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
 	return rc;
-
 }
 
 struct net_device_stats *
@@ -604,7 +613,7 @@
 	islpci_private *priv = netdev_priv(ndev);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-	DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n");
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
 #endif
 
 	return &priv->statistics;
@@ -830,6 +839,12 @@
 	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
 		priv->monitor_type : ARPHRD_ETHER;
 
+#if WIRELESS_EXT > 16
+	/* Add pointers to enable iwspy support. */
+	priv->wireless_data.spy_data = &priv->spy_data;
+	ndev->wireless_data = &priv->wireless_data;
+#endif /* WIRELESS_EXT > 16 */
+
 	/* 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;
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_dev.h linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_dev.h
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_dev.h	2004-10-08 06:28:21.616095201 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_dev.h	2004-10-08 06:28:25.383248464 -0700
@@ -100,6 +100,10 @@
 
 	struct iw_spy_data spy_data; /* iwspy support */
 
+#if WIRELESS_EXT > 16
+	struct iw_public_data wireless_data;
+#endif /* WIRELESS_EXT > 16 */
+
 	int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
 
 	struct islpci_acl acl;
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_eth.c linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_eth.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_eth.c	2004-10-08 06:28:21.618095282 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_eth.c	2004-10-08 06:28:25.384248505 -0700
@@ -508,11 +508,12 @@
 	/* increment the transmit error counter */
 	statistics->tx_errors++;
 
+	printk(KERN_WARNING "%s: tx_timeout", ndev->name);
 	if (!priv->reset_task_pending) {
 		priv->reset_task_pending = 1;
+		printk(", scheduling a reset");
 		netif_stop_queue(ndev);
 		schedule_work(&priv->reset_task);
 	}
-
-	return;
+	printk("\n");
 }
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_hotplug.c linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_hotplug.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_hotplug.c	2004-10-08 06:28:21.619095323 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_hotplug.c	2004-10-08 06:28:25.386248586 -0700
@@ -107,9 +107,6 @@
 	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);
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_mgt.c linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_mgt.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_mgt.c	2004-10-08 06:28:21.621095404 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_mgt.c	2004-10-08 06:28:25.388248668 -0700
@@ -473,6 +473,7 @@
 		int timeleft;
 		struct islpci_mgmtframe *frame;
 
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		timeleft = schedule_timeout(wait_cycle_jiffies);
 		frame = xchg(&priv->mgmt_received, NULL);
 		if (frame) {
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_mgt.h linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_mgt.h
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/islpci_mgt.h	2004-10-08 06:28:21.622095445 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/islpci_mgt.h	2004-10-08 06:28:25.389248709 -0700
@@ -31,8 +31,6 @@
 #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 */
 
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/oid_mgt.c linux-2.4.28-pre4/drivers/net/wireless/prism54/oid_mgt.c
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/oid_mgt.c	2004-10-08 06:28:21.624095527 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/oid_mgt.c	2004-10-08 06:28:25.391248790 -0700
@@ -201,7 +201,8 @@
 	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),
+	[DOT11_OID_ATTACHMENT] = {0x19000003, 0,
+		sizeof(struct obj_attachment), OID_TYPE_ATTACH},
 	OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
 		     OID_TYPE_BUFFER),
 
@@ -329,6 +330,12 @@
 			mlme->size = le16_to_cpu(mlme->size);
 			break;
 		}
+	case OID_TYPE_ATTACH:{
+			struct obj_attachment *attach = data;
+			attach->id = le16_to_cpu(attach->id);
+			attach->size = le16_to_cpu(attach->size);; 
+			break;
+	}
 	case OID_TYPE_SSID:
 	case OID_TYPE_KEY:
 	case OID_TYPE_ADDR:
@@ -392,6 +399,12 @@
 			mlme->size = cpu_to_le16(mlme->size);
 			break;
 		}
+	case OID_TYPE_ATTACH:{
+			struct obj_attachment *attach = data;
+			attach->id = cpu_to_le16(attach->id);
+			attach->size = cpu_to_le16(attach->size);; 
+			break;
+	}
 	case OID_TYPE_SSID:
 	case OID_TYPE_KEY:
 	case OID_TYPE_ADDR:
@@ -465,6 +478,42 @@
 	return ret;
 }
 
+/* None of these are cached */
+int
+mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len)
+{
+	int ret = 0;
+	struct islpci_mgmtframe *response;
+	int response_op = PIMFOR_OP_ERROR;
+	int dlen;
+	u32 oid;
+
+	BUG_ON(OID_NUM_LAST <= n);
+
+	dlen = isl_oid[n].size;
+	oid = isl_oid[n].oid;
+
+	mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
+	if (islpci_get_state(priv) >= PRV_STATE_READY) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
+					     data, dlen + extra_len, &response);
+		if (!ret) {
+			response_op = response->header->operation;
+			islpci_mgt_release(response);
+		}
+		if (ret || response_op == PIMFOR_OP_ERROR)
+			ret = -EIO;
+	} else 
+		ret = -EIO;
+
+	/* 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)
@@ -555,15 +604,18 @@
 		u32 oid = t->oid;
 		BUG_ON(data == NULL);
 		while (j <= t->range) {
-			response = NULL;
-			ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+			int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
 						      oid, data, t->size,
 						      &response);
 			if (response) {
-				ret |= (response->header->operation ==
-					PIMFOR_OP_ERROR);
+				r |= (response->header->operation == PIMFOR_OP_ERROR);
 				islpci_mgt_release(response);
 			}
+			if (r)
+				printk(KERN_ERR "%s: mgt_commit_list: failure. "
+					"oid=%08x err=%d\n",
+					priv->ndev->name, oid, r);
+			ret |= r;
 			j++;
 			oid++;
 			data += t->size;
@@ -624,7 +676,7 @@
 static int
 mgt_update_addr(islpci_private *priv)
 {
-	struct islpci_mgmtframe *res = NULL;
+	struct islpci_mgmtframe *res;
 	int ret;
 
 	ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
@@ -638,26 +690,26 @@
 	if (res)
 		islpci_mgt_release(res);
 
+	if (ret)
+		printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name);
 	return ret;
 }
 
-void
+#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+int
 mgt_commit(islpci_private *priv)
 {
 	int rvalue;
 	u32 u;
 
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
-		return;
+		return 0;
 
-	rvalue = mgt_commit_list(priv, commit_part1,
-				 sizeof (commit_part1) /
-				 sizeof (commit_part1[0]));
+	rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1));
 
 	if (priv->iw_mode != IW_MODE_MONITOR)
-		rvalue |= mgt_commit_list(priv, commit_part2,
-					  sizeof (commit_part2) /
-					  sizeof (commit_part2[0]));
+		rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2));
 
 	u = OID_INL_MODE;
 	rvalue |= mgt_commit_list(priv, &u, 1);
@@ -666,9 +718,43 @@
 	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);
+		printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name);
 	}
+	return rvalue;
+}
+
+/* The following OIDs need to be "unlatched":
+ *
+ * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL
+ * FREQUENCY,EXTENDEDRATES.
+ *
+ * The way to do this is to set ESSID. Note though that they may get 
+ * unlatch before though by setting another OID. */
+void
+mgt_unlatch_all(islpci_private *priv)
+{
+	u32 u;
+	int rvalue = 0;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return;
+
+	u = DOT11_OID_SSID;
+	rvalue = mgt_commit_list(priv, &u, 1);
+	/* Necessary if in MANUAL RUN mode? */
+#if 0
+	u = OID_INL_MODE;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+
+	u = DOT11_OID_MLMEAUTOLEVEL;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+
+	u = OID_INL_MODE;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+#endif
+
+	if (rvalue)
+		printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name);
 }
 
 /* This will tell you if you are allowed to answer a mlme(ex) request .*/
@@ -771,6 +857,14 @@
 					mlme->state, mlme->code, mlme->size);
 		}
 		break;
+	case OID_TYPE_ATTACH:{
+			struct obj_attachment *attach = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"id=%d\nsize=%d\n",
+					attach->id,
+					attach->size);
+		}
+		break;
 	case OID_TYPE_SSID:{
 			struct obj_ssid *ssid = r->ptr;
 			return snprintf(str, PRIV_STR_SIZE,
diff -urN linux-2.4.28-pre3/drivers/net/wireless/prism54/oid_mgt.h linux-2.4.28-pre4/drivers/net/wireless/prism54/oid_mgt.h
--- linux-2.4.28-pre3/drivers/net/wireless/prism54/oid_mgt.h	2004-10-08 06:28:21.625095567 -0700
+++ linux-2.4.28-pre4/drivers/net/wireless/prism54/oid_mgt.h	2004-10-08 06:28:25.392248831 -0700
@@ -36,6 +36,8 @@
 void mgt_le_to_cpu(int, void *);
 
 int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
+int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int);
+
 
 int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
 		    union oid_res_t *);
@@ -46,7 +48,8 @@
 
 void mgt_get(islpci_private *, enum oid_num_t, void *);
 
-void mgt_commit(islpci_private *);
+int mgt_commit(islpci_private *);
+void mgt_unlatch_all(islpci_private *);
 
 int mgt_mlme_answer(islpci_private *);
 
diff -urN linux-2.4.28-pre3/drivers/scsi/53c700.h linux-2.4.28-pre4/drivers/scsi/53c700.h
--- linux-2.4.28-pre3/drivers/scsi/53c700.h	2002-02-25 11:38:04.000000000 -0800
+++ linux-2.4.28-pre4/drivers/scsi/53c700.h	2004-10-08 06:28:25.758263722 -0700
@@ -109,8 +109,11 @@
 static inline void
 NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer)
 {
-	((unsigned long)SDp->hostdata) &= 0xffffff00;
-	((unsigned long)SDp->hostdata) |= sxfer & 0xff;
+	long l = (long)SDp->hostdata;
+
+	l &= 0xffffff00;
+	l |= sxfer & 0xff;
+	SDp->hostdata = (void *)l;
 }
 static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp)
 {
@@ -119,8 +122,11 @@
 static inline void
 NCR_700_set_depth(Scsi_Device *SDp, __u8 depth)
 {
-	((unsigned long)SDp->hostdata) &= 0xffff00ff;
-	((unsigned long)SDp->hostdata) |= (0xff00 & (depth << 8));
+	long l = (long)SDp->hostdata;
+
+	l &= 0xffff00ff;
+	l |= 0xff00 & (depth << 8);
+	SDp->hostdata = (void *)l;
 }
 static inline __u8
 NCR_700_get_depth(Scsi_Device *SDp)
@@ -140,12 +146,12 @@
 static inline void
 NCR_700_set_flag(Scsi_Device *SDp, __u32 flag)
 {
-	((unsigned long)SDp->hostdata) |= (flag & 0xffff0000);
+	SDp->hostdata = (void *)((long)SDp->hostdata | (flag & 0xffff0000));
 }
 static inline void
 NCR_700_clear_flag(Scsi_Device *SDp, __u32 flag)
 {
-	((unsigned long)SDp->hostdata) &= ~(flag & 0xffff0000);
+	SDp->hostdata = (void *)((long)SDp->hostdata & ~(flag & 0xffff0000));
 }
 
 /* These represent the Nexus hashing functions.  A Nexus in SCSI terms
diff -urN linux-2.4.28-pre3/drivers/scsi/ata_piix.c linux-2.4.28-pre4/drivers/scsi/ata_piix.c
--- linux-2.4.28-pre3/drivers/scsi/ata_piix.c	2004-10-08 06:28:21.767101345 -0700
+++ linux-2.4.28-pre4/drivers/scsi/ata_piix.c	2004-10-08 06:28:25.783264739 -0700
@@ -106,7 +106,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -126,15 +126,15 @@
 	.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,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
 
 	.phy_reset		= piix_pata_phy_reset,
 
-	.bmdma_setup		= ata_bmdma_setup_pio,
-	.bmdma_start		= ata_bmdma_start_pio,
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 
@@ -150,15 +150,15 @@
 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,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
 
 	.phy_reset		= piix_sata_phy_reset,
 
-	.bmdma_setup		= ata_bmdma_setup_pio,
-	.bmdma_start		= ata_bmdma_start_pio,
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 
diff -urN linux-2.4.28-pre3/drivers/scsi/gdth.c linux-2.4.28-pre4/drivers/scsi/gdth.c
--- linux-2.4.28-pre3/drivers/scsi/gdth.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.28-pre4/drivers/scsi/gdth.c	2004-10-08 06:28:25.803265552 -0700
@@ -4,11 +4,14 @@
  * Intel Corporation:  Storage RAID Controllers                         *
  *                                                                      *
  * gdth.c                                                               *
- * Copyright (C) 1995-02 ICP vortex, an Intel company,  Achim Leubner   *
- * <achim.leubner@intel.com>                                            *
+ * Copyright (C) 1995-04 ICP vortex GmbH, Achim Leubner                 *
+ * Copyright (C) 2002-03 Intel Corporation                              *
+ * Copyright (C) 2003-04 Adaptec Inc.                                   *
+ * <achim_leubner@adaptec.com>                                          *
  *                                                                      *
- * Additions/Fixes: Boji Tony Kannanthanam                              *
- * <boji.t.kannanthanam@intel.com>                                      *
+ * Additions/Fixes:                                                     *
+ * Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>               *
+ * Johannes Dinner <johannes_dinner@adaptec.com>                        *
  *                                                                      *
  * This program is free software; you can redistribute it and/or modify *
  * it under the terms of the GNU General Public License as published    *
@@ -24,11 +27,57 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.20, ..., 2.4.18                   *
+ * Linux kernel 2.2.x, 2.4.x, 2.6.x supported                           *
  *                                                                      *
  * $Log: gdth.c,v $
- * Revision 1.61  2002/10/03 09:35:22  boji
- * Fixed SCREENSERVICE intialisation in SMP cases.
+ * Revision 1.73  2004/03/31 13:33:03  achim
+ * Special command 0xfd implemented to detect 64-bit DMA support
+ *
+ * Revision 1.72  2004/03/17 08:56:04  achim
+ * 64-bit DMA only enabled if FW >= x.43
+ *
+ * Revision 1.71  2004/03/05 15:51:29  achim
+ * Screen service: separate message buffer, bugfixes
+ *
+ * Revision 1.70  2004/02/27 12:19:07  achim
+ * Bugfix: Reset bit in config (0xfe) call removed
+ *
+ * Revision 1.69  2004/02/20 09:50:24  achim
+ * Compatibility changes for kernels < 2.4.20
+ * Bugfix screen service command size
+ * pci_set_dma_mask() error handling added
+ *
+ * Revision 1.68  2004/02/19 15:46:54  achim
+ * 64-bit DMA bugfixes
+ * Drive size bugfix for drives > 1TB
+ *
+ * Revision 1.67  2004/01/14 13:11:57  achim
+ * Tool access over /proc no longer supported
+ * Bugfixes IOCTLs
+ *
+ * Revision 1.66  2003/12/19 15:04:06  achim
+ * Bugfixes support for drives > 2TB
+ *
+ * Revision 1.65  2003/12/15 11:21:56  achim
+ * 64-bit DMA support added
+ * Support for drives > 2 TB implemented
+ * Kernels 2.2.x, 2.4.x, 2.6.x supported
+ *
+ * Revision 1.64  2003/09/17 08:30:26  achim
+ * EISA/ISA controller scan disabled
+ * Command line switch probe_eisa_isa added
+ *
+ * Revision 1.63  2003/07/12 14:01:00  Daniele Bellucci <bellucda@tiscali.it>
+ * Minor cleanups in gdth_ioctl.
+ *
+ * Revision 1.62  2003/02/27 15:01:59  achim
+ * Dynamic DMA mapping implemented
+ * New (character device) IOCTL interface added
+ * Other controller related changes made
+ *
+ * Revision 1.61  2002/11/08 13:09:52  boji
+ * Added support for XSCALE based RAID Controllers
+ * Fixed SCREENSERVICE initialization in SMP cases
  * Added checks for gdth_polling before GDTH_HA_LOCK
  *
  * Revision 1.60  2002/02/05 09:35:22  achim
@@ -216,7 +265,7 @@
  *
  * Revision 1.9  1997/09/04 10:07:25  achim
  * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ...
- * register_reboot_notifier() to get a notify on shutdown used
+ * register_reboot_notifier() to get a notify on shutown used
  *
  * Revision 1.8  1997/04/02 12:14:30  achim
  * Version 1.00 (see gdth.h), tested with kernel 2.0.29
@@ -248,7 +297,6 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.60 2002/02/05 09:35:22 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -282,10 +330,14 @@
  *                              access a shared resource from several nodes, 
  *                              appropiate controller firmware required
  * shared_access:N              enable driver reserve/release protocol
+ * probe_eisa_isa:Y             scan for EISA/ISA controllers
+ * probe_eisa_isa:N             do not scan for EISA/ISA controllers
+ * force_dma32:Y                use only 32 bit DMA mode
+ * force_dma32:N                use 64 bit DMA mode, if supported
  *
  * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
  *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
- *                          shared_access:Y".
+ *                          shared_access:Y,probe_eisa_isa:N,force_dma32:N".
  * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
  * 
  * When loading the gdth driver as a module, the same options are available. 
@@ -295,22 +347,31 @@
  * '1' in place of 'Y' and '0' in place of 'N'.
  * 
  * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- *           max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0"
+ *           max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0 
+ *           probe_eisa_isa=0 force_dma32=0"
  * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
  */
 
 /* The meaning of the Scsi_Pointer members in this driver is as follows:
- * ptr:                         Chaining
- * this_residual:               Command priority
- * buffer:                      Unused
- * buffers_residual:            Timeout value
- * Status:                      Command status (gdth_do_cmd())
- * Message:                     Additional info (gdth_do_cmd())
- * have_data_in:                Flag for gdth_wait_completion()
- * sent_command:                Opcode special command
- * phase:                       Service/parameter/return code special command
+ * ptr:                     Chaining
+ * this_residual:           Command priority
+ * buffer:                  phys. DMA sense buffer 
+ * dma_handle:              phys. DMA buffer (kernel >= 2.4.0)
+ * buffers_residual:        Timeout value
+ * Status:                  Command status (gdth_do_cmd()), DMA mem. mappings
+ * Message:                 Additional info (gdth_do_cmd()), DMA direction
+ * have_data_in:            Flag for gdth_wait_completion()
+ * sent_command:            Opcode special command
+ * phase:                   Service/parameter/return code special command
  */
 
+
+/* interrupt coalescing */
+/* #define INT_COAL */
+
+/* statistics */
+#define GDTH_STATISTICS
+
 #include <linux/module.h>
 
 #include <linux/version.h>
@@ -322,6 +383,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/proc_fs.h>
 #include <linux/time.h>
@@ -329,38 +391,34 @@
 #ifdef GDTH_RTC
 #include <linux/mc146818rtc.h>
 #endif
-#if LINUX_VERSION_CODE >= 0x020100
 #include <linux/reboot.h>
-#else
-#include <linux/bios32.h>
-#endif
 
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/io.h>
-#if LINUX_VERSION_CODE >= 0x020322
+#include <asm/uaccess.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #include <linux/spinlock.h>
-#elif LINUX_VERSION_CODE >= 0x02015F
+#else
 #include <asm/spinlock.h>
 #endif
-
-#if LINUX_VERSION_CODE >= 0x010300
-#include <linux/blk.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/blkdev.h>
 #else
-#include "../block/blk.h"
+#include <linux/blk.h>
+#include "sd.h"
 #endif
+
 #include "scsi.h"
 #include "hosts.h"
-#include "sd.h"
-
 #include "gdth.h"
 
 static void gdth_delay(int milliseconds);
-static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs);
-#if LINUX_VERSION_CODE >= 0x010346
-static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 #else
-static void gdth_interrupt(int irq,struct pt_regs *regs);
+static void gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 #endif
 static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
 static int gdth_async_event(int hanum);
@@ -377,7 +435,8 @@
                                gdth_evt_str *estr);
 static void gdth_clear_events(void);
 
-static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count);
+static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
+                                    char *buffer,ushort count);
 static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp);
 static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
 
@@ -398,24 +457,19 @@
 static void gdth_release_event(int hanum);
 static int gdth_wait(int hanum,int index,ulong32 time);
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
-                             ulong32 p2,ulong32 p3);
+                             ulong64 p2,ulong64 p3);
 static int gdth_search_drives(int hanum);
 static int gdth_analyse_hdrive(int hanum, ushort hdrive);
 
-static void *gdth_mmap(ulong paddr, ulong size);
-static void gdth_munmap(void *addr);
-
 static const char *gdth_ctr_name(int hanum);
 
-#if LINUX_VERSION_CODE >= 0x010300
+static int gdth_open(struct inode *inode, struct file *filep);
+static int gdth_close(struct inode *inode, struct file *filep);
+static int gdth_ioctl(struct inode *inode, struct file *filep,
+                      unsigned int cmd, unsigned long arg);
+
 static void gdth_flush(int hanum);
-#if LINUX_VERSION_CODE >= 0x020100
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
-#else
-static int halt_called = FALSE;
-void gdth_halt(void);
-#endif
-#endif
 
 #ifdef DEBUG_GDTH
 static unchar   DebugState = DEBUG_GDTH;
@@ -500,6 +554,9 @@
 
 #ifdef GDTH_STATISTICS
 static ulong32 max_rq=0, max_index=0, max_sg=0;
+#ifdef INT_COAL
+static ulong32 max_int_coal=0;
+#endif
 static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;
 static struct timer_list gdth_timer;
 #endif
@@ -514,80 +571,12 @@
 
 #define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))
 
-#if LINUX_VERSION_CODE < 0x010300
-static void *gdth_mmap(ulong paddr, ulong size) 
-{
-    if (paddr >= high_memory)
-        return NULL; 
-    else
-        return (void *)paddr;
-}
-static void gdth_munmap(void *addr) 
-{
-}
-inline ulong32 virt_to_phys(volatile void *addr)
-{
-    return (ulong32)addr;
-}
-inline void *phys_to_virt(ulong32 addr)
-{
-    return (void *)addr;
-}
-#define virt_to_bus             virt_to_phys
-#define bus_to_virt             phys_to_virt
-#define gdth_readb(addr)        (*(volatile unchar *)(addr))
-#define gdth_readw(addr)        (*(volatile ushort *)(addr))
-#define gdth_readl(addr)        (*(volatile ulong32 *)(addr))
-#define gdth_writeb(b,addr)     (*(volatile unchar *)(addr) = (b))
-#define gdth_writew(b,addr)     (*(volatile ushort *)(addr) = (b))
-#define gdth_writel(b,addr)     (*(volatile ulong32 *)(addr) = (b))
-#define memset_io(a,b,c)        memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c)    memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)      memcpy((void *)(a),(b),(c))
-
-#define PCI_SLOT(devfn)         ((devfn >> 3) & 0x1f)
-
-#elif LINUX_VERSION_CODE < 0x020100
-static int remapped = FALSE;
-static void *gdth_mmap(ulong paddr, ulong size) 
-{
-    if ( paddr >= high_memory) {
-        remapped = TRUE;
-        return vremap(paddr, size);
-    } else {
-        return (void *)paddr; 
-    }
-}
-static void gdth_munmap(void *addr) 
-{
-    if (remapped)
-        vfree(addr);
-    remapped = FALSE;
-}
-#define gdth_readb(addr)        readb((ulong)(addr))
-#define gdth_readw(addr)        readw((ulong)(addr))
-#define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
-#define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
-#define gdth_writew(b,addr)     writew((b),(ulong)(addr))
-#define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
-
-#else
-static void *gdth_mmap(ulong paddr, ulong size) 
-{ 
-    return ioremap(paddr, size); 
-}
-static void gdth_munmap(void *addr) 
-{
-    return iounmap(addr);
-}
 #define gdth_readb(addr)        readb((ulong)(addr))
 #define gdth_readw(addr)        readw((ulong)(addr))
 #define gdth_readl(addr)        (ulong32)readl((ulong)(addr))
 #define gdth_writeb(b,addr)     writeb((b),(ulong)(addr))
 #define gdth_writew(b,addr)     writew((b),(ulong)(addr))
 #define gdth_writel(b,addr)     writel((ulong32)(b),(ulong)(addr))
-#endif
-
 
 static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
 static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
@@ -603,6 +592,7 @@
 static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
 static int elastidx;
 static int eoldidx;
+static int major;
 
 #define DIN     1                               /* IN data direction */
 #define DOU     2                               /* OUT data direction */
@@ -617,8 +607,8 @@
     DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
-    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
-    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,
     DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
     DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
     DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
@@ -628,36 +618,32 @@
 };
 
 /* __initfunc, __initdata macros */
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define __devinitdata
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #define GDTH_INITFUNC(type, func)       type __init func 
 #include <linux/init.h>
-#elif LINUX_VERSION_CODE >= 0x020126
+#else
 #define GDTH_INITFUNC(type, func)       __initfunc(type func)
 #include <linux/init.h>
-#else
-#define GDTH_INITFUNC(type, func)       type func
-#define __initdata
-#define __init
 #endif
 
-#if LINUX_VERSION_CODE >= 0x02015F
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define GDTH_INIT_LOCK_HA(ha)           spin_lock_init(&(ha)->smp_lock)
+#define GDTH_LOCK_HA(ha,flags)          spin_lock_irqsave(&(ha)->smp_lock,flags)
+#define GDTH_UNLOCK_HA(ha,flags)        spin_unlock_irqrestore(&(ha)->smp_lock,flags)
+
+#define GDTH_LOCK_SCSI_DONE(dev, flags) spin_lock_irqsave(dev->host_lock,flags)
+#define GDTH_UNLOCK_SCSI_DONE(dev, flags) spin_unlock_irqrestore(dev->host_lock,flags)
+
+#else
 #define GDTH_INIT_LOCK_HA(ha)           spin_lock_init(&(ha)->smp_lock)
 #define GDTH_LOCK_HA(ha,flags)          spin_lock_irqsave(&(ha)->smp_lock,flags)
 #define GDTH_UNLOCK_HA(ha,flags)        spin_unlock_irqrestore(&(ha)->smp_lock,flags)
 
 #define GDTH_LOCK_SCSI_DONE(flags)      spin_lock_irqsave(&io_request_lock,flags)
 #define GDTH_UNLOCK_SCSI_DONE(flags)    spin_unlock_irqrestore(&io_request_lock,flags)
-#define GDTH_LOCK_SCSI_DOCMD()          spin_lock_irq(&io_request_lock)
-#define GDTH_UNLOCK_SCSI_DOCMD()        spin_unlock_irq(&io_request_lock)
-#else
-#define GDTH_INIT_LOCK_HA(ha)           do {} while (0)
-#define GDTH_LOCK_HA(ha,flags)          do {save_flags(flags); cli();} while (0)
-#define GDTH_UNLOCK_HA(ha,flags)        do {restore_flags(flags);} while (0)
-
-#define GDTH_LOCK_SCSI_DONE(flags)      do {} while (0)
-#define GDTH_UNLOCK_SCSI_DONE(flags)    do {} while (0)
-#define GDTH_LOCK_SCSI_DOCMD()          do {} while (0)
-#define GDTH_UNLOCK_SCSI_DOCMD()        do {} while (0)
 #endif
 
 /* LILO and modprobe/insmod parameters */
@@ -686,9 +672,12 @@
 static int virt_ctr = 0;
 /* shared access */
 static int shared_access = 1;
+/* enable support for EISA and ISA controllers */
+static int probe_eisa_isa = 0;
+/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */
+static int force_dma32 = 0;
 
 #ifdef MODULE
-#if LINUX_VERSION_CODE >= 0x02011A
 /* parameters for modprobe/insmod */
 MODULE_PARM(irq, "i");
 MODULE_PARM(disable, "i");
@@ -700,32 +689,43 @@
 MODULE_PARM(rescan, "i");
 MODULE_PARM(virt_ctr, "i");
 MODULE_PARM(shared_access, "i");
+MODULE_PARM(probe_eisa_isa, "i");
+MODULE_PARM(force_dma32, "i");
 MODULE_AUTHOR("Achim Leubner");
-#endif
-#if LINUX_VERSION_CODE >= 0x02040B
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,11)
 MODULE_LICENSE("GPL");
 #endif
 #endif
 
+/* ioctl interface */
+static struct file_operations gdth_fops = {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    .ioctl   = gdth_ioctl,
+    .open    = gdth_open,
+    .release = gdth_close,
+#else
+    ioctl:gdth_ioctl,
+    open:gdth_open,
+    release:gdth_close,
+#endif
+};
+
 /* /proc support */
-#if LINUX_VERSION_CODE >= 0x010300
 #include <linux/stat.h> 
-#if LINUX_VERSION_CODE < 0x020322
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 struct proc_dir_entry proc_scsi_gdth = {
     PROC_SCSI_GDTH, 4, "gdth",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 #endif
+
 #include "gdth_proc.h"
 #include "gdth_proc.c"
-#endif
 
-#if LINUX_VERSION_CODE >= 0x020100
 /* notifier block to get a notify on system shutdown/halt/reboot */
 static struct notifier_block gdth_notifier = {
     gdth_halt, NULL, 0
 };
-#endif
 
 
 static void gdth_delay(int milliseconds)
@@ -733,17 +733,11 @@
     if (milliseconds == 0) {
         udelay(1);
     } else {
-#if LINUX_VERSION_CODE >= 0x020168
         mdelay(milliseconds);
-#else
-        int i;
-        for (i = 0; i < milliseconds; ++i) 
-            udelay(1000);
-#endif
     }
 }
 
-static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs)
+static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs)
 {
     *cyls = size /HEADS/SECS;
     if (*cyls <= MAXCYLS) {
@@ -788,9 +782,9 @@
     ulong32 id;
 
     TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
-    if ((addr = gdth_mmap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
+    if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
         id = gdth_readl(addr);
-        gdth_munmap(addr);
+        iounmap(addr);
         if (id == GDT2_ID)                          /* GDT2000 */
             return 1;
     }
@@ -812,19 +806,24 @@
         gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device);
     gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, 
                     PCI_DEVICE_ID_VORTEX_GDTNEWRX);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, 
+                    PCI_DEVICE_ID_VORTEX_GDTNEWRX2);
     gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL,
                     PCI_DEVICE_ID_INTEL_SRC);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL,
+                    PCI_DEVICE_ID_INTEL_SRC_XSCALE);
     return cnt;
 }
 
-#if LINUX_VERSION_CODE >= 0x20363
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 /* Vortex only makes RAID controllers.
  * We do not really want to specify all 550 ids here, so wildcard match.
  */
-static struct pci_device_id gdthtable[] = {
-	{PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID },
-	{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID }, 
-	{0}
+static struct pci_device_id gdthtable[] __devinitdata = {
+    {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID},
+    {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID}, 
+    {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID}, 
+    {0}
 };
 MODULE_DEVICE_TABLE(pci,gdthtable);
 #endif
@@ -833,17 +832,12 @@
                                            ushort vendor, ushort device))
 {
     ulong base0, base1, base2;
-#if LINUX_VERSION_CODE >= 0x2015C
     struct pci_dev *pdev;
-#else
-    int error;
-    ushort idx;
-#endif
     
     TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n",
           *cnt, vendor, device));
 
-#if LINUX_VERSION_CODE >= 0x20363
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     pdev = NULL;
     while ((pdev = pci_find_device(vendor, device, pdev)) 
            != NULL) {
@@ -881,7 +875,7 @@
                 pcistr[*cnt].irq, pcistr[*cnt].dpmem));
         (*cnt)++;
     }       
-#elif LINUX_VERSION_CODE >= 0x2015C
+#else
     pdev = NULL;
     while ((pdev = pci_find_device(vendor, device, pdev)) 
            != NULL) {
@@ -922,66 +916,6 @@
                 pcistr[*cnt].irq, pcistr[*cnt].dpmem));
         (*cnt)++;
     }       
-#else   
-    idx = 0;
-    while (!pcibios_find_device(vendor, device, idx++,
-                                &pcistr[*cnt].bus,&pcistr[*cnt].device_fn)) {
-        if (*cnt >= MAXHA)
-            return;
-        /* GDT PCI ctr. found, now read resources from config space */
-#if LINUX_VERSION_CODE >= 0x010300
-#define GDTH_BASEP      (int *)
-#else
-#define GDTH_BASEP
-#endif
-        if ((error = pcibios_read_config_dword(pcistr[*cnt].bus,
-                                               pcistr[*cnt].device_fn,
-                                               PCI_BASE_ADDRESS_0,
-                                               GDTH_BASEP&base0)) ||
-            (error = pcibios_read_config_dword(pcistr[*cnt].bus,
-                                               pcistr[*cnt].device_fn,
-                                               PCI_BASE_ADDRESS_1,
-                                               GDTH_BASEP&base1)) ||
-            (error = pcibios_read_config_dword(pcistr[*cnt].bus,
-                                               pcistr[*cnt].device_fn,
-                                               PCI_BASE_ADDRESS_2,
-                                               GDTH_BASEP&base2)) ||
-            (error = pcibios_read_config_word(pcistr[*cnt].bus,
-                                              pcistr[*cnt].device_fn,
-                                              PCI_SUBSYSTEM_ID,
-                                              &pcistr[*cnt].subdevice_id)) ||
-            (error = pcibios_read_config_byte(pcistr[*cnt].bus,
-                                              pcistr[*cnt].device_fn,
-                                              PCI_INTERRUPT_LINE,
-                                              &pcistr[*cnt].irq))) {
-            printk("GDT-PCI: error %d reading configuration space", error);
-            continue;
-        }
-        pcistr[*cnt].vendor_id = vendor;
-        pcistr[*cnt].device_id = device;
-        if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
-            device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
-            if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_MEMORY)
-                continue;
-            pcistr[*cnt].dpmem = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-        } else {                                    /* GDT6110, GDT6120, .. */
-            if ((base0 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_MEMORY ||
-                (base2 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_MEMORY ||
-                (base1 & PCI_BASE_ADDRESS_SPACE) !=
-                PCI_BASE_ADDRESS_SPACE_IO)
-                continue;
-            pcistr[*cnt].dpmem = base2 & PCI_BASE_ADDRESS_MEM_MASK;
-            pcistr[*cnt].io_mm = base0 & PCI_BASE_ADDRESS_MEM_MASK;
-            pcistr[*cnt].io    = base1 & PCI_BASE_ADDRESS_IO_MASK;
-        }
-        TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
-                pcistr[*cnt].bus, PCI_SLOT(pcistr[*cnt].device_fn), 
-                pcistr[*cnt].irq, pcistr[*cnt].dpmem));
-        (*cnt)++;
-    }
 #endif
 }   
 
@@ -1111,6 +1045,8 @@
         ha->type = GDT_EISA;
         ha->stype = id;
     }
+
+    ha->dma64_support = 0;
     return 1;
 }
 
@@ -1124,7 +1060,7 @@
 
     TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr));
 
-    ha->brd = gdth_mmap(bios_adr, sizeof(gdt2_dpram_str));
+    ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str));
     if (ha->brd == NULL) {
         printk("GDT-ISA: Initialization error (DPMEM remap error)\n");
         return 0;
@@ -1134,8 +1070,8 @@
     /* reset interface area */
     memset_io((char *)&dp2_ptr->u,0,sizeof(dp2_ptr->u));
     if (gdth_readl(&dp2_ptr->u) != 0) {
-        printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-        gdth_munmap(ha->brd);
+        printk("GDT-ISA: Initialization error (DPMEM write error)\n");
+        iounmap(ha->brd);
         return 0;
     }
 
@@ -1170,7 +1106,7 @@
     while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error (DEINIT failed)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         gdth_delay(1);
@@ -1180,7 +1116,7 @@
     gdth_writeb(0xff, &dp2_ptr->io.irqdel);
     if (prot_ver != PROTOCOL_VERSION) {
         printk("GDT-ISA: Illegal protocol version\n");
-        gdth_munmap(ha->brd);
+        iounmap(ha->brd);
         return 0;
     }
 
@@ -1202,13 +1138,15 @@
     while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
         if (--retries == 0) {
             printk("GDT-ISA: Initialization error\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         gdth_delay(1);
     }
     gdth_writeb(0, &dp2_ptr->u.ic.Status);
     gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+
+    ha->dma64_support = 0;
     return 1;
 }
 
@@ -1222,9 +1160,6 @@
     unchar prot_ver;
     ushort command;
     int i, found = FALSE;
-#if LINUX_VERSION_CODE < 0x2015C
-    int rom_addr;
-#endif
 
     TRACE(("gdth_init_pci()\n"));
 
@@ -1236,10 +1171,13 @@
     ha->stype = (ulong32)pcistr->device_id;
     ha->subdevice_id = pcistr->subdevice_id;
     ha->irq = pcistr->irq;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    ha->pdev = pcistr->pdev;
+#endif
     
     if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {  /* GDT6000/B */
         TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
-        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6_dpram_str));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str));
         if (ha->brd == NULL) {
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
             return 0;
@@ -1252,8 +1190,8 @@
                    pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
-                gdth_munmap(ha->brd);
-                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1262,15 +1200,10 @@
                     TRACE2(("init_pci_old() address 0x%x busy\n", i));
                     continue;
                 }
-                gdth_munmap(ha->brd);
-#if LINUX_VERSION_CODE >= 0x2015C
+                iounmap(ha->brd);
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_0, i);
-#else
-                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                           PCI_BASE_ADDRESS_0, i);
-#endif
-                ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); 
+                ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1285,20 +1218,20 @@
             }   
             if (!found) {
                 printk("GDT-PCI: No free address found!\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
         }
         memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
         if (gdth_readl(&dp6_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         
         /* disable board interrupts, deinit services */
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);
-        gdth_writeb(0x00, &dp6_ptr->io.irqen);;
+        gdth_writeb(0x00, &dp6_ptr->io.irqen);
         gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
         gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
 
@@ -1310,7 +1243,7 @@
         while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1320,7 +1253,7 @@
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
 
@@ -1330,7 +1263,7 @@
         /* special command to controller BIOS */
         gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
         gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x01, &dp6_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
         gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
         gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
         gdth_writeb(0, &dp6_ptr->io.event);
@@ -1339,7 +1272,7 @@
         while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1347,14 +1280,16 @@
         gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);
 
+        ha->dma64_support = 0;
+
     } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
         ha->plx = (gdt6c_plx_regs *)pcistr->io;
         TRACE2(("init_pci_new() dpmem %lx irq %d\n",
             pcistr->dpmem,ha->irq));
-        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
         if (ha->brd == NULL) {
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         /* check and reset interface area */
@@ -1365,8 +1300,8 @@
                    pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
-                gdth_munmap(ha->brd);
-                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1375,15 +1310,10 @@
                     TRACE2(("init_pci_plx() address 0x%x busy\n", i));
                     continue;
                 }
-                gdth_munmap(ha->brd);
-#if LINUX_VERSION_CODE >= 0x2015C
+                iounmap(ha->brd);
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_2, i);
-#else
-                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                           PCI_BASE_ADDRESS_2, i);
-#endif
-                ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); 
+                ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1398,14 +1328,14 @@
             }   
             if (!found) {
                 printk("GDT-PCI: No free address found!\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
         }
         memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
         if (gdth_readl(&dp6c_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
         
@@ -1426,7 +1356,7 @@
         while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1435,7 +1365,7 @@
         gdth_writeb(0, &dp6c_ptr->u.ic.Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
 
@@ -1445,7 +1375,7 @@
         /* special command to controller BIOS */
         gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
         gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x01, &dp6c_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
         gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
         gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
         
@@ -1456,23 +1386,25 @@
         while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
         }
         gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
 
+        ha->dma64_support = 0;
+
     } else {                                            /* MPR */
         TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
-        ha->brd = gdth_mmap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
         if (ha->brd == NULL) {
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
             return 0;
         }
 
         /* manipulate config. space to enable DPMEM, start RP controller */
-#if LINUX_VERSION_CODE >= 0x20363
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
         command |= 6;
         pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
@@ -1483,7 +1415,7 @@
         gdth_delay(1);
         pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
                                pci_resource_start(pcistr->pdev, 8));
-#elif LINUX_VERSION_CODE >= 0x2015C
+#else
         pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
         command |= 6;
         pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
@@ -1494,24 +1426,13 @@
         gdth_delay(1);
         pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
                                pcistr->pdev->rom_address);
-#else
-        pcibios_read_config_word(pcistr->bus, pcistr->device_fn,
-                                 PCI_COMMAND, &command);
-        command |= 6;
-        pcibios_write_config_word(pcistr->bus, pcistr->device_fn, 
-                                  PCI_COMMAND, command);
-        pcibios_read_config_dword(pcistr->bus, pcistr->device_fn,
-                                  PCI_ROM_ADDRESS, &rom_addr);
-        if (rom_addr == 1UL)
-            rom_addr = 0UL;
-        i = 0xFEFF0001UL;
-        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                   PCI_ROM_ADDRESS, i);
-        gdth_delay(1);
-        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                   PCI_ROM_ADDRESS, rom_addr);
 #endif
         
+        /* Ensure that it is safe to access the non HW portions of DPMEM.
+         * Aditional check needed for Xscale based RAID controllers */
+        while( ((int)gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.sema0_reg) ) & 3 )
+            gdth_delay(1);
+        
         /* check and reset interface area */
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
@@ -1520,8 +1441,8 @@
                    pcistr->dpmem);
             found = FALSE;
             for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
-                gdth_munmap(ha->brd);
-                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1530,15 +1451,10 @@
                     TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
                     continue;
                 }
-                gdth_munmap(ha->brd);
-#if LINUX_VERSION_CODE >= 0x2015C
+                iounmap(ha->brd);
                 pci_write_config_dword(pcistr->pdev, 
                                        PCI_BASE_ADDRESS_0, i);
-#else
-                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
-                                           PCI_BASE_ADDRESS_0, i);
-#endif
-                ha->brd = gdth_mmap(i, sizeof(gdt6m_dpram_str)); 
+                ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); 
                 if (ha->brd == NULL) {
                     printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
                     return 0;
@@ -1553,7 +1469,7 @@
             }   
             if (!found) {
                 printk("GDT-PCI: No free address found!\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
         }
@@ -1574,7 +1490,7 @@
         while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error (DEINIT failed)\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
@@ -1583,7 +1499,7 @@
         gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
         if (prot_ver != PROTOCOL_VERSION) {
             printk("GDT-PCI: Illegal protocol version\n");
-            gdth_munmap(ha->brd);
+            iounmap(ha->brd);
             return 0;
         }
 
@@ -1593,7 +1509,7 @@
         /* special command to controller BIOS */
         gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
         gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
-        gdth_writel(0x01, &dp6m_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
         gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
         gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
         gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
@@ -1602,12 +1518,32 @@
         while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
             if (--retries == 0) {
                 printk("GDT-PCI: Initialization error\n");
-                gdth_munmap(ha->brd);
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+
+        /* read FW version to detect 64-bit DMA support */
+        gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                iounmap(ha->brd);
                 return 0;
             }
             gdth_delay(1);
         }
+        prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
         gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        if (prot_ver < 0x2b)      /* FW < x.43: no 64-bit DMA support */
+            ha->dma64_support = 0;
+        else 
+            ha->dma64_support = 1;
     }
 
     return 1;
@@ -1841,7 +1777,7 @@
 
     if (ha->type == GDT_EISA) {
         if (ha->pccb->OpCode == GDT_INIT)               /* store DMA buffer */
-            outl(virt_to_bus(ha->pccb), ha->bmic + MAILBOXREG);
+            outl(ha->ccb_phys, ha->bmic + MAILBOXREG);
         outb(ha->pccb->Service, ha->bmic + LDOORREG);
     } else if (ha->type == GDT_ISA) {
         gdth_writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event);
@@ -1868,11 +1804,7 @@
 
     gdth_from_wait = TRUE;
     do {
-#if LINUX_VERSION_CODE >= 0x010346
         gdth_interrupt((int)ha->irq,ha,NULL);
-#else
-        gdth_interrupt((int)ha->irq,NULL);
-#endif
         if (wait_hanum==hanum && wait_index==index) {
             answer_found = TRUE;
             break;
@@ -1889,7 +1821,7 @@
 
 
 static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
-                             ulong32 p2,ulong32 p3)
+                             ulong64 p2,ulong64 p3)
 {
     register gdth_ha_str *ha;
     register gdth_cmd_str *cmd_ptr;
@@ -1915,23 +1847,35 @@
         if (service == CACHESERVICE) {
             if (opcode == GDT_IOCTL) {
                 cmd_ptr->u.ioctl.subfunc = p1;
-                cmd_ptr->u.ioctl.channel = p2;
+                cmd_ptr->u.ioctl.channel = (ulong32)p2;
                 cmd_ptr->u.ioctl.param_size = (ushort)p3;
-                cmd_ptr->u.ioctl.p_param = virt_to_bus(ha->pscratch);
+                cmd_ptr->u.ioctl.p_param = ha->scratch_phys;
             } else {
-                cmd_ptr->u.cache.DeviceNo = (ushort)p1;
-                cmd_ptr->u.cache.BlockNo  = p2;
+                if (ha->cache_feat & GDT_64BIT) {
+                    cmd_ptr->u.cache64.DeviceNo = (ushort)p1;
+                    cmd_ptr->u.cache64.BlockNo  = p2;
+                } else {
+                    cmd_ptr->u.cache.DeviceNo = (ushort)p1;
+                    cmd_ptr->u.cache.BlockNo  = (ulong32)p2;
+                }
             }
         } else if (service == SCSIRAWSERVICE) {
-            cmd_ptr->u.raw.direction  = p1;
-            cmd_ptr->u.raw.bus        = (unchar)p2;
-            cmd_ptr->u.raw.target     = (unchar)p3;
-            cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+            if (ha->raw_feat & GDT_64BIT) {
+                cmd_ptr->u.raw64.direction  = p1;
+                cmd_ptr->u.raw64.bus        = (unchar)p2;
+                cmd_ptr->u.raw64.target     = (unchar)p3;
+                cmd_ptr->u.raw64.lun        = (unchar)(p3 >> 8);
+            } else {
+                cmd_ptr->u.raw.direction  = p1;
+                cmd_ptr->u.raw.bus        = (unchar)p2;
+                cmd_ptr->u.raw.target     = (unchar)p3;
+                cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+            }
         } else if (service == SCREENSERVICE) {
             if (opcode == GDT_REALTIME) {
                 *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1;
-                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = p2;
-                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = p3;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3;
             }
         }
         ha->cmd_len          = sizeof(gdth_cmd_str);
@@ -1959,6 +1903,7 @@
 {
     register gdth_ha_str *ha;
     ushort cdev_cnt, i;
+    int ok;
     ulong32 bus_no, drv_cnt, drv_no, j;
     gdth_getch_str *chn;
     gdth_drlist_str *drl;
@@ -1966,6 +1911,11 @@
     gdth_raw_iochan_str *iocr;
     gdth_arcdl_str *alst;
     gdth_alist_str *alst2;
+    gdth_oem_str_ioctl *oemstr;
+#ifdef INT_COAL
+    gdth_perf_modes *pmod;
+#endif
+
 #ifdef GDTH_RTC
     unchar rtc[12];
     ulong flags;
@@ -1973,11 +1923,20 @@
    
     TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
+    ok = 0;
 
     /* initialize controller services, at first: screen service */
-    if (!gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0)) {
-        printk("GDT: Initialization error screen service (code %d)\n",
-               ha->status);
+    ha->screen_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0);
+        if (ok)
+            ha->screen_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error screen service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
@@ -2009,15 +1968,52 @@
     gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0);
  
     /* initialize cache service */
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
+    ha->cache_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0);
+        if (ok)
+            ha->cache_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error cache service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
     ha->fw_vers = ha->service;
 
+#ifdef INT_COAL
+    if (ha->type == GDT_PCIMPR) {
+        /* set perf. modes */
+        pmod = (gdth_perf_modes *)ha->pscratch;
+        pmod->version          = 1;
+        pmod->st_mode          = 1;    /* enable one status buffer */
+        *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys;
+        pmod->st_buff_indx1    = COALINDEX;
+        pmod->st_buff_addr2    = 0;
+        pmod->st_buff_u_addr2  = 0;
+        pmod->st_buff_indx2    = 0;
+        pmod->st_buff_size     = sizeof(gdth_coal_status) * MAXOFFSETS;
+        pmod->cmd_mode         = 0;    // disable all cmd buffers
+        pmod->cmd_buff_addr1   = 0;
+        pmod->cmd_buff_u_addr1 = 0;
+        pmod->cmd_buff_indx1   = 0;
+        pmod->cmd_buff_addr2   = 0;
+        pmod->cmd_buff_u_addr2 = 0;
+        pmod->cmd_buff_indx2   = 0;
+        pmod->cmd_buff_size    = 0;
+        pmod->reserved1        = 0;            
+        pmod->reserved2        = 0;            
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES,
+                              INVALID_CHANNEL,sizeof(gdth_perf_modes))) {
+            printk("GDT-HA %d: Interrupt coalescing activated\n", hanum);
+        }
+    }
+#endif
+
     /* detect number of buses - try new IOCTL */
     iocr = (gdth_raw_iochan_str *)ha->pscratch;
     iocr->hdr.version        = 0xffffffff;
@@ -2045,8 +2041,8 @@
                                    IO_CHANNEL | INVALID_CHANNEL,
                                    sizeof(gdth_getch_str))) {
                 if (bus_no == 0) {
-                    printk("GDT: Error detecting channel count (0x%x)\n",
-                           ha->status);
+                    printk("GDT-HA %d: Error detecting channel count (0x%x)\n",
+                           hanum, ha->status);
                     return 0;
                 }
                 break;
@@ -2063,8 +2059,8 @@
     /* read cache configuration */
     if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
                            INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
+        printk("GDT-HA %d: Initialization error cache service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar;
@@ -2183,9 +2179,17 @@
     }       
                                   
     /* initialize raw service */
-    if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
-        printk("GDT: Initialization error raw service (code %d)\n",
-               ha->status);
+    ha->raw_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0);
+        if (ok)
+            ha->raw_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error raw service (code %d)\n",
+               hanum, ha->status);
         return 0;
     }
     TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
@@ -2197,7 +2201,7 @@
         if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
             TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
                     ha->info));
-            ha->raw_feat = (ushort)ha->info;
+            ha->raw_feat |= (ushort)ha->info;
         }
     } 
 
@@ -2208,7 +2212,7 @@
         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
             TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
                     ha->info));
-            ha->cache_feat = (ushort)ha->info;
+            ha->cache_feat |= (ushort)ha->info;
         }
     }
 
@@ -2228,12 +2232,48 @@
             if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
                                    reserve_list[i+1], reserve_list[i+2] | 
                                    (reserve_list[i+3] << 8))) {
-                printk("GDT: Error raw service (RESERVE, code %d)\n",
-                       ha->status);
+                printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n",
+                       hanum, ha->status);
              }
         }
     }
 
+    /* Determine OEM string using IOCTL */
+    oemstr = (gdth_oem_str_ioctl *)ha->pscratch;
+    oemstr->params.ctl_version = 0x01;
+    oemstr->params.buffer_size = sizeof(oemstr->text);
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                          CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL,
+                          sizeof(gdth_oem_str_ioctl))) {
+        TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n"));
+        printk("GDT-HA %d: Vendor: %s Name: %s\n",
+               hanum,oemstr->text.oem_company_name,ha->binfo.type_string);
+        /* Save the Host Drive inquiry data */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,
+                sizeof(ha->oem_name));
+#else
+        strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7);
+        ha->oem_name[7] = '\0';
+#endif
+    } else {
+        /* Old method, based on PCI ID */
+        TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n"));
+        printk("GDT-HA %d: Name: %s\n",
+               hanum,ha->binfo.type_string);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        if (ha->oem_id == OEM_ID_INTEL)
+            strlcpy(ha->oem_name,"Intel  ", sizeof(ha->oem_name));
+        else
+            strlcpy(ha->oem_name,"ICP    ", sizeof(ha->oem_name));
+#else 
+        if (ha->oem_id == OEM_ID_INTEL)
+            strcpy(ha->oem_name,"Intel  ");
+        else
+            strcpy(ha->oem_name,"ICP    ");
+#endif
+    }
+
     /* scanning for host drives */
     for (i = 0; i < cdev_cnt; ++i) 
         gdth_analyse_hdrive(hanum,i);
@@ -2245,7 +2285,8 @@
 static int gdth_analyse_hdrive(int hanum,ushort hdrive)
 {
     register gdth_ha_str *ha;
-    int drv_cyls, drv_hds, drv_secs;
+    ulong32 drv_cyls;
+    int drv_hds, drv_secs;
 
     TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
     if (hdrive >= MAX_HDRIVES)
@@ -2256,7 +2297,7 @@
         return 0;
     ha->hdr[hdrive].present = TRUE;
     ha->hdr[hdrive].size = ha->info;
-
+   
     /* evaluate mapping (sectors per head, heads per cylinder) */
     ha->hdr[hdrive].size &= ~SECS32;
     if (ha->info2 == 0) {
@@ -2264,15 +2305,22 @@
     } else {
         drv_hds = ha->info2 & 0xff;
         drv_secs = (ha->info2 >> 8) & 0xff;
-        drv_cyls = ha->hdr[hdrive].size /drv_hds/drv_secs;
+        drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs;
     }
     ha->hdr[hdrive].heads = (unchar)drv_hds;
     ha->hdr[hdrive].secs  = (unchar)drv_secs;
     /* round size */
     ha->hdr[hdrive].size  = drv_cyls * drv_hds * drv_secs;
+    
+    if (ha->cache_feat & GDT_64BIT) {
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0)
+            && ha->info2 != 0) {
+            ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
+        }
+    }
     TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
             hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
-            
+
     /* get informations about device */
     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
         TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
@@ -2314,9 +2362,13 @@
     GDTH_LOCK_HA(ha, flags);
 
     scp->SCp.this_residual = (int)priority;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+    t = scp->device->id;
+#else
     b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
     t = scp->target;
-#if LINUX_VERSION_CODE >= 0x010300
+#endif
     if (priority >= DEFAULT_PRI) {
         if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
             (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
@@ -2324,7 +2376,6 @@
             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
     }
-#endif
 
     if (ha->req_first==NULL) {
         ha->req_first = scp;                    /* queue was empty */
@@ -2358,7 +2409,7 @@
     register gdth_ha_str *ha;
     register Scsi_Cmnd *pscp;
     register Scsi_Cmnd *nscp;
-    unchar b, t, firsttime;
+    unchar b, t, l, firsttime;
     unchar this_cmd, next_cmd;
     ulong flags = 0;
     int cmd_index;
@@ -2366,7 +2417,7 @@
     TRACE(("gdth_next() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
     if (!gdth_polling) 
-    	GDTH_LOCK_HA(ha, flags);
+        GDTH_LOCK_HA(ha, flags);
 
     ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
     this_cmd = firsttime = TRUE;
@@ -2376,8 +2427,15 @@
     for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
         if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
             pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        b = virt_ctr ? NUMDATA(nscp->device->host)->busnum : nscp->device->channel;
+        t = nscp->device->id;
+        l = nscp->device->lun;
+#else
         b = virt_ctr ? NUMDATA(nscp->host)->busnum : nscp->channel;
         t = nscp->target;
+        l = nscp->lun;
+#endif
         if (nscp->SCp.this_residual >= DEFAULT_PRI) {
             if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
                 (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) 
@@ -2397,24 +2455,21 @@
             firsttime = FALSE;
         }
 
-#if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) 
-#endif
-        {
+        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) {        
         if (nscp->SCp.phase == -1) {
             nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
             if (nscp->cmnd[0] == TEST_UNIT_READY) {
                 TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 
-                        b, t, nscp->lun));
+                        b, t, l));
                 /* TEST_UNIT_READY -> set scan mode */
                 if ((ha->scan_mode & 0x0f) == 0) {
-                    if (b == 0 && t == 0 && nscp->lun == 0) {
+                    if (b == 0 && t == 0 && l == 0) {
                         ha->scan_mode |= 1;
                         TRACE2(("Scan mode: 0x%x\n", ha->scan_mode));
                     }
                 } else if ((ha->scan_mode & 0x0f) == 1) {
-                    if (b == 0 && ((t == 0 && nscp->lun == 1) ||
-                         (t == 1 && nscp->lun == 0))) {
+                    if (b == 0 && ((t == 0 && l == 1) ||
+                         (t == 1 && l == 0))) {
                         nscp->SCp.sent_command = GDT_SCAN_START;
                         nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 
                             | SCSIRAWSERVICE;
@@ -2466,37 +2521,32 @@
                     /* io_request_lock already active ! */
                     nscp->scsi_done(nscp);
                     if (!gdth_polling) 
-                    	GDTH_LOCK_HA(ha,flags);
+                        GDTH_LOCK_HA(ha,flags);
                 }
             }
-        } else
-
-#if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
+        } else if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
             if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
                 this_cmd = FALSE;
             next_cmd = FALSE;
-        } else
-#endif
-        if (b != ha->virt_bus) {
+        } else if (b != ha->virt_bus) {
             if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
                 !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) 
                 this_cmd = FALSE;
             else 
                 ha->raw[BUS_L2P(ha,b)].io_cnt[t]++;
-        } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || nscp->lun != 0) {
+        } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || l != 0) {
             TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
-                    nscp->cmnd[0], b, t, nscp->lun));
+                    nscp->cmnd[0], b, t, l));
             nscp->result = DID_BAD_TARGET << 16;
             if (!nscp->SCp.have_data_in)
                 nscp->SCp.have_data_in++;
             else {
                 if (!gdth_polling) 
-                	GDTH_UNLOCK_HA(ha,flags);
+                    GDTH_UNLOCK_HA(ha,flags);
                 /* io_request_lock already active ! */      
                 nscp->scsi_done(nscp);
                 if (!gdth_polling) 
-                	GDTH_LOCK_HA(ha,flags);
+                    GDTH_LOCK_HA(ha,flags);
             }
         } else {
             switch (nscp->cmnd[0]) {
@@ -2507,6 +2557,9 @@
               case VERIFY:
               case START_STOP:
               case MODE_SENSE:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+              case SERVICE_ACTION_IN:
+#endif
                 TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                        nscp->cmnd[4],nscp->cmnd[5]));
@@ -2522,20 +2575,20 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                	if (!gdth_polling) 
-                        	GDTH_UNLOCK_HA(ha,flags);
+                        if (!gdth_polling) 
+                            GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                	if (!gdth_polling) 
-                        	GDTH_LOCK_HA(ha,flags);
+                        if (!gdth_polling) 
+                            GDTH_LOCK_HA(ha,flags);
                     }
                 } else if (gdth_internal_cache_cmd(hanum,nscp)) {
                     if (!gdth_polling) 
-                    	GDTH_UNLOCK_HA(ha,flags);
+                        GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */      
                     nscp->scsi_done(nscp);
                     if (!gdth_polling) 
-                    	GDTH_LOCK_HA(ha,flags);
+                        GDTH_LOCK_HA(ha,flags);
                 }
                 break;
 
@@ -2550,12 +2603,12 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                    	if (!gdth_polling) 
-                        	GDTH_UNLOCK_HA(ha,flags);
+                        if (!gdth_polling) 
+                            GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                    	if (!gdth_polling) 
-                        	GDTH_LOCK_HA(ha,flags);
+                        if (!gdth_polling) 
+                            GDTH_LOCK_HA(ha,flags);
                     }
                 } else {
                     nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
@@ -2578,6 +2631,10 @@
               case WRITE_6:
               case READ_10:
               case WRITE_10:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+              case READ_16:
+              case WRITE_16:
+#endif
                 if (ha->hdr[t].media_changed) {
                     /* return UNIT_ATTENTION */
                     TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
@@ -2590,12 +2647,12 @@
                     if (!nscp->SCp.have_data_in)
                         nscp->SCp.have_data_in++;
                     else {
-                    	if (!gdth_polling) 
-                        	GDTH_UNLOCK_HA(ha,flags);
+                        if (!gdth_polling) 
+                            GDTH_UNLOCK_HA(ha,flags);
                         /* io_request_lock already active ! */      
                         nscp->scsi_done(nscp);
-                    	if (!gdth_polling) 
-                        	GDTH_LOCK_HA(ha,flags);
+                        if (!gdth_polling) 
+                            GDTH_LOCK_HA(ha,flags);
                     }
                 } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
                     this_cmd = FALSE;
@@ -2605,18 +2662,18 @@
                 TRACE2(("cache cmd %x/%x/%x/%x/%x/%x unknown\n",nscp->cmnd[0],
                         nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                         nscp->cmnd[4],nscp->cmnd[5]));
-                printk("GDT: Unknown SCSI command 0x%x to cache service !\n",
-                       nscp->cmnd[0]);
+                printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n",
+                       hanum, nscp->cmnd[0]);
                 nscp->result = DID_ABORT << 16;
                 if (!nscp->SCp.have_data_in)
                     nscp->SCp.have_data_in++;
                 else {
                     if (!gdth_polling) 
-                    	GDTH_UNLOCK_HA(ha,flags);
+                        GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */  
                     nscp->scsi_done(nscp);
                     if (!gdth_polling) 
-                    	GDTH_LOCK_HA(ha,flags);
+                        GDTH_LOCK_HA(ha,flags);
                 }
                 break;
             }
@@ -2637,36 +2694,68 @@
     }
 
     if (!gdth_polling) 
-    	GDTH_UNLOCK_HA(ha, flags);
+        GDTH_UNLOCK_HA(ha, flags);
 
     if (gdth_polling && ha->cmd_cnt > 0) {
         if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
-            printk("GDT: Controller %d: Command %d timed out !\n",
+            printk("GDT-HA %d: Command %d timed out !\n",
                    hanum,cmd_index);
     }
 }
-    
-static void gdth_copy_internal_data(Scsi_Cmnd *scp,char *buffer,ushort count)
+   
+static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
+                                    char *buffer,ushort count)
 {
     ushort cpcount,i;
     ushort cpsum,cpnow;
     struct scatterlist *sl;
+    gdth_ha_str *ha;
+    int sgcnt;
+    char *address;
 
     cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
     if (scp->use_sg) {
         sl = (struct scatterlist *)scp->request_buffer;
-        for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
-            cpnow = (ushort)sl->length;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+        sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,PCI_DMA_FROMDEVICE);
+        for (i=0,cpsum=0; i<sgcnt; ++i,++sl) {
+            cpnow = (ushort)sg_dma_len(sl);
             TRACE(("copy_internal() now %d sum %d count %d %d\n",
                           cpnow,cpsum,cpcount,(ushort)scp->bufflen));
             if (cpsum+cpnow > cpcount) 
                 cpnow = cpcount - cpsum;
             cpsum += cpnow;
-            memcpy((char*)sl->address,buffer,cpnow);
+            if (!sl->page) {
+                printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
+                       hanum);
+                return;
+            }
+            address = (char *)(page_address(sl->page) + sl->offset);
+            memcpy(address,buffer,cpnow);
+            if (cpsum == cpcount)
+                break;
+            buffer += cpnow;
+        }
+        pci_unmap_sg(ha->pdev,scp->request_buffer,
+                     scp->use_sg,PCI_DMA_FROMDEVICE);
+#else
+        sgcnt = scp->use_sg;
+        for (i=0,cpsum=0; i<sgcnt; ++i,++sl) {
+            cpnow = (ushort)sl->length;
+            TRACE(("copy_internal() now %d sum %d count %d %d\n",
+                          cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+            if (cpsum+cpnow > cpcount) 
+               cpnow = cpcount - cpsum;
+            cpsum += cpnow;
+            address = (char *)sl->address;
+            memcpy(address,buffer,cpnow);
             if (cpsum == cpcount)
                 break;
             buffer += cpnow;
         }
+#endif
     } else {
         TRACE(("copy_internal() count %d\n",cpcount));
         memcpy((char*)scp->request_buffer,buffer,cpcount);
@@ -2683,10 +2772,17 @@
     gdth_modep_data mpd;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    t  = scp->device->id;
+#else
     t  = scp->target;
+#endif
     TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
            scp->cmnd[0],t));
 
+    scp->result = DID_OK << 16;
+    scp->sense_buffer[0] = 0;
+
     switch (scp->cmnd[0]) {
       case TEST_UNIT_READY:
       case VERIFY:
@@ -2707,13 +2803,10 @@
         inq.version   = 2;
         inq.resp_aenc = 2;
         inq.add_length= 32;
-        if (ha->oem_id == OEM_ID_INTEL)
-            strcpy(inq.vendor,"Intel  ");
-        else 
-            strcpy(inq.vendor,"ICP    ");
+        strcpy(inq.vendor,ha->oem_name);
         sprintf(inq.product,"Host Drive  #%02d",t);
         strcpy(inq.revision,"   ");
-        gdth_copy_internal_data(scp,(char*)&inq,sizeof(gdth_inq_data));
+        gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data));
         break;
 
       case REQUEST_SENSE:
@@ -2723,7 +2816,7 @@
         sd.key       = NO_SENSE;
         sd.info      = 0;
         sd.add_length= 0;
-        gdth_copy_internal_data(scp,(char*)&sd,sizeof(gdth_sense_data));
+        gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data));
         break;
 
       case MODE_SENSE:
@@ -2735,24 +2828,40 @@
         mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
         mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
         mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
-        gdth_copy_internal_data(scp,(char*)&mpd,sizeof(gdth_modep_data));
+        gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data));
         break;
 
       case READ_CAPACITY:
         TRACE2(("Read capacity hdrive %d\n",t));
-        rdc.last_block_no = ntohl(ha->hdr[t].size-1);
-        rdc.block_length  = ntohl(SECTOR_SIZE);
-        gdth_copy_internal_data(scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+        if (ha->hdr[t].size > (ulong64)0xffffffff)
+            rdc.last_block_no = 0xffffffff;
+        else
+            rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
+        rdc.block_length  = cpu_to_be32(SECTOR_SIZE);
+        gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+        break;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+      case SERVICE_ACTION_IN:
+        if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 &&
+            (ha->cache_feat & GDT_64BIT)) {
+            gdth_rdcap16_data rdc16;
+
+            TRACE2(("Read capacity (16) hdrive %d\n",t));
+            rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
+            rdc16.block_length  = cpu_to_be32(SECTOR_SIZE);
+            gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data));
+        } else { 
+            scp->result = DID_ABORT << 16;
+        }
         break;
+#endif
 
       default:
         TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
         break;
     }
 
-    scp->result = DID_OK << 16;
-    scp->sense_buffer[0] = 0;
-
     if (!scp->SCp.have_data_in)
         scp->SCp.have_data_in++;
     else 
@@ -2766,9 +2875,14 @@
     register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
-    ushort i, cnt;
-    ulong32 no;
-    int cmd_index, read_write;
+    ulong32 cnt, blockcnt;
+    ulong64 no, blockno;
+    dma_addr_t phys_addr;
+    int i, cmd_index, read_write, sgcnt, mode64;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+    struct page *page;
+    ulong offset;
+#endif
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -2778,6 +2892,11 @@
     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
         return 0;
 
+    mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE;
+    /* test for READ_16, WRITE_16 if !mode64 ? ---
+       not required, should not occur due to error return on 
+       READ_CAPACITY_16 */
+
     cmdp->Service = CACHESERVICE;
     cmdp->RequestBuffer = scp;
     /* search free command index */
@@ -2790,7 +2909,7 @@
         gdth_set_sema0(hanum);
 
     /* fill command */
-    read_write = FALSE;
+    read_write = 0;
     if (scp->SCp.sent_command != -1) 
         cmdp->OpCode = scp->SCp.sent_command;   /* special cache cmd. */
     else if (scp->cmnd[0] == RESERVE) 
@@ -2804,76 +2923,173 @@
             cmdp->OpCode = GDT_UNMOUNT;
         else
             cmdp->OpCode = GDT_FLUSH;
-    } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) {
-        read_write = TRUE;
+    } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10 ||
+               scp->cmnd[0] == WRITE_12 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+               || scp->cmnd[0] == WRITE_16
+#endif
+    ) {
+        read_write = 1;
         if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 
                                    (ha->cache_feat & GDT_WR_THROUGH)))
             cmdp->OpCode = GDT_WRITE_THR;
         else
             cmdp->OpCode = GDT_WRITE;
     } else {
-        read_write = TRUE;
+        read_write = 2;
         cmdp->OpCode = GDT_READ;
     }
-    
-    cmdp->BoardNode        = LOCALBOARD;
-    cmdp->u.cache.DeviceNo = hdrive;
-    cmdp->u.cache.BlockNo  = 1;
-    cmdp->u.cache.sg_canz  = 0;
+
+    cmdp->BoardNode = LOCALBOARD;
+    if (mode64) {
+        cmdp->u.cache64.DeviceNo = hdrive;
+        cmdp->u.cache64.BlockNo  = 1;
+        cmdp->u.cache64.sg_canz  = 0;
+    } else {
+        cmdp->u.cache.DeviceNo = hdrive;
+        cmdp->u.cache.BlockNo  = 1;
+        cmdp->u.cache.sg_canz  = 0;
+    }
 
     if (read_write) {
-        if (scp->cmd_len != 6) {
+        if (scp->cmd_len == 16) {
+            memcpy(&no, &scp->cmnd[2], sizeof(ulong64));
+            blockno = be64_to_cpu(no);
+            memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32));
+            blockcnt = be32_to_cpu(cnt);
+        } else if (scp->cmd_len == 10) {
             memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
-            cmdp->u.cache.BlockNo = ntohl(no);
+            blockno = be32_to_cpu(no);
             memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
-            cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt);
+            blockcnt = be16_to_cpu(cnt);
         } else {
             memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
-            cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL;
-            cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+            blockno = be32_to_cpu(no) & 0x001fffffUL;
+            blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+        }
+        if (mode64) {
+            cmdp->u.cache64.BlockNo = blockno;
+            cmdp->u.cache64.BlockCnt = blockcnt;
+        } else {
+            cmdp->u.cache.BlockNo = (ulong32)blockno;
+            cmdp->u.cache.BlockCnt = blockcnt;
         }
 
         if (scp->use_sg) {
-            cmdp->u.cache.DestAddr= 0xffffffff;
             sl = (struct scatterlist *)scp->request_buffer;
-            for (i=0; i<scp->use_sg; ++i,++sl) {
-                cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
-                cmdp->u.cache.sg_lst[i].sg_len = (ulong32)sl->length;
+            sgcnt = scp->use_sg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+            scp->SCp.Status = GDTH_MAP_SG;
+            scp->SCp.Message = (read_write == 1 ? 
+                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);   
+            sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+            if (mode64) {
+                cmdp->u.cache64.DestAddr= (ulong64)-1;
+                cmdp->u.cache64.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+                        ha->dma64_cnt++;
+                    else
+                        ha->dma32_cnt++;
+#endif
+                    cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            } else {
+                cmdp->u.cache.DestAddr= 0xffffffff;
+                cmdp->u.cache.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    ha->dma32_cnt++;
+#endif
+                    cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            }
+#else
+            if (mode64) {
+                cmdp->u.cache64.DestAddr= (ulong64)-1;
+                cmdp->u.cache64.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache64.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.cache64.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
+            } else {
+                cmdp->u.cache.DestAddr= 0xffffffff;
+                cmdp->u.cache.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.cache.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
             }
-            cmdp->u.cache.sg_canz = (ulong32)i;
+#endif
 
 #ifdef GDTH_STATISTICS
-            if (max_sg < (ulong32)i) {
-                max_sg = (ulong32)i;
-                TRACE3(("GDT: max_sg = %d\n",i));
+            if (max_sg < (ulong32)sgcnt) {
+                max_sg = (ulong32)sgcnt;
+                TRACE3(("GDT: max_sg = %d\n",max_sg));
             }
 #endif
-            if (i<GDTH_MAXSG)
-                cmdp->u.cache.sg_lst[i].sg_len = 0;
+
         } else {
-            if (ha->cache_feat & SCATTER_GATHER) {
-                cmdp->u.cache.DestAddr = 0xffffffff;
-                cmdp->u.cache.sg_canz = 1;
-                cmdp->u.cache.sg_lst[0].sg_ptr = 
-                    virt_to_bus(scp->request_buffer);
-                cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
-                cmdp->u.cache.sg_lst[1].sg_len = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+            scp->SCp.Status = GDTH_MAP_SINGLE;
+            scp->SCp.Message = (read_write == 1 ? 
+                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+            page = virt_to_page(scp->request_buffer);
+            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
+            phys_addr = pci_map_page(ha->pdev,page,offset,
+                                     scp->request_bufflen,scp->SCp.Message);
+            scp->SCp.dma_handle = phys_addr;
+#else
+            phys_addr = virt_to_bus(scp->request_buffer);
+#endif
+            if (mode64) {
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    cmdp->u.cache64.DestAddr = (ulong64)-1;
+                    cmdp->u.cache64.sg_canz = 1;
+                    cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.cache64.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.cache64.DestAddr  = phys_addr;
+                    cmdp->u.cache64.sg_canz= 0;
+                }
             } else {
-                cmdp->u.cache.DestAddr  = virt_to_bus(scp->request_buffer);
-                cmdp->u.cache.sg_canz= 0;
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    cmdp->u.cache.DestAddr = 0xffffffff;
+                    cmdp->u.cache.sg_canz = 1;
+                    cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.cache.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.cache.DestAddr  = phys_addr;
+                    cmdp->u.cache.sg_canz= 0;
+                }
             }
         }
     }
-    TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
-           cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
-           cmdp->u.cache.sg_lst[0].sg_ptr,
-           cmdp->u.cache.sg_lst[0].sg_len));
-    TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
-           cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
-
     /* evaluate command size, check space */
-    ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
-        (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+    if (mode64) {
+        TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+               cmdp->u.cache64.DestAddr,cmdp->u.cache64.sg_canz,
+               cmdp->u.cache64.sg_lst[0].sg_ptr,
+               cmdp->u.cache64.sg_lst[0].sg_len));
+        TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
+               cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) +
+            (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str);
+    } else {
+        TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+               cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
+               cmdp->u.cache.sg_lst[0].sg_ptr,
+               cmdp->u.cache.sg_lst[0].sg_len));
+        TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
+               cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
+            (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+    }
     if (ha->cmd_len & 3)
         ha->cmd_len += (4 - (ha->cmd_len & 3));
 
@@ -2897,12 +3113,22 @@
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
     ushort i;
-    int cmd_index;
+    dma_addr_t phys_addr, sense_paddr;
+    int cmd_index, sgcnt, mode64;
     unchar t,l;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+    struct page *page;
+    ulong offset;
+#endif
 
     ha = HADATA(gdth_ctr_tab[hanum]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    t = scp->device->id;
+    l = scp->device->lun;
+#else
     t = scp->target;
     l = scp->lun;
+#endif
     cmdp = ha->pccb;
     TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n",
            scp->cmnd[0],b,t,l));
@@ -2910,6 +3136,8 @@
     if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
         return 0;
 
+    mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE;
+
     cmdp->Service = SCSIRAWSERVICE;
     cmdp->RequestBuffer = scp;
     /* search free command index */
@@ -2925,68 +3153,176 @@
     if (scp->SCp.sent_command != -1) {
         cmdp->OpCode           = scp->SCp.sent_command; /* special raw cmd. */
         cmdp->BoardNode        = LOCALBOARD;
-        cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
-        TRACE2(("special raw cmd 0x%x param 0x%x\n", 
-                cmdp->OpCode, cmdp->u.raw.direction));
+        if (mode64) {
+            cmdp->u.raw64.direction = (scp->SCp.phase >> 8);
+            TRACE2(("special raw cmd 0x%x param 0x%x\n", 
+                    cmdp->OpCode, cmdp->u.raw64.direction));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst);
+        } else {
+            cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
+            TRACE2(("special raw cmd 0x%x param 0x%x\n", 
+                    cmdp->OpCode, cmdp->u.raw.direction));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst);
+        }
 
-        /* evaluate command size */
-        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst);
     } else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+        page = virt_to_page(scp->sense_buffer);
+        offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
+        sense_paddr = pci_map_page(ha->pdev,page,offset,
+                                   16,PCI_DMA_FROMDEVICE);
+        scp->SCp.buffer = (struct scatterlist *)((ulong32)sense_paddr);
+        /* high part, if 64bit */
+        scp->host_scribble = (char *)(ulong32)((ulong64)sense_paddr >> 32);
+#else
+        sense_paddr = virt_to_bus(scp->sense_buffer);
+#endif
         cmdp->OpCode           = GDT_WRITE;             /* always */
         cmdp->BoardNode        = LOCALBOARD;
-        cmdp->u.raw.reserved   = 0;
-        cmdp->u.raw.mdisc_time = 0;
-        cmdp->u.raw.mcon_time  = 0;
-        cmdp->u.raw.clen       = scp->cmd_len;
-        cmdp->u.raw.target     = t;
-        cmdp->u.raw.lun        = l;
-        cmdp->u.raw.bus        = b;
-        cmdp->u.raw.priority   = 0;
-        cmdp->u.raw.link_p     = 0;
-        cmdp->u.raw.sdlen      = scp->request_bufflen;
-        cmdp->u.raw.sense_len  = 16;
-        cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
-        cmdp->u.raw.direction  = 
-            gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
-        memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+        if (mode64) { 
+            cmdp->u.raw64.reserved   = 0;
+            cmdp->u.raw64.mdisc_time = 0;
+            cmdp->u.raw64.mcon_time  = 0;
+            cmdp->u.raw64.clen       = scp->cmd_len;
+            cmdp->u.raw64.target     = t;
+            cmdp->u.raw64.lun        = l;
+            cmdp->u.raw64.bus        = b;
+            cmdp->u.raw64.priority   = 0;
+            cmdp->u.raw64.sdlen      = scp->request_bufflen;
+            cmdp->u.raw64.sense_len  = 16;
+            cmdp->u.raw64.sense_data = sense_paddr;
+            cmdp->u.raw64.direction  = 
+                gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
+            memcpy(cmdp->u.raw64.cmd,scp->cmnd,16);
+        } else {
+            cmdp->u.raw.reserved   = 0;
+            cmdp->u.raw.mdisc_time = 0;
+            cmdp->u.raw.mcon_time  = 0;
+            cmdp->u.raw.clen       = scp->cmd_len;
+            cmdp->u.raw.target     = t;
+            cmdp->u.raw.lun        = l;
+            cmdp->u.raw.bus        = b;
+            cmdp->u.raw.priority   = 0;
+            cmdp->u.raw.link_p     = 0;
+            cmdp->u.raw.sdlen      = scp->request_bufflen;
+            cmdp->u.raw.sense_len  = 16;
+            cmdp->u.raw.sense_data = sense_paddr;
+            cmdp->u.raw.direction  = 
+                gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
+            memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+        }
 
         if (scp->use_sg) {
-            cmdp->u.raw.sdata  = 0xffffffff;
             sl = (struct scatterlist *)scp->request_buffer;
-            for (i=0; i<scp->use_sg; ++i,++sl) {
-                cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
-                cmdp->u.raw.sg_lst[i].sg_len = (ulong32)sl->length;
-            }
-            cmdp->u.raw.sg_ranz = (ulong32)i;
-
+            sgcnt = scp->use_sg;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+            scp->SCp.Status = GDTH_MAP_SG;
+            scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
+            sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+            if (mode64) {
+                cmdp->u.raw64.sdata = (ulong64)-1;
+                cmdp->u.raw64.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+                        ha->dma64_cnt++;
+                    else
+                        ha->dma32_cnt++;
+#endif
+                    cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            } else {
+                cmdp->u.raw.sdata = 0xffffffff;
+                cmdp->u.raw.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    ha->dma32_cnt++;
+#endif
+                    cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            }
+#else
+            if (mode64) {
+                cmdp->u.raw64.sdata = (ulong64)-1;
+                cmdp->u.raw64.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw64.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.raw64.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
+            } else {
+                cmdp->u.raw.sdata = 0xffffffff;
+                cmdp->u.raw.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw.sg_lst[i].sg_ptr = virt_to_bus(sl->address);
+                    cmdp->u.raw.sg_lst[i].sg_len = (ulong32)sl->length;
+                }
+            }
+#endif
+
 #ifdef GDTH_STATISTICS
-            if (max_sg < (ulong32)i) {
-                max_sg = (ulong32)i;
-                TRACE3(("GDT: max_sg = %d\n",i));
+            if (max_sg < sgcnt) {
+                max_sg = sgcnt;
+                TRACE3(("GDT: max_sg = %d\n",sgcnt));
             }
 #endif
-            if (i<GDTH_MAXSG)
-                cmdp->u.raw.sg_lst[i].sg_len = 0;
+
         } else {
-            if (ha->raw_feat & SCATTER_GATHER) {
-                cmdp->u.raw.sdata  = 0xffffffff;
-                cmdp->u.raw.sg_ranz= 1;
-                cmdp->u.raw.sg_lst[0].sg_ptr = virt_to_bus(scp->request_buffer);
-                cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
-                cmdp->u.raw.sg_lst[1].sg_len = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+            scp->SCp.Status = GDTH_MAP_SINGLE;
+            scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
+            page = virt_to_page(scp->request_buffer);
+            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
+            phys_addr = pci_map_page(ha->pdev,page,offset,
+                                     scp->request_bufflen,scp->SCp.Message);
+            scp->SCp.dma_handle = phys_addr;
+#else
+            phys_addr = virt_to_bus(scp->request_buffer);
+#endif
+            if (mode64) {
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    cmdp->u.raw64.sdata  = (ulong64)-1;
+                    cmdp->u.raw64.sg_ranz= 1;
+                    cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.raw64.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.raw64.sdata  = phys_addr;
+                    cmdp->u.raw64.sg_ranz= 0;
+                }
             } else {
-                cmdp->u.raw.sdata  = virt_to_bus(scp->request_buffer);
-                cmdp->u.raw.sg_ranz= 0;
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    cmdp->u.raw.sdata  = 0xffffffff;
+                    cmdp->u.raw.sg_ranz= 1;
+                    cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.raw.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.raw.sdata  = phys_addr;
+                    cmdp->u.raw.sg_ranz= 0;
+                }
             }
         }
-        TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
-               cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
-               cmdp->u.raw.sg_lst[0].sg_ptr,
-               cmdp->u.raw.sg_lst[0].sg_len));
-
-        /* evaluate command size */
-        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
-            (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+        if (mode64) {
+            TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+                   cmdp->u.raw64.sdata,cmdp->u.raw64.sg_ranz,
+                   cmdp->u.raw64.sg_lst[0].sg_ptr,
+                   cmdp->u.raw64.sg_lst[0].sg_len));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) +
+                (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str);
+        } else {
+            TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+                   cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
+                   cmdp->u.raw.sg_lst[0].sg_ptr,
+                   cmdp->u.raw.sg_lst[0].sg_len));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
+                (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+        }
     }
     /* check space */
     if (ha->cmd_len & 3)
@@ -3036,15 +3372,23 @@
     if (cmdp->OpCode == GDT_IOCTL) {
         TRACE2(("IOCTL\n"));
         ha->cmd_len = 
-            GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong32);
+            GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64);
     } else if (cmdp->Service == CACHESERVICE) {
         TRACE2(("cache command %d\n",cmdp->OpCode));
-        ha->cmd_len = 
-            GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
+        if (ha->cache_feat & GDT_64BIT)
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + sizeof(gdth_sg64_str);
+        else
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
     } else if (cmdp->Service == SCSIRAWSERVICE) {
-        TRACE2(("raw command %d/%d\n",cmdp->OpCode,cmdp->u.raw.cmd[0]));
-        ha->cmd_len = 
-            GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
+        TRACE2(("raw command %d\n",cmdp->OpCode));
+        if (ha->raw_feat & GDT_64BIT)
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + sizeof(gdth_sg64_str);
+        else
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
     }
 
     if (ha->cmd_len & 3)
@@ -3187,14 +3531,14 @@
 
 /* SCSI interface functions */
 
-#if LINUX_VERSION_CODE >= 0x010346
-static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
 #else
-static void gdth_interrupt(int irq,struct pt_regs *regs)
+static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
 #endif
 {
     register gdth_ha_str *ha;
-    gdt6m_dpram_str *dp6m_ptr;
+    gdt6m_dpram_str *dp6m_ptr = NULL;
     gdt6_dpram_str *dp6_ptr;
     gdt2_dpram_str *dp2_ptr;
     Scsi_Cmnd *scp;
@@ -3202,13 +3546,23 @@
     unchar IStatus;
     ushort Service;
     ulong flags = 0;
+#ifdef INT_COAL
+    int coalesced = FALSE;
+    int next = FALSE;
+    gdth_coal_status *pcs = NULL;
+    int act_int_coal = 0;       
+#endif
 
     TRACE(("gdth_interrupt() IRQ %d\n",irq));
 
     /* if polling and not from gdth_wait() -> return */
     if (gdth_polling) {
         if (!gdth_from_wait) {
-            return;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
         }
     }
 
@@ -3221,163 +3575,261 @@
         /* spurious interrupt */
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
     }
+    ha = HADATA(gdth_ctr_tab[hanum]);
 
 #ifdef GDTH_STATISTICS
     ++act_ints;
 #endif
-    
-    ha = HADATA(gdth_ctr_tab[hanum]);
-    if (ha->type == GDT_EISA) {
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = inw(ha->bmic + MAILBOXREG+8);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = inl(ha->bmic + MAILBOXREG+12);
-        ha->service = inw(ha->bmic + MAILBOXREG+10);
-        ha->info2 = inl(ha->bmic + MAILBOXREG+4);
-
-        outb(0xff, ha->bmic + EDOORREG);            /* acknowledge interrupt */
-        outb(0x00, ha->bmic + SEMA1REG);            /* reset status semaphore */
-    } else if (ha->type == GDT_ISA) {
-        dp2_ptr = (gdt2_dpram_str *)ha->brd;
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
-        ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
-        ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
-
-        gdth_writeb(0xff, &dp2_ptr->io.irqdel);     /* acknowledge interrupt */
-        gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);   /* reset command index */
-        gdth_writeb(0, &dp2_ptr->io.Sema1);         /* reset status semaphore */
-    } else if (ha->type == GDT_PCI) {
-        dp6_ptr = (gdt6_dpram_str *)ha->brd;
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
-        ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
-        ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
-
-        gdth_writeb(0xff, &dp6_ptr->io.irqdel);     /* acknowledge interrupt */
-        gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);   /* reset command index */
-        gdth_writeb(0, &dp6_ptr->io.Sema1);         /* reset status semaphore */
-    } else if (ha->type == GDT_PCINEW) {
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = inw(PTR2USHORT(&ha->plx->status));
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else
-            ha->status = S_OK;
-        ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
-        ha->service = inw(PTR2USHORT(&ha->plx->service));
-        ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
 
-        outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
-        outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
-    } else if (ha->type == GDT_PCIMPR) {
-        dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
-        if (IStatus & 0x80) {                       /* error flag */
-            IStatus &= ~0x80;
-            ha->status = gdth_readw(&dp6m_ptr->i960r.status);
-            TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
-        } else                                      /* no error */
-            ha->status = S_OK;
-        ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
-        ha->service = gdth_readw(&dp6m_ptr->i960r.service);
-        ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+#ifdef INT_COAL
+    /* See if the fw is returning coalesced status */
+    if (IStatus == COALINDEX) {
+        /* Coalesced status.  Setup the initial status 
+           buffer pointer and flags */
+        pcs = ha->coal_stat;
+        coalesced = TRUE;        
+        next = TRUE;
+    }
 
-        /* event string */
-        if (IStatus == ASYNCINDEX) {
-            if (ha->service != SCREENSERVICE &&
-                (ha->fw_vers & 0xff) >= 0x1a) {
-                ha->dvr.severity =   
-                    gdth_readb(&((gdt6m_dpram_str *)ha->brd)->i960r.severity);
-                for (i = 0; i < 256; ++i) {
-                    ha->dvr.event_string[i] = gdth_readb
-                        (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]);
-                    if (ha->dvr.event_string[i] == 0)
-                        break;
+    do {
+        if (coalesced) {
+            /* For coalesced requests all status
+               information is found in the status buffer */
+            IStatus = (unchar)(pcs->status & 0xff);
+        }
+#endif
+    
+        if (ha->type == GDT_EISA) {
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = inw(ha->bmic + MAILBOXREG+8);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = inl(ha->bmic + MAILBOXREG+12);
+            ha->service = inw(ha->bmic + MAILBOXREG+10);
+            ha->info2 = inl(ha->bmic + MAILBOXREG+4);
+
+            outb(0xff, ha->bmic + EDOORREG);    /* acknowledge interrupt */
+            outb(0x00, ha->bmic + SEMA1REG);    /* reset status semaphore */
+        } else if (ha->type == GDT_ISA) {
+            dp2_ptr = (gdt2_dpram_str *)ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
+            ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
+            ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+
+            gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
+            gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
+            gdth_writeb(0, &dp2_ptr->io.Sema1);     /* reset status semaphore */
+        } else if (ha->type == GDT_PCI) {
+            dp6_ptr = (gdt6_dpram_str *)ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
+            ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
+            ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+
+            gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
+            gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
+            gdth_writeb(0, &dp6_ptr->io.Sema1);     /* reset status semaphore */
+        } else if (ha->type == GDT_PCINEW) {
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = inw(PTR2USHORT(&ha->plx->status));
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else
+                ha->status = S_OK;
+            ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
+            ha->service = inw(PTR2USHORT(&ha->plx->service));
+            ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
+
+            outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
+            outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
+        } else if (ha->type == GDT_PCIMPR) {
+            dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+#ifdef INT_COAL
+                if (coalesced)
+                    ha->status = pcs->ext_status && 0xffff;
+                else 
+#endif
+                    ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+#ifdef INT_COAL
+            /* get information */
+            if (coalesced) {    
+                ha->info = pcs->info0;
+                ha->info2 = pcs->info1;
+                ha->service = (pcs->ext_status >> 16) && 0xffff;
+            } else
+#endif
+            {
+                ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
+                ha->service = gdth_readw(&dp6m_ptr->i960r.service);
+                ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+            }
+            /* event string */
+            if (IStatus == ASYNCINDEX) {
+                if (ha->service != SCREENSERVICE &&
+                    (ha->fw_vers & 0xff) >= 0x1a) {
+                    ha->dvr.severity = gdth_readb
+                        (&((gdt6m_dpram_str *)ha->brd)->i960r.severity);
+                    for (i = 0; i < 256; ++i) {
+                        ha->dvr.event_string[i] = gdth_readb
+                            (&((gdt6m_dpram_str *)ha->brd)->i960r.evt_str[i]);
+                        if (ha->dvr.event_string[i] == 0)
+                            break;
+                    }
                 }
             }
+#ifdef INT_COAL
+            /* Make sure that non coalesced interrupts get cleared
+               before being handled by gdth_async_event/gdth_sync_event */
+            if (!coalesced)
+#endif                          
+            {
+                gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+                gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+            }
+        } else {
+            TRACE2(("gdth_interrupt() unknown controller type\n"));
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
         }
-        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
-        gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
-    } else {
-        TRACE2(("gdth_interrupt() unknown controller type\n"));
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return;
-    }
 
-    TRACE(("gdth_interrupt() index %d stat %d info %d\n",
-           IStatus,ha->status,ha->info));
+        TRACE(("gdth_interrupt() index %d stat %d info %d\n",
+               IStatus,ha->status,ha->info));
 
-    if (gdth_from_wait) {
-        wait_hanum = hanum;
-        wait_index = (int)IStatus;
-    }
+        if (gdth_from_wait) {
+            wait_hanum = hanum;
+            wait_index = (int)IStatus;
+        }
 
-    if (IStatus == ASYNCINDEX) {
-        TRACE2(("gdth_interrupt() async. event\n"));
-        gdth_async_event(hanum);
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        gdth_next(hanum);
-        return;
-    } 
+        if (IStatus == ASYNCINDEX) {
+            TRACE2(("gdth_interrupt() async. event\n"));
+            gdth_async_event(hanum);
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+            gdth_next(hanum);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        } 
+
+        if (IStatus == SPEZINDEX) {
+            TRACE2(("Service unknown or not initialized !\n"));
+            ha->dvr.size = sizeof(ha->dvr.eu.driver);
+            ha->dvr.eu.driver.ionode = hanum;
+            gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        }
+        scp     = ha->cmd_tab[IStatus-2].cmnd;
+        Service = ha->cmd_tab[IStatus-2].service;
+        ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
+        if (scp == UNUSED_CMND) {
+            TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
+            ha->dvr.size = sizeof(ha->dvr.eu.driver);
+            ha->dvr.eu.driver.ionode = hanum;
+            ha->dvr.eu.driver.index = IStatus;
+            gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        }
+        if (scp == INTERNAL_CMND) {
+            TRACE(("gdth_interrupt() answer to internal command\n"));
+            if (!gdth_polling)
+                GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            return IRQ_HANDLED;
+#else
+            return;             
+#endif
+        }
 
-    if (IStatus == SPEZINDEX) {
-        TRACE2(("Service unknown or not initialized !\n"));
-        ha->dvr.size = sizeof(ha->dvr.eu.driver);
-        ha->dvr.eu.driver.ionode = hanum;
-        gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return;
-    }
-    scp     = ha->cmd_tab[IStatus-2].cmnd;
-    Service = ha->cmd_tab[IStatus-2].service;
-    ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
-    if (scp == UNUSED_CMND) {
-        TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
-        ha->dvr.size = sizeof(ha->dvr.eu.driver);
-        ha->dvr.eu.driver.ionode = hanum;
-        ha->dvr.eu.driver.index = IStatus;
-        gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
-        if (!gdth_polling)
-            GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return;
-    }
-    if (scp == INTERNAL_CMND) {
-        TRACE(("gdth_interrupt() answer to internal command\n"));
+        TRACE(("gdth_interrupt() sync. status\n"));
+        rval = gdth_sync_event(hanum,Service,IStatus,scp);
         if (!gdth_polling)
             GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-        return;
-    }
+        if (rval == 2) {
+            gdth_putq(hanum,scp,scp->SCp.this_residual);
+        } else if (rval == 1) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
+            scp->scsi_done(scp);
+            GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
+#else
+            GDTH_LOCK_SCSI_DONE(flags);
+            scp->scsi_done(scp);
+            GDTH_UNLOCK_SCSI_DONE(flags);
+#endif
+        }
 
-    TRACE(("gdth_interrupt() sync. status\n"));
-    rval = gdth_sync_event(hanum,Service,IStatus,scp);
-    if (!gdth_polling)
-        GDTH_UNLOCK_HA((gdth_ha_str *)dev_id,flags);
-    if (rval == 2) {
-        gdth_putq(hanum,scp,scp->SCp.this_residual);
-    } else if (rval == 1) {
-        GDTH_LOCK_SCSI_DONE(flags);
-        scp->scsi_done(scp);
-        GDTH_UNLOCK_SCSI_DONE(flags);
+#ifdef INT_COAL
+        if (coalesced) {
+            /* go to the next status in the status buffer */
+            ++pcs;
+#ifdef GDTH_STATISTICS
+            ++act_int_coal;
+            if (act_int_coal > max_int_coal) {
+                max_int_coal = act_int_coal;
+                printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal);
+            }
+#endif      
+            /* see if there is another status */
+            if (pcs->status == 0)    
+                /* Stop the coalesce loop */
+                next = FALSE;
+        }
+    } while (next);
+
+    /* coalescing only for new GDT_PCIMPR controllers available */      
+    if (ha->type == GDT_PCIMPR && coalesced) {
+        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
     }
+#endif
+
     gdth_next(hanum);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    return IRQ_HANDLED;
+#endif
 }
 
 static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
@@ -3385,7 +3837,7 @@
     register gdth_ha_str *ha;
     gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
-    unchar b;
+    unchar b, t;
 
     ha   = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -3393,10 +3845,11 @@
            service,ha->status));
 
     if (service == SCREENSERVICE) {
-        msg  = (gdth_msg_str *)ha->pscratch;
-        ha->scratch_busy = FALSE;
+        msg  = ha->pmsg;
         TRACE(("len: %d, answer: %d, ext: %d, alen: %d\n",
                msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen));
+        if (msg->msg_len > MSGLEN+1)
+            msg->msg_len = MSGLEN+1;
         if (msg->msg_len)
             if (!(msg->msg_answer && msg->msg_ext)) {
                 msg->msg_text[msg->msg_len] = '\0';
@@ -3414,11 +3867,10 @@
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
             cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
-            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
-            ha->scratch_busy = TRUE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
             ha->cmd_offs_dpmem = 0;
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
-                + sizeof(ulong32);
+                + sizeof(ulong64);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
             gdth_release_event(hanum);
@@ -3449,11 +3901,10 @@
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
             cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
-            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
-            ha->scratch_busy = TRUE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
             ha->cmd_offs_dpmem = 0;
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
-                + sizeof(ulong32);
+                + sizeof(ulong64);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
             gdth_release_event(hanum);
@@ -3462,11 +3913,39 @@
         printk("\n");
 
     } else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+#else
         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+        t = scp->target;
+#endif
         if (scp->SCp.sent_command == -1 && b != ha->virt_bus) {
-            ha->raw[BUS_L2P(ha,b)].io_cnt[scp->target]--;
+            ha->raw[BUS_L2P(ha,b)].io_cnt[t]--;
         }
         /* cache or raw service */
+        if (ha->status == S_BSY) {
+            TRACE2(("Controller busy -> retry !\n"));
+            if (scp->SCp.sent_command == GDT_MOUNT)
+                scp->SCp.sent_command = GDT_CLUST_INFO;
+            /* retry */
+            return 2;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,13)
+        if (scp->SCp.Status == GDTH_MAP_SG) 
+            pci_unmap_sg(ha->pdev,scp->request_buffer,
+                         scp->use_sg,scp->SCp.Message);
+        else if (scp->SCp.Status == GDTH_MAP_SINGLE) 
+            pci_unmap_page(ha->pdev,scp->SCp.dma_handle,
+                           scp->request_bufflen,scp->SCp.Message);
+        if (scp->SCp.buffer) {
+            dma_addr_t addr;
+            addr = (dma_addr_t)(ulong32)scp->SCp.buffer;
+            if (scp->host_scribble)
+                addr += (dma_addr_t)((ulong64)(ulong32)scp->host_scribble << 32);               
+            pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE);
+        }
+#endif
         if (ha->status == S_OK) {
             scp->SCp.Status = S_OK;
             scp->SCp.Message = ha->info;
@@ -3475,12 +3954,12 @@
                         scp->SCp.sent_command));
                 /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
                 if (scp->SCp.sent_command == GDT_CLUST_INFO) {
-                    ha->hdr[scp->target].cluster_type = (unchar)ha->info;
-                    if (!(ha->hdr[scp->target].cluster_type & 
+                    ha->hdr[t].cluster_type = (unchar)ha->info;
+                    if (!(ha->hdr[t].cluster_type & 
                         CLUSTER_MOUNTED)) {
                         /* NOT MOUNTED -> MOUNT */
                         scp->SCp.sent_command = GDT_MOUNT;
-                        if (ha->hdr[scp->target].cluster_type & 
+                        if (ha->hdr[t].cluster_type & 
                             CLUSTER_RESERVED) {
                             /* cluster drive RESERVED (on the other node) */
                             scp->SCp.phase = -2;      /* reservation conflict */
@@ -3490,11 +3969,11 @@
                     }
                 } else {
                     if (scp->SCp.sent_command == GDT_MOUNT) {
-                        ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
-                        ha->hdr[scp->target].media_changed = TRUE;
+                        ha->hdr[t].cluster_type |= CLUSTER_MOUNTED;
+                        ha->hdr[t].media_changed = TRUE;
                     } else if (scp->SCp.sent_command == GDT_UNMOUNT) {
-                        ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED;
-                        ha->hdr[scp->target].media_changed = TRUE;
+                        ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED;
+                        ha->hdr[t].media_changed = TRUE;
                     } 
                     scp->SCp.sent_command = -1;
                 }
@@ -3504,21 +3983,13 @@
             } else {
                 /* RESERVE/RELEASE ? */
                 if (scp->cmnd[0] == RESERVE) {
-                    ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED;
+                    ha->hdr[t].cluster_type |= CLUSTER_RESERVED;
                 } else if (scp->cmnd[0] == RELEASE) {
-                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                    ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED;
                 }           
                 scp->result = DID_OK << 16;
                 scp->sense_buffer[0] = 0;
             }
-        } else if (ha->status == S_BSY) {
-            TRACE2(("Controller busy -> retry !\n"));
-            scp->SCp.Status = S_BSY;
-            scp->SCp.Message = ha->info;
-            if (scp->SCp.sent_command == GDT_MOUNT)
-                scp->SCp.sent_command = GDT_CLUST_INFO;
-            /* retry */
-            return 2;
         } else {
             scp->SCp.Status = ha->status;
             scp->SCp.Message = ha->info;
@@ -3539,10 +4010,10 @@
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
             } else if (service == CACHESERVICE) {
                 if (ha->status == S_CACHE_UNKNOWN &&
-                    (ha->hdr[scp->target].cluster_type & 
+                    (ha->hdr[t].cluster_type & 
                      CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
                     /* bus reset -> force GDT_CLUST_INFO */
-                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                    ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED;
                 }
                 memset((char*)scp->sense_buffer,0,16);
                 if (ha->status == (ushort)S_CACHE_RESERV) {
@@ -3552,16 +4023,13 @@
                     scp->sense_buffer[2] = NOT_READY;
                     scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
                 }
-#if LINUX_VERSION_CODE >= 0x010300
-                if (scp->done != gdth_scsi_done)
-#endif  
-                {
+                if (scp->done != gdth_scsi_done) {
                     ha->dvr.size = sizeof(ha->dvr.eu.sync);
                     ha->dvr.eu.sync.ionode  = hanum;
                     ha->dvr.eu.sync.service = service;
                     ha->dvr.eu.sync.status  = ha->status;
                     ha->dvr.eu.sync.info    = ha->info;
-                    ha->dvr.eu.sync.hostdrive = scp->target;
+                    ha->dvr.eu.sync.hostdrive = t;
                     if (ha->status >= 0x8000)
                         gdth_store_event(ha, ES_SYNC, 0, &ha->dvr);
                     else
@@ -3651,9 +4119,9 @@
 /*31*/  "\007\000\002\012\001\013\001"
         "GDT HA %u, Fault bus %u, ID %u: old disk detected",
 /*32*/  "\007\000\002\012\001\013\001"
-        "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is illegal",
+        "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is invalid",
 /*33*/  "\007\000\002\012\001\013\001"
-        "GDT HA %u, Fault bus %u, ID %u: illegal device detected",
+        "GDT HA %u, Fault bus %u, ID %u: invalid device detected",
 /*34*/  "\011\000\002\012\001\013\001\006\004"
         "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)",
 /*35*/  "\007\000\002\012\001\013\001"
@@ -3744,13 +4212,11 @@
 static int gdth_async_event(int hanum)
 {
     gdth_ha_str *ha;
-    gdth_msg_str *msg;
     gdth_cmd_str *cmdp;
     int cmd_index;
 
     ha  = HADATA(gdth_ctr_tab[hanum]);
     cmdp= ha->pccb;
-    msg = (gdth_msg_str *)ha->pscratch;
     TRACE2(("gdth_async_event() ha %d serv %d\n",
             hanum,ha->service));
 
@@ -3766,11 +4232,10 @@
             cmdp->BoardNode     = LOCALBOARD;
             cmdp->u.screen.reserved  = 0;
             cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE;
-            cmdp->u.screen.su.msg.msg_addr  = virt_to_bus(msg);
-            ha->scratch_busy = TRUE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
             ha->cmd_offs_dpmem = 0;
             ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
-                + sizeof(ulong32);
+                + sizeof(ulong64);
             ha->cmd_cnt = 0;
             gdth_copy_command(hanum);
             if (ha->type == GDT_EISA)
@@ -3943,6 +4408,8 @@
             virt_ctr = val;
         else if (!strncmp(argv, "shared_access:", 14))
             shared_access = val;
+        else if (!strncmp(argv, "probe_eisa_isa:", 15))
+            probe_eisa_isa = val;
         else if (!strncmp(argv, "reserve_list:", 13)) {
             reserve_list[0] = val;
             for (i = 1; i < MAX_RES_ARGS; i++) {
@@ -3988,10 +4455,11 @@
 GDTH_INITFUNC(int, gdth_detect(Scsi_Host_Template *shtp))
 {
     struct Scsi_Host *shp;
+    gdth_pci_str pcistr[MAXHA];
     gdth_ha_str *ha;
     ulong32 isa_bios;
     ushort eisa_slot;
-    int i,hanum,cnt,ctr;
+    int i,hanum,cnt,ctr,err;
     unchar b;
     
  
@@ -4014,347 +4482,493 @@
     TRACE(("gdth_detect()\n"));
 
     if (disable) {
-        printk("GDT: Controller driver disabled from command line !\n");
+        printk("GDT-HA: Controller driver disabled from command line !\n");
         return 0;
     }
 
-    printk("GDT: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
+    printk("GDT-HA: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
     /* initializations */
     gdth_polling = TRUE; b = 0;
     gdth_clear_events();
 
-    /* scanning for controllers, at first: ISA controller */
-    for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
-        if (gdth_ctr_count >= MAXHA) 
-            break;
-        if (gdth_search_isa(isa_bios)) {        /* controller found */
-            shp = scsi_register(shtp,sizeof(gdth_ext_str));
-            if(shp == NULL)
-            	continue;
-            ha = HADATA(shp);
-            if (!gdth_init_isa(isa_bios,ha)) {
-                scsi_unregister(shp);
-                continue;
-            }
-#ifdef __ia64__
-            break;
-#else
-            /* controller found and initialized */
-            printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
-                   isa_bios,ha->irq,ha->drq);
+    /* As default we do not probe for EISA or ISA controllers */
+    if (probe_eisa_isa) {    
+        /* scanning for controllers, at first: ISA controller */
+        for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
+            dma_addr_t scratch_dma_handle;
+            scratch_dma_handle = 0;
 
-#if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha))
-#else
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
-#endif
-            {
-                printk("GDT-ISA: Unable to allocate IRQ\n");
-                scsi_unregister(shp);
-                continue;
-            }
-            if (request_dma(ha->drq,"gdth")) {
-                printk("GDT-ISA: Unable to allocate DMA channel\n");
-#if LINUX_VERSION_CODE >= 0x010346 
-                free_irq(ha->irq,ha);
-#else
-                free_irq(ha->irq);
-#endif
-                scsi_unregister(shp);
-                continue;
-            }
-            set_dma_mode(ha->drq,DMA_MODE_CASCADE);
-            enable_dma(ha->drq);
-            shp->unchecked_isa_dma = 1;
-            shp->irq = ha->irq;
-            shp->dma_channel = ha->drq;
-            hanum = gdth_ctr_count;         
-            gdth_ctr_tab[gdth_ctr_count++] = shp;
-            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-            NUMDATA(shp)->hanum = (ushort)hanum;
-            NUMDATA(shp)->busnum= 0;
-
-            ha->pccb = CMDDATA(shp);
-#if LINUX_VERSION_CODE >= 0x020322
-            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
-                                                     GDTH_SCRATCH_ORD);
-#else
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
-#endif
-            ha->scratch_busy = FALSE;
-            ha->req_first = NULL;
-            ha->tid_cnt = MAX_HDRIVES;
-            if (max_ids > 0 && max_ids < ha->tid_cnt)
-                ha->tid_cnt = max_ids;
-            for (i=0; i<GDTH_MAXCMDS; ++i)
-                ha->cmd_tab[i].cmnd = UNUSED_CMND;
-            ha->scan_mode = rescan ? 0x10 : 0;
-
-            if (ha->pscratch == NULL || !gdth_search_drives(hanum)) {
-                printk("GDT-ISA: Error during device scan\n");
-                --gdth_ctr_count;
-                --gdth_ctr_vcount;
-                if (ha->pscratch != NULL)
-#if LINUX_VERSION_CODE >= 0x020322
-                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
-#else
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
-#endif
-#if LINUX_VERSION_CODE >= 0x010346 
-                free_irq(ha->irq,ha);
+            if (gdth_ctr_count >= MAXHA) 
+                break;
+            if (gdth_search_isa(isa_bios)) {        /* controller found */
+                shp = scsi_register(shtp,sizeof(gdth_ext_str));
+                if (shp == NULL)
+                    continue;  
+
+                ha = HADATA(shp);
+                if (!gdth_init_isa(isa_bios,ha)) {
+                    scsi_unregister(shp);
+                    continue;
+                }
+#ifdef __ia64__
+                break;
 #else
-                free_irq(ha->irq);
+                /* controller found and initialized */
+                printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
+                       isa_bios,ha->irq,ha->drq);
+
+                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+                    printk("GDT-ISA: Unable to allocate IRQ\n");
+                    scsi_unregister(shp);
+                    continue;
+                }
+                if (request_dma(ha->drq,"gdth")) {
+                    printk("GDT-ISA: Unable to allocate DMA channel\n");
+                    free_irq(ha->irq,ha);
+                    scsi_unregister(shp);
+                    continue;
+                }
+                set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+                enable_dma(ha->drq);
+                shp->unchecked_isa_dma = 1;
+                shp->irq = ha->irq;
+                shp->dma_channel = ha->drq;
+                hanum = gdth_ctr_count;         
+                gdth_ctr_tab[gdth_ctr_count++] = shp;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum= 0;
+
+                ha->pccb = CMDDATA(shp);
+                ha->ccb_phys = 0L;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                ha->pdev = NULL;
+                ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                                    &scratch_dma_handle);
+                ha->scratch_phys = scratch_dma_handle;
+                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                                &scratch_dma_handle);
+                ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+                ha->coal_stat = (gdth_coal_status *)
+                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                        MAXOFFSETS, &scratch_dma_handle);
+                ha->coal_stat_phys = scratch_dma_handle;
+#endif
+#else
+                ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+                if (ha->pscratch)
+                    ha->scratch_phys = virt_to_bus(ha->pscratch);
+                ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA);
+                if (ha->pmsg)
+                    ha->msg_phys = virt_to_bus(ha->pmsg);
+#ifdef INT_COAL
+                ha->coal_stat = 
+                    scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, 
+                                     GFP_ATOMIC | GFP_DMA);
+                if (ha->coal_stat)
+                    ha->coal_stat_phys = virt_to_bus(ha->coal_stat);
+#endif
+#endif
+                ha->scratch_busy = FALSE;
+                ha->req_first = NULL;
+                ha->tid_cnt = MAX_HDRIVES;
+                if (max_ids > 0 && max_ids < ha->tid_cnt)
+                    ha->tid_cnt = max_ids;
+                for (i=0; i<GDTH_MAXCMDS; ++i)
+                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
+                ha->scan_mode = rescan ? 0x10 : 0;
+
+                if (ha->pscratch == NULL || ha->pmsg == NULL || 
+                    !gdth_search_drives(hanum)) {
+                    printk("GDT-ISA: Error during device scan\n");
+                    --gdth_ctr_count;
+                    --gdth_ctr_vcount;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                            MAXOFFSETS, ha->coal_stat,
+                                            ha->coal_stat_phys);
+#endif
+                    if (ha->pscratch)
+                        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            ha->pscratch, ha->scratch_phys);
+                    if (ha->pmsg)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                            ha->pmsg, ha->msg_phys);
+#else
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        scsi_init_free((void *)ha->coal_stat, 
+                                       sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+                    if (ha->pscratch)
+                        scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    if (ha->pmsg)
+                        scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
-                scsi_unregister(shp);
-                continue;
+                    free_irq(ha->irq,ha);
+                    scsi_unregister(shp);
+                    continue;
+                }
+                if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+                    hdr_channel = ha->bus_cnt;
+                ha->virt_bus = hdr_channel;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
+    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                shp->highmem_io  = 0;
+#endif
+                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
+                    shp->max_cmd_len = 16;
+#endif
+                shp->max_id      = ha->tid_cnt;
+                shp->max_lun     = MAXLUN;
+                shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+                if (virt_ctr) {
+                    virt_ctr = 1;
+                    /* register addit. SCSI channels as virtual controllers */
+                    for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                        shp = scsi_register(shtp,sizeof(gdth_num_str));
+                        shp->unchecked_isa_dma = 1;
+                        shp->irq = ha->irq;
+                        shp->dma_channel = ha->drq;
+                        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                        NUMDATA(shp)->hanum = (ushort)hanum;
+                        NUMDATA(shp)->busnum = b;
+                    }
+                }  
+
+                GDTH_INIT_LOCK_HA(ha);
+                gdth_enable_int(hanum);
+#endif /* !__ia64__ */
             }
-            if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
-                hdr_channel = ha->bus_cnt;
-            ha->virt_bus = hdr_channel;
+        }
 
-#if LINUX_VERSION_CODE >= 0x020000
-            shp->max_id      = ha->tid_cnt;
-            shp->max_lun     = MAXLUN;
-            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-            if (virt_ctr)  
+        /* scanning for EISA controllers */
+        for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
+            dma_addr_t scratch_dma_handle;
+            scratch_dma_handle = 0;
+
+            if (gdth_ctr_count >= MAXHA) 
+                break;
+            if (gdth_search_eisa(eisa_slot)) {      /* controller found */
+                shp = scsi_register(shtp,sizeof(gdth_ext_str));
+                if (shp == NULL)
+                    continue;  
+
+                ha = HADATA(shp);
+                if (!gdth_init_eisa(eisa_slot,ha)) {
+                    scsi_unregister(shp);
+                    continue;
+                }
+                /* controller found and initialized */
+                printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+                       eisa_slot>>12,ha->irq);
+
+                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+                    printk("GDT-EISA: Unable to allocate IRQ\n");
+                    scsi_unregister(shp);
+                    continue;
+                }
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                hanum = gdth_ctr_count;
+                gdth_ctr_tab[gdth_ctr_count++] = shp;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum= 0;
+                TRACE2(("EISA detect Bus 0: hanum %d\n",
+                        NUMDATA(shp)->hanum));
+
+                ha->pccb = CMDDATA(shp);
+                ha->ccb_phys = 0L; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                ha->pdev = NULL;
+                ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                                    &scratch_dma_handle);
+                ha->scratch_phys = scratch_dma_handle;
+                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                                &scratch_dma_handle);
+                ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+                ha->coal_stat = (gdth_coal_status *)
+                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                         MAXOFFSETS, &scratch_dma_handle);
+                ha->coal_stat_phys = scratch_dma_handle;
+#endif
+                ha->ccb_phys = 
+                    pci_map_single(ha->pdev,ha->pccb,
+                                   sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+#else
+                ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+                if (ha->pscratch)
+                    ha->scratch_phys = virt_to_bus(ha->pscratch);
+                ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA);
+                if (ha->pmsg)
+                    ha->msg_phys = virt_to_bus(ha->pmsg);
+#ifdef INT_COAL
+                ha->coal_stat = 
+                    scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, 
+                                     GFP_ATOMIC | GFP_DMA);
+                if (ha->coal_stat)
+                    ha->coal_stat_phys = virt_to_bus(ha->coal_stat);
+#endif
+                ha->ccb_phys = virt_to_bus(ha->pccb);
+#endif
+                ha->scratch_busy = FALSE;
+                ha->req_first = NULL;
+                ha->tid_cnt = MAX_HDRIVES;
+                if (max_ids > 0 && max_ids < ha->tid_cnt)
+                    ha->tid_cnt = max_ids;
+                for (i=0; i<GDTH_MAXCMDS; ++i)
+                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
+                ha->scan_mode = rescan ? 0x10 : 0;
+
+                if (ha->pscratch == NULL || ha->pmsg == NULL || 
+                    !gdth_search_drives(hanum)) {
+                    printk("GDT-EISA: Error during device scan\n");
+                    --gdth_ctr_count;
+                    --gdth_ctr_vcount;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                            MAXOFFSETS, ha->coal_stat,
+                                            ha->coal_stat_phys);
+#endif
+                    if (ha->pscratch)
+                        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            ha->pscratch, ha->scratch_phys);
+                    if (ha->pmsg)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                            ha->pmsg, ha->msg_phys);
+                    if (ha->ccb_phys)
+                        pci_unmap_single(ha->pdev,ha->ccb_phys,
+                                        sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+#else
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        scsi_init_free((void *)ha->coal_stat, 
+                                       sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+                    if (ha->pscratch)
+                        scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+                    if (ha->pmsg)
+                        scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
-            {
-                virt_ctr = 1;
-                /* register addit. SCSI channels as virtual controllers */
-                for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                    shp = scsi_register(shtp,sizeof(gdth_num_str));
-                    shp->unchecked_isa_dma = 1;
-                    shp->irq = ha->irq;
-                    shp->dma_channel = ha->drq;
-                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                    NUMDATA(shp)->hanum = (ushort)hanum;
-                    NUMDATA(shp)->busnum = b;
+                    free_irq(ha->irq,ha);
+                    scsi_unregister(shp);
+                    continue;
                 }
-            }  
+                if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+                    hdr_channel = ha->bus_cnt;
+                ha->virt_bus = hdr_channel;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
+    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                shp->highmem_io  = 0;
+#endif
+                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
+                    shp->max_cmd_len = 16;
+#endif
+                shp->max_id      = ha->tid_cnt;
+                shp->max_lun     = MAXLUN;
+                shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+                if (virt_ctr) {
+                    virt_ctr = 1;
+                    /* register addit. SCSI channels as virtual controllers */
+                    for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                        shp = scsi_register(shtp,sizeof(gdth_num_str));
+                        shp->unchecked_isa_dma = 0;
+                        shp->irq = ha->irq;
+                        shp->dma_channel = 0xff;
+                        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                        NUMDATA(shp)->hanum = (ushort)hanum;
+                        NUMDATA(shp)->busnum = b;
+                    }
+                }  
 
-            GDTH_INIT_LOCK_HA(ha);
-            gdth_enable_int(hanum);
-#endif /* !__ia64__ */
+                GDTH_INIT_LOCK_HA(ha);
+                gdth_enable_int(hanum);
+            }
         }
     }
 
-    /* scanning for EISA controllers */
-    for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
-        if (gdth_ctr_count >= MAXHA) 
+    /* scanning for PCI controllers */
+    cnt = gdth_search_pci(pcistr);
+    printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt);
+    gdth_sort_pci(pcistr,cnt);
+    for (ctr = 0; ctr < cnt; ++ctr) {
+        dma_addr_t scratch_dma_handle;
+        scratch_dma_handle = 0;
+
+        if (gdth_ctr_count >= MAXHA)
             break;
-        if (gdth_search_eisa(eisa_slot)) {      /* controller found */
-            shp = scsi_register(shtp,sizeof(gdth_ext_str));
-	    if(shp == NULL)
-		    continue;
-
-            ha = HADATA(shp);
-            if (!gdth_init_eisa(eisa_slot,ha)) {
-                scsi_unregister(shp);
-                continue;
-            }
-            /* controller found and initialized */
-            printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
-                   eisa_slot>>12,ha->irq);
+        shp = scsi_register(shtp,sizeof(gdth_ext_str));
+        if (shp == NULL)
+            continue;  
+
+        ha = HADATA(shp);
+        if (!gdth_init_pci(&pcistr[ctr],ha)) {
+            scsi_unregister(shp);
+            continue;
+        }
+        /* controller found and initialized */
+        printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+               pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
 
-#if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha))
-#else
-            if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth")) 
+        if (request_irq(ha->irq, gdth_interrupt,
+                        SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
+        {
+            printk("GDT-PCI: Unable to allocate IRQ\n");
+            scsi_unregister(shp);
+            continue;
+        }
+        shp->unchecked_isa_dma = 0;
+        shp->irq = ha->irq;
+        shp->dma_channel = 0xff;
+        hanum = gdth_ctr_count;
+        gdth_ctr_tab[gdth_ctr_count++] = shp;
+        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+        NUMDATA(shp)->hanum = (ushort)hanum;
+        NUMDATA(shp)->busnum= 0;
+
+        ha->pccb = CMDDATA(shp);
+        ha->ccb_phys = 0L;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            &scratch_dma_handle);
+        ha->scratch_phys = scratch_dma_handle;
+        ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                        &scratch_dma_handle);
+        ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+        ha->coal_stat = (gdth_coal_status *)
+            pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                 MAXOFFSETS, &scratch_dma_handle);
+        ha->coal_stat_phys = scratch_dma_handle;
+#endif
+#else
+        ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+        if (ha->pscratch)
+            ha->scratch_phys = virt_to_bus(ha->pscratch);
+        ha->pmsg = scsi_init_malloc(sizeof(gdth_msg_str), GFP_ATOMIC | GFP_DMA);
+        if (ha->pmsg)
+            ha->msg_phys = virt_to_bus(ha->pmsg);
+#ifdef INT_COAL
+        ha->coal_stat = 
+            scsi_init_malloc(sizeof(gdth_coal_status) * MAXOFFSETS, 
+                             GFP_ATOMIC | GFP_DMA);
+        if (ha->coal_stat)
+            ha->coal_stat_phys = virt_to_bus(ha->coal_stat);
 #endif
-            {
-                printk("GDT-EISA: Unable to allocate IRQ\n");
-                scsi_unregister(shp);
-                continue;
-            }
-            shp->unchecked_isa_dma = 0;
-            shp->irq = ha->irq;
-            shp->dma_channel = 0xff;
-            hanum = gdth_ctr_count;
-            gdth_ctr_tab[gdth_ctr_count++] = shp;
-            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-            NUMDATA(shp)->hanum = (ushort)hanum;
-            NUMDATA(shp)->busnum= 0;
-            TRACE2(("EISA detect Bus 0: hanum %d\n",
-                    NUMDATA(shp)->hanum));
-
-            ha->pccb = CMDDATA(shp);
-#if LINUX_VERSION_CODE >= 0x020322
-            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
-                                                     GDTH_SCRATCH_ORD);
-#else
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
-#endif
-            ha->scratch_busy = FALSE;
-            ha->req_first = NULL;
-            ha->tid_cnt = MAX_HDRIVES;
-            if (max_ids > 0 && max_ids < ha->tid_cnt)
-                ha->tid_cnt = max_ids;
-            for (i=0; i<GDTH_MAXCMDS; ++i)
-                ha->cmd_tab[i].cmnd = UNUSED_CMND;
-            ha->scan_mode = rescan ? 0x10 : 0;
-
-            if (ha->pscratch == NULL || !gdth_search_drives(hanum)) {
-                printk("GDT-EISA: Error during device scan\n");
-                --gdth_ctr_count;
-                --gdth_ctr_vcount;
-                if (ha->pscratch != NULL)
-#if LINUX_VERSION_CODE >= 0x020322
-                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
-#else
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
 #endif
-#if LINUX_VERSION_CODE >= 0x010346 
-                free_irq(ha->irq,ha);
-#else
-                free_irq(ha->irq);
-#endif
-                scsi_unregister(shp);
-                continue;
-            }
+        ha->scratch_busy = FALSE;
+        ha->req_first = NULL;
+        ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
+        if (max_ids > 0 && max_ids < ha->tid_cnt)
+            ha->tid_cnt = max_ids;
+        for (i=0; i<GDTH_MAXCMDS; ++i)
+            ha->cmd_tab[i].cmnd = UNUSED_CMND;
+        ha->scan_mode = rescan ? 0x10 : 0;
+
+        err = FALSE;
+        if (ha->pscratch == NULL || ha->pmsg == NULL || 
+            !gdth_search_drives(hanum)) {
+            err = TRUE;
+        } else {
             if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
                 hdr_channel = ha->bus_cnt;
             ha->virt_bus = hdr_channel;
 
-#if LINUX_VERSION_CODE >= 0x020000
-            shp->max_id      = ha->tid_cnt;
-            shp->max_lun     = MAXLUN;
-            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-            if (virt_ctr)  
-#endif
-            {
-                virt_ctr = 1;
-                /* register addit. SCSI channels as virtual controllers */
-                for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                    shp = scsi_register(shtp,sizeof(gdth_num_str));
-                    shp->unchecked_isa_dma = 0;
-                    shp->irq = ha->irq;
-                    shp->dma_channel = 0xff;
-                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                    NUMDATA(shp)->hanum = (ushort)hanum;
-                    NUMDATA(shp)->busnum = b;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            scsi_set_device(shp, &pcistr[ctr].pdev->dev);
+#else
+            scsi_set_pci_device(shp, pcistr[ctr].pdev);
+#endif
+            if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
+                /* 64-bit DMA only supported from FW >= x.43 */
+                (!ha->dma64_support)) {
+                if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
+                    err = TRUE;
                 }
-            }  
-
-            GDTH_INIT_LOCK_HA(ha);
-            gdth_enable_int(hanum);
+            } else {
+                shp->max_cmd_len = 16;
+                if (!pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffffffffffffULL)) {
+                    printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
+                } else if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
+                    err = TRUE;
+                }
+            }
+#endif
         }
-    }
 
-    /* scanning for PCI controllers */
-#if LINUX_VERSION_CODE >= 0x2015C
-    if (pci_present())
-#else
-    if (pcibios_present())
+        if (err) {
+            printk("GDT-PCI %d: Error during device scan\n", hanum);
+            --gdth_ctr_count;
+            --gdth_ctr_vcount;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+            if (ha->coal_stat)
+                pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                    MAXOFFSETS, ha->coal_stat,
+                                    ha->coal_stat_phys);
+#endif
+            if (ha->pscratch)
+                pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                    ha->pscratch, ha->scratch_phys);
+            if (ha->pmsg)
+                pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                    ha->pmsg, ha->msg_phys);
+#else
+#ifdef INT_COAL
+            if (ha->coal_stat)
+                scsi_init_free((void *)ha->coal_stat, 
+                               sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+            if (ha->pscratch)
+                scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+            if (ha->pmsg)
+                scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
-    {
-        gdth_pci_str pcistr[MAXHA];
+            free_irq(ha->irq,ha);
+            scsi_unregister(shp);
+            continue;
+        }
 
-        cnt = gdth_search_pci(pcistr);
-	printk("GDT: Found %d PCI Storage RAID Controllers\n",cnt);
-        gdth_sort_pci(pcistr,cnt);
-        for (ctr = 0; ctr < cnt; ++ctr) {
-            if (gdth_ctr_count >= MAXHA)
-                break;
-            shp = scsi_register(shtp,sizeof(gdth_ext_str));
-	    if(shp == NULL)
-		    continue;
-
-            ha = HADATA(shp);
-            if (!gdth_init_pci(&pcistr[ctr],ha)) {
-                scsi_unregister(shp);
-                continue;
-            }
-            /* controller found and initialized */
-            printk("GDT CTR%d: Configuring GDT-PCI HA at %d/%d IRQ %u\n",
-                   ctr,pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
-
-#if LINUX_VERSION_CODE >= 0x010346 
-            if (request_irq(ha->irq, gdth_interrupt,
-                            SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
-#else
-            if (request_irq(ha->irq, gdth_interrupt,
-                            SA_INTERRUPT|SA_SHIRQ, "gdth")) 
-#endif
-            {
-                printk("GDT-PCI: Unable to allocate IRQ\n");
-                scsi_unregister(shp);
-                continue;
-            }
-            shp->unchecked_isa_dma = 0;
-            shp->irq = ha->irq;
-            shp->dma_channel = 0xff;
-            hanum = gdth_ctr_count;
-            gdth_ctr_tab[gdth_ctr_count++] = shp;
-            gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-
-            NUMDATA(shp)->hanum = (ushort)hanum;
-            NUMDATA(shp)->busnum= 0;
-
-            ha->pccb = CMDDATA(shp);
-#if LINUX_VERSION_CODE >= 0x020322
-            ha->pscratch = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
-                                                     GDTH_SCRATCH_ORD);
-#else
-            ha->pscratch = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
-#endif
-            ha->scratch_busy = FALSE;
-            ha->req_first = NULL;
-            ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
-            if (max_ids > 0 && max_ids < ha->tid_cnt)
-                ha->tid_cnt = max_ids;
-            for (i=0; i<GDTH_MAXCMDS; ++i)
-                ha->cmd_tab[i].cmnd = UNUSED_CMND;
-            ha->scan_mode = rescan ? 0x10 : 0;
-
-            if (ha->pscratch == NULL || !gdth_search_drives(hanum)) {
-                printk("GDT-PCI: Error during device scan\n");
-                --gdth_ctr_count;
-                --gdth_ctr_vcount;
-                if (ha->pscratch != NULL)
-#if LINUX_VERSION_CODE >= 0x020322
-                    free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
-#else
-                    scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
-#endif
-#if LINUX_VERSION_CODE >= 0x010346 
-                free_irq(ha->irq,ha);
-#else
-                free_irq(ha->irq);
-#endif
-                scsi_unregister(shp);
-                continue;
+        shp->max_id      = ha->tid_cnt;
+        shp->max_lun     = MAXLUN;
+        shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+        if (virt_ctr) {
+            virt_ctr = 1;
+            /* register addit. SCSI channels as virtual controllers */
+            for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                shp = scsi_register(shtp,sizeof(gdth_num_str));
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum = b;
             }
-            if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
-                hdr_channel = ha->bus_cnt;
-            ha->virt_bus = hdr_channel;
+        }  
 
-#if LINUX_VERSION_CODE >= 0x020000
-            shp->max_id      = ha->tid_cnt;
-            shp->max_lun     = MAXLUN;
-            shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
-            if (virt_ctr)  
-#endif
-            {
-                virt_ctr = 1;
-                /* register addit. SCSI channels as virtual controllers */
-                for (b = 1; b < ha->bus_cnt + 1; ++b) {
-                    shp = scsi_register(shtp,sizeof(gdth_num_str));
-                    shp->unchecked_isa_dma = 0;
-                    shp->irq = ha->irq;
-                    shp->dma_channel = 0xff;
-                    gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
-                    NUMDATA(shp)->hanum = (ushort)hanum;
-                    NUMDATA(shp)->busnum = b;
-                }
-            }  
 
-            GDTH_INIT_LOCK_HA(ha);
-            gdth_enable_int(hanum);
-        }
+        GDTH_INIT_LOCK_HA(ha);
+        gdth_enable_int(hanum);
     }
-
+    
     TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
     if (gdth_ctr_count > 0) {
 #ifdef GDTH_STATISTICS
@@ -4365,9 +4979,8 @@
         gdth_timer.function = gdth_timeout;
         add_timer(&gdth_timer);
 #endif
-#if LINUX_VERSION_CODE >= 0x020100
+        major = register_chrdev(0,"gdth",&gdth_fops);
         register_reboot_notifier(&gdth_notifier);
-#endif
     }
     gdth_polling = FALSE;
     return gdth_ctr_vcount;
@@ -4383,26 +4996,47 @@
     if (NUMDATA(shp)->busnum == 0) {
         hanum = NUMDATA(shp)->hanum;
         ha    = HADATA(gdth_ctr_tab[hanum]);
-#if LINUX_VERSION_CODE >= 0x010300
-        gdth_flush(hanum);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        if (ha->sdev) {
+            scsi_free_host_dev(ha->sdev);
+            ha->sdev = NULL;
+        }
 #endif
+        gdth_flush(hanum);
 
         if (shp->irq) {
-#if LINUX_VERSION_CODE >= 0x010346
             free_irq(shp->irq,ha);
-#else
-            free_irq(shp->irq);
-#endif
         }
 #ifndef __ia64__
         if (shp->dma_channel != 0xff) {
             free_dma(shp->dma_channel);
         }
 #endif
-#if LINUX_VERSION_CODE >= 0x020322
-        free_pages((unsigned long)ha->pscratch, GDTH_SCRATCH_ORD);
-#else
-        scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#ifdef INT_COAL
+        if (ha->coal_stat)
+            pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
+#endif
+        if (ha->pscratch)
+            pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                ha->pscratch, ha->scratch_phys);
+        if (ha->pmsg)
+            pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                ha->pmsg, ha->msg_phys);
+        if (ha->ccb_phys)
+            pci_unmap_single(ha->pdev,ha->ccb_phys,
+                             sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+#else
+#ifdef INT_COAL
+        if (ha->coal_stat)
+            scsi_init_free((void *)ha->coal_stat, 
+                           sizeof(gdth_coal_status) * MAXOFFSETS);
+#endif
+        if (ha->pscratch)
+            scsi_init_free((void *)ha->pscratch, GDTH_SCRATCH);
+        if (ha->pmsg)
+            scsi_init_free((void *)ha->pmsg, sizeof(gdth_msg_str));
 #endif
         gdth_ctr_released++;
         TRACE2(("gdth_release(): HA %d of %d\n", 
@@ -4412,9 +5046,8 @@
 #ifdef GDTH_STATISTICS
             del_timer(&gdth_timer);
 #endif
-#if LINUX_VERSION_CODE >= 0x020100
+            unregister_chrdev(major,"gdth");
             unregister_reboot_notifier(&gdth_notifier);
-#endif
         }
     }
 
@@ -4467,6 +5100,7 @@
     return ((const char *)ha->binfo.type_string);
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 /* old error handling */
 int gdth_abort(Scsi_Cmnd *scp)
 {
@@ -4474,17 +5108,13 @@
     return SCSI_ABORT_SNOOZE;
 }
 
-#if LINUX_VERSION_CODE >= 0x010346
 int gdth_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
-#else
-int gdth_reset(Scsi_Cmnd *scp)
-#endif
 {
     TRACE2(("gdth_reset()\n"));
     return SCSI_RESET_PUNT;
 }
+#endif
 
-#if LINUX_VERSION_CODE >= 0x02015F
 /* new error handling */
 int gdth_eh_abort(Scsi_Cmnd *scp)
 {
@@ -4507,15 +5137,24 @@
     unchar b;
 
     TRACE2(("gdth_eh_bus_reset()\n"));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    hanum = NUMDATA(scp->device->host)->hanum;
+    b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+#else
     hanum = NUMDATA(scp->host)->hanum;
     b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
+#endif
     ha    = HADATA(gdth_ctr_tab[hanum]);
 
     /* clear command tab */
     GDTH_LOCK_HA(ha, flags);
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         cmnd = ha->cmd_tab[i].cmnd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        if (!SPECIAL_SCP(cmnd) && cmnd->device->channel == b)
+#else
         if (!SPECIAL_SCP(cmnd) && cmnd->channel == b)
+#endif
             ha->cmd_tab[i].cmnd = UNUSED_CMND;
     }
     GDTH_UNLOCK_HA(ha, flags);
@@ -4556,32 +5195,41 @@
     TRACE2(("gdth_eh_host_reset()\n"));
     return FAILED;
 }
-#endif
 
-#if LINUX_VERSION_CODE >= 0x010300
-int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
 #else
-int gdth_bios_param(Disk *disk,int dev,int *ip)
+int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
 #endif
 {
     unchar b, t;
     int hanum;
     gdth_ha_str *ha;
+    struct scsi_device *sd;
+    unsigned capacity;
 
-    hanum = NUMDATA(disk->device->host)->hanum;
-    b = virt_ctr ? NUMDATA(disk->device->host)->busnum : disk->device->channel;
-    t = disk->device->id;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sd = sdev;
+    capacity = cap;
+#else
+    sd = disk->device;
+    capacity = disk->capacity;
+#endif
+    hanum = NUMDATA(sd->host)->hanum;
+    b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel;
+    t = sd->id;
     TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); 
     ha = HADATA(gdth_ctr_tab[hanum]);
 
     if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
         /* raw device or host drive without mapping information */
         TRACE2(("Evaluate mapping\n"));
-        gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
+        gdth_eval_mapping(capacity,&ip[2],&ip[0],&ip[1]);
     } else {
         ip[0] = ha->hdr[t].heads;
         ip[1] = ha->hdr[t].secs;
-        ip[2] = disk->capacity / ip[0] / ip[1];
+        ip[2] = capacity / ip[0] / ip[1];
     }
 
     TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
@@ -4595,37 +5243,813 @@
     int hanum;
     int priority;
 
-    TRACE(("gdth_queuecommand() cmd 0x%x id %d lun %d\n",
-           scp->cmnd[0],scp->target,scp->lun));
+    TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0]));
     
     scp->scsi_done = (void *)done;
     scp->SCp.have_data_in = 1;
     scp->SCp.phase = -1;
     scp->SCp.sent_command = -1;
+    scp->SCp.Status = GDTH_MAP_NONE;
+    scp->SCp.buffer = (struct scatterlist *)NULL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    hanum = NUMDATA(scp->device->host)->hanum;
+#else
     hanum = NUMDATA(scp->host)->hanum;
+#endif
 #ifdef GDTH_STATISTICS
     ++act_ios;
 #endif
 
     priority = DEFAULT_PRI;
-#if LINUX_VERSION_CODE >= 0x010300
     if (scp->done == gdth_scsi_done)
         priority = scp->SCp.this_residual;
-#endif
     gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
     gdth_putq( hanum, scp, priority );
     gdth_next( hanum );
     return 0;
 }
 
-#if LINUX_VERSION_CODE >= 0x010300
+
+static int gdth_open(struct inode *inode, struct file *filep)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    gdth_ha_str *ha;
+    int i;
+
+    for (i = 0; i < gdth_ctr_count; i++) {
+        ha = HADATA(gdth_ctr_tab[i]);
+        if (!ha->sdev)
+            ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]);
+    }
+#endif
+
+    TRACE(("gdth_open()\n"));
+    return 0;
+}
+
+static int gdth_close(struct inode *inode, struct file *filep)
+{
+    TRACE(("gdth_close()\n"));
+    return 0;
+}
+
+static int ioc_event(unsigned long arg)
+{
+    gdth_ioctl_event evt;
+    gdth_ha_str *ha;
+    ulong flags;
+
+    if (copy_from_user(&evt, (char *)arg, sizeof(gdth_ioctl_event)) ||
+        evt.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    ha = HADATA(gdth_ctr_tab[evt.ionode]);
+
+    if (evt.erase == 0xff) {
+        if (evt.event.event_source == ES_TEST)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); 
+        else if (evt.event.event_source == ES_DRIVER)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); 
+        else if (evt.event.event_source == ES_SYNC)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); 
+        else
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.async);
+        GDTH_LOCK_HA(ha, flags);
+        gdth_store_event(ha, evt.event.event_source, evt.event.event_idx,
+                         &evt.event.event_data);
+        GDTH_UNLOCK_HA(ha, flags);
+    } else if (evt.erase == 0xfe) {
+        gdth_clear_events();
+    } else if (evt.erase == 0) {
+        evt.handle = gdth_read_event(ha, evt.handle, &evt.event);
+    } else {
+        gdth_readapp_event(ha, evt.erase, &evt.event);
+    }     
+    if (copy_to_user((char *)arg, &evt, sizeof(gdth_ioctl_event)))
+        return -EFAULT;
+    return 0;
+}
+
+static int ioc_lockdrv(unsigned long arg)
+{
+    gdth_ioctl_lockdrv ldrv;
+    unchar i, j;
+    ulong flags;
+    gdth_ha_str *ha;
+
+    if (copy_from_user(&ldrv, (char *)arg, sizeof(gdth_ioctl_lockdrv)) ||
+        ldrv.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
+ 
+    for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
+        j = ldrv.drives[i];
+        if (j >= MAX_HDRIVES || !ha->hdr[j].present)
+            continue;
+        if (ldrv.lock) {
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[j].lock = 1;
+            GDTH_UNLOCK_HA(ha, flags);
+            gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); 
+        } else {
+            GDTH_LOCK_HA(ha, flags);
+            ha->hdr[j].lock = 0;
+            GDTH_UNLOCK_HA(ha, flags);
+            gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_next(ldrv.ionode); 
+        }
+    } 
+    return 0;
+}
+
+static int ioc_resetdrv(unsigned long arg, char *cmnd)
+{
+    gdth_ioctl_reset res;
+    gdth_cmd_str cmd;
+    int hanum;
+    gdth_ha_str *ha;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        Scsi_Cmnd *scp;
+#else
+        Scsi_Cmnd scp;
+#endif
+
+    if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) ||
+        res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
+        return -EFAULT;
+    hanum = res.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+ 
+    if (!ha->hdr[res.number].present)
+        return 0;
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
+    cmd.Service = CACHESERVICE;
+    cmd.OpCode = GDT_CLUST_RESET;
+    if (ha->cache_feat & GDT_64BIT)
+        cmd.u.cache64.DeviceNo = res.number;
+    else
+        cmd.u.cache.DeviceNo = res.number;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+    gdth_do_req(srp, &cmd, cmnd, 30);
+    res.status = (ushort)srp->sr_command->SCp.Status;
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+    gdth_do_cmd(scp, &cmd, cmnd, 30);
+    res.status = (ushort)scp->SCp.Status;
+    scsi_release_command(scp);
+#else
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
+    gdth_do_cmd(&scp, &cmd, cmnd, 30);
+    res.status = (ushort)scp.SCp.Status;
+#endif
+    if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset)))
+        return -EFAULT;
+    return 0;
+}
+
+static int ioc_general(unsigned long arg, char *cmnd)
+{
+    gdth_ioctl_general gen;
+    char *buf = NULL;
+    ulong64 paddr; 
+    int hanum;
+        gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        Scsi_Cmnd *scp;
+#else
+        Scsi_Cmnd scp;
+#endif
+        
+    if (copy_from_user(&gen, (char *)arg, sizeof(gdth_ioctl_general)) ||
+        gen.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = gen.ionode; 
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (gen.data_len + gen.sense_len != 0) {
+        if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, 
+                                     FALSE, &paddr)))
+            return -EFAULT;
+        if (copy_from_user(buf, (char *)arg + sizeof(gdth_ioctl_general),  
+                           gen.data_len + gen.sense_len)) {
+            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            return -EFAULT;
+        }
+
+        if (gen.command.OpCode == GDT_IOCTL) {
+            gen.command.u.ioctl.p_param = paddr;
+        } else if (gen.command.Service == CACHESERVICE) {
+            if (ha->cache_feat & GDT_64BIT) {
+                /* copy elements from 32-bit IOCTL structure */
+                gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt;
+                gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo;
+                gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo;
+                /* addresses */
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    gen.command.u.cache64.DestAddr = (ulong64)-1;
+                    gen.command.u.cache64.sg_canz = 1;
+                    gen.command.u.cache64.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.cache64.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.cache64.DestAddr = paddr;
+                    gen.command.u.cache64.sg_canz = 0;
+                }
+            } else {
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    gen.command.u.cache.DestAddr = 0xffffffff;
+                    gen.command.u.cache.sg_canz = 1;
+                    gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr;
+                    gen.command.u.cache.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.cache.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.cache.DestAddr = paddr;
+                    gen.command.u.cache.sg_canz = 0;
+                }
+            }
+        } else if (gen.command.Service == SCSIRAWSERVICE) {
+            if (ha->raw_feat & GDT_64BIT) {
+                /* copy elements from 32-bit IOCTL structure */
+                char cmd[16];
+                gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len;
+                gen.command.u.raw64.bus = gen.command.u.raw.bus;
+                gen.command.u.raw64.lun = gen.command.u.raw.lun;
+                gen.command.u.raw64.target = gen.command.u.raw.target;
+                memcpy(cmd, gen.command.u.raw.cmd, 16);
+                memcpy(gen.command.u.raw64.cmd, cmd, 16);
+                gen.command.u.raw64.clen = gen.command.u.raw.clen;
+                gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen;
+                gen.command.u.raw64.direction = gen.command.u.raw.direction;
+                /* addresses */
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    gen.command.u.raw64.sdata = (ulong64)-1;
+                    gen.command.u.raw64.sg_ranz = 1;
+                    gen.command.u.raw64.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.raw64.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.raw64.sdata = paddr;
+                    gen.command.u.raw64.sg_ranz = 0;
+                }
+                gen.command.u.raw64.sense_data = paddr + gen.data_len;
+            } else {
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    gen.command.u.raw.sdata = 0xffffffff;
+                    gen.command.u.raw.sg_ranz = 1;
+                    gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr;
+                    gen.command.u.raw.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.raw.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.raw.sdata = paddr;
+                    gen.command.u.raw.sg_ranz = 0;
+                }
+                gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
+            }
+        } else {
+            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            return -EFAULT;
+        }
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+    gdth_do_req(srp, &gen.command, cmnd, gen.timeout);
+    gen.status = srp->sr_command->SCp.Status;
+    gen.info = srp->sr_command->SCp.Message;
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+    gdth_do_cmd(scp, &gen.command, cmnd, gen.timeout);
+    gen.status = scp->SCp.Status;
+    gen.info = scp->SCp.Message;
+    scsi_release_command(scp);
+#else
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
+    gdth_do_cmd(&scp, &gen.command, cmnd, gen.timeout);
+    gen.status = scp.SCp.Status;
+    gen.info = scp.SCp.Message;
+#endif
+
+    if (copy_to_user((char *)arg + sizeof(gdth_ioctl_general), buf, 
+                     gen.data_len + gen.sense_len)) {
+        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        return -EFAULT; 
+    } 
+    if (copy_to_user((char *)arg, &gen, 
+        sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
+        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        return -EFAULT;
+    }
+    gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+    return 0;
+}
+ 
+static int ioc_hdrlist(unsigned long arg, char *cmnd)
+{
+    gdth_ioctl_rescan rsc;
+    gdth_cmd_str cmd;
+    gdth_ha_str *ha;
+    unchar i;
+    int hanum;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Cmnd *scp;
+#else
+    Scsi_Cmnd scp;
+#endif
+        
+    if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) ||
+        rsc.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = rsc.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
+   
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
+#endif
+
+    for (i = 0; i < MAX_HDRIVES; ++i) { 
+        if (!ha->hdr[i].present) {
+            rsc.hdr_list[i].bus = 0xff; 
+            continue;
+        } 
+        rsc.hdr_list[i].bus = ha->virt_bus;
+        rsc.hdr_list[i].target = i;
+        rsc.hdr_list[i].lun = 0;
+        rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+        if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { 
+            cmd.Service = CACHESERVICE;
+            cmd.OpCode = GDT_CLUST_INFO;
+            if (ha->cache_feat & GDT_64BIT)
+                cmd.u.cache64.DeviceNo = i;
+            else
+                cmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(srp, &cmd, cmnd, 30);
+            if (srp->sr_command->SCp.Status == S_OK)
+                rsc.hdr_list[i].cluster_type = srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &cmd, cmnd, 30);
+            if (scp->SCp.Status == S_OK)
+                rsc.hdr_list[i].cluster_type = scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &cmd, cmnd, 30);
+            if (scp.SCp.Status == S_OK)
+                rsc.hdr_list[i].cluster_type = scp.SCp.Message;
+#endif
+        }
+    } 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scsi_release_command(scp);
+#endif       
+ 
+    if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan)))
+        return -EFAULT;
+    return 0;
+}
+
+static int ioc_rescan(unsigned long arg, char *cmnd)
+{
+    gdth_ioctl_rescan rsc;
+    gdth_cmd_str cmd;
+    ushort i, status, hdr_cnt;
+    ulong32 info;
+    int hanum, cyls, hds, secs;
+    ulong flags;
+    gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Cmnd *scp;
+#else
+    Scsi_Cmnd scp;
+#endif
+        
+    if (copy_from_user(&rsc, (char *)arg, sizeof(gdth_ioctl_rescan)) ||
+        rsc.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = rsc.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
+    memset(&ha->sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+    ha->sdev.id = scp.target = ha->sdev.host->this_id;
+    scp.device = &ha->sdev;
+#endif
+     
+    if (rsc.flag == 0) {
+        /* old method: re-init. cache service */
+        cmd.Service = CACHESERVICE;
+        if (ha->cache_feat & GDT_64BIT) {
+            cmd.OpCode = GDT_X_INIT_HOST;
+            cmd.u.cache64.DeviceNo = LINUX_OS;
+        } else {
+            cmd.OpCode = GDT_INIT;
+            cmd.u.cache.DeviceNo = LINUX_OS;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#else
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
+#endif
+        i = 0;
+        hdr_cnt = (status == S_OK ? (ushort)info : 0);
+    } else {
+        i = rsc.hdr_no;
+        hdr_cnt = i + 1;
+    }
+    for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) {
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_INFO;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else 
+            cmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#else
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
+#endif
+        GDTH_LOCK_HA(ha, flags);
+        rsc.hdr_list[i].bus = ha->virt_bus;
+        rsc.hdr_list[i].target = i;
+        rsc.hdr_list[i].lun = 0;
+        if (status != S_OK) {
+            ha->hdr[i].present = FALSE;
+        } else {
+            ha->hdr[i].present = TRUE;
+            ha->hdr[i].size = info;
+            /* evaluate mapping */
+            ha->hdr[i].size &= ~SECS32;
+            gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); 
+            ha->hdr[i].heads = hds;
+            ha->hdr[i].secs = secs;
+            /* round size */
+            ha->hdr[i].size = cyls * hds * secs;
+        }
+        GDTH_UNLOCK_HA(ha, flags);
+        if (status != S_OK)
+            continue; 
+        
+        /* extended info, if GDT_64BIT, for drives > 2 TB */
+        /* but we need ha->info2, not yet stored in scp->SCp */
+
+        /* devtype, cluster info, R/W attribs */
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_DEVTYPE;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else
+            cmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#else
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
+#endif
+        GDTH_LOCK_HA(ha, flags);
+        ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0);
+        GDTH_UNLOCK_HA(ha, flags);
+
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_CLUST_INFO;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else
+            cmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#else
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
+#endif
+        GDTH_LOCK_HA(ha, flags);
+        ha->hdr[i].cluster_type = 
+            ((status == S_OK && !shared_access) ? (ushort)info : 0);
+        GDTH_UNLOCK_HA(ha, flags);
+        rsc.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+
+        cmd.Service = CACHESERVICE;
+        cmd.OpCode = GDT_RW_ATTRIBS;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd.u.cache64.DeviceNo = i;
+        else
+            cmd.u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, &cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, &cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#else
+        gdth_do_cmd(&scp, &cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
+#endif
+        GDTH_LOCK_HA(ha, flags);
+        ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0);
+        GDTH_UNLOCK_HA(ha, flags);
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    scsi_release_command(scp);
+#endif       
+ 
+    if (copy_to_user((char *)arg, &rsc, sizeof(gdth_ioctl_rescan)))
+        return -EFAULT;
+    return 0;
+}
+  
+static int gdth_ioctl(struct inode *inode, struct file *filep,
+                      unsigned int cmd, unsigned long arg)
+{
+    gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Cmnd *scp;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Cmnd *scp;
+#else
+    Scsi_Cmnd scp;
+#endif
+    ulong flags;
+    char cmnd[MAX_COMMAND_SIZE];   
+
+    memset(cmnd, 0xff, 12);
+    
+    TRACE(("gdth_ioctl() cmd 0x%x\n", cmd));
+ 
+    switch (cmd) {
+      case GDTIOCTL_CTRCNT:
+      { 
+        int cnt = gdth_ctr_count;
+        if (put_user(cnt, (int *)arg))
+                return -EFAULT;
+        break;
+      }
+
+      case GDTIOCTL_DRVERS:
+      { 
+        int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
+        if (put_user(ver, (int *)arg))
+                return -EFAULT;
+        break;
+      }
+      
+      case GDTIOCTL_OSVERS:
+      { 
+        gdth_ioctl_osvers osv; 
+
+        osv.version = (unchar)(LINUX_VERSION_CODE >> 16);
+        osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
+        osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
+        if (copy_to_user((char *)arg, &osv, sizeof(gdth_ioctl_osvers)))
+                return -EFAULT;
+        break;
+      }
+
+      case GDTIOCTL_CTRTYPE:
+      { 
+        gdth_ioctl_ctrtype ctrt;
+        
+        if (copy_from_user(&ctrt, (char *)arg, sizeof(gdth_ioctl_ctrtype)) ||
+            ctrt.ionode >= gdth_ctr_count)
+            return -EFAULT;
+        ha = HADATA(gdth_ctr_tab[ctrt.ionode]);
+        if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
+            ctrt.type = (unchar)((ha->stype>>20) - 0x10);
+        } else {
+            if (ha->type != GDT_PCIMPR) {
+                ctrt.type = (unchar)((ha->stype<<4) + 6);
+            } else {
+                ctrt.type = 
+                    (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
+                if (ha->stype >= 0x300)
+                    ctrt.ext_type = 0x6000 | ha->subdevice_id;
+                else 
+                    ctrt.ext_type = 0x6000 | ha->stype;
+            }
+            ctrt.device_id = ha->stype;
+            ctrt.sub_device_id = ha->subdevice_id;
+        }
+        ctrt.info = ha->brd_phys;
+        ctrt.oem_id = ha->oem_id;
+        if (copy_to_user((char *)arg, &ctrt, sizeof(gdth_ioctl_ctrtype)))
+            return -EFAULT;
+        break;
+      }
+        
+      case GDTIOCTL_GENERAL:
+        return ioc_general(arg, cmnd);
+
+      case GDTIOCTL_EVENT:
+        return ioc_event(arg);
+
+      case GDTIOCTL_LOCKDRV:
+        return ioc_lockdrv(arg);
+
+      case GDTIOCTL_LOCKCHN:
+      {
+        gdth_ioctl_lockchn lchn;
+        unchar i, j;
+
+        if (copy_from_user(&lchn, (char *)arg, sizeof(gdth_ioctl_lockchn)) ||
+            lchn.ionode >= gdth_ctr_count)
+            return -EFAULT;
+        ha = HADATA(gdth_ctr_tab[lchn.ionode]);
+        
+        i = lchn.channel;
+        if (i < ha->bus_cnt) {
+            if (lchn.lock) {
+                GDTH_LOCK_HA(ha, flags);
+                ha->raw[i].lock = 1;
+                GDTH_UNLOCK_HA(ha, flags);
+                for (j = 0; j < ha->tid_cnt; ++j) {
+                    gdth_wait_completion(lchn.ionode, i, j); 
+                    gdth_stop_timeout(lchn.ionode, i, j); 
+                }
+            } else {
+                GDTH_LOCK_HA(ha, flags);
+                ha->raw[i].lock = 0;
+                GDTH_UNLOCK_HA(ha, flags);
+                for (j = 0; j < ha->tid_cnt; ++j) {
+                    gdth_start_timeout(lchn.ionode, i, j); 
+                    gdth_next(lchn.ionode); 
+                }
+            }
+        } 
+        break;
+      }
+
+      case GDTIOCTL_RESCAN:
+        return ioc_rescan(arg, cmnd);
+
+      case GDTIOCTL_HDRLIST:
+        return ioc_hdrlist(arg, cmnd);
+
+      case GDTIOCTL_RESET_BUS:
+      {
+        gdth_ioctl_reset res;
+        int hanum, rval;
+
+        if (copy_from_user(&res, (char *)arg, sizeof(gdth_ioctl_reset)) ||
+            res.ionode >= gdth_ctr_count)
+            return -EFAULT;
+        hanum = res.ionode; 
+        ha = HADATA(gdth_ctr_tab[hanum]);
+
+        /* Because we need a Scsi_Cmnd struct., we make a scsi_allocate device also for kernels >=2.6.x */        
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        scp  = scsi_get_command(ha->sdev, GFP_KERNEL);
+        if (!scp)
+            return -ENOMEM;
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
+        scp->device->channel = virt_ctr ? 0 : res.number;
+        rval = gdth_eh_bus_reset(scp);
+        res.status = (rval == SUCCESS ? S_OK : S_GENERR);
+        scsi_put_command(scp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+        if (!scp)
+            return -ENOMEM;
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
+        scp->channel = virt_ctr ? 0 : res.number;
+        rval = gdth_eh_bus_reset(scp);
+        res.status = (rval == SUCCESS ? S_OK : S_GENERR);
+        scsi_release_command(scp);
+#else 
+        memset(&ha->sdev,0,sizeof(Scsi_Device));
+        memset(&scp, 0,sizeof(Scsi_Cmnd));
+        ha->sdev.host = scp.host = gdth_ctr_tab[hanum];
+        ha->sdev.id = scp.target = ha->sdev.host->this_id;
+        scp.device = &ha->sdev;
+        scp.channel = virt_ctr ? 0 : res.number;
+        rval = gdth_eh_bus_reset(&scp);
+        res.status = (rval == SUCCESS ? S_OK : S_GENERR);
+#endif
+        if (copy_to_user((char *)arg, &res, sizeof(gdth_ioctl_reset)))
+            return -EFAULT;
+        break;
+      }
+
+      case GDTIOCTL_RESET_DRV:
+        return ioc_resetdrv(arg, cmnd);
+
+      default:
+        break; 
+    }
+    return 0;
+}
+
+
 /* flush routine */
 static void gdth_flush(int hanum)
 {
     int             i;
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request    *srp;
+    Scsi_Device     *sdev;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd       *scp;
     Scsi_Device     *sdev;
 #else
@@ -4638,9 +6062,18 @@
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+    srp  = scsi_allocate_request(sdev, GFP_KERNEL);
+    if (!srp)
+        return;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
+    if (!scp)
+        return;
     scp->cmd_len = 12;
     scp->use_sg = 0;
 #else
@@ -4656,34 +6089,44 @@
             gdtcmd.BoardNode = LOCALBOARD;
             gdtcmd.Service = CACHESERVICE;
             gdtcmd.OpCode = GDT_FLUSH;
-            gdtcmd.u.cache.DeviceNo = i;
-            gdtcmd.u.cache.BlockNo = 1;
-            gdtcmd.u.cache.sg_canz = 0;
+            if (ha->cache_feat & GDT_64BIT) { 
+                gdtcmd.u.cache64.DeviceNo = i;
+                gdtcmd.u.cache64.BlockNo = 1;
+                gdtcmd.u.cache64.sg_canz = 0;
+            } else {
+                gdtcmd.u.cache.DeviceNo = i;
+                gdtcmd.u.cache.BlockNo = 1;
+                gdtcmd.u.cache.sg_canz = 0;
+            }
             TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(srp, &gdtcmd, cmnd, 30);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
 #else
             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
 #endif
         }
     }
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+    scsi_free_host_dev(sdev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
 #endif
 }
 
 /* shutdown routine */
-#if LINUX_VERSION_CODE >= 0x020100
 static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
-#else
-void gdth_halt(void)
-#endif
 {
     int             hanum;
 #ifndef __alpha__
     gdth_cmd_str    gdtcmd;
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request    *srp;
+    Scsi_Device     *sdev;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd       *scp;
     Scsi_Device     *sdev;
 #else
@@ -4693,47 +6136,51 @@
     char            cmnd[MAX_COMMAND_SIZE];   
 #endif
 
-#if LINUX_VERSION_CODE >= 0x020100
     TRACE2(("gdth_halt() event %d\n",(int)event));
     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
         return NOTIFY_DONE;
-#else
-    TRACE2(("gdth_halt()\n"));
-    if (halt_called) {
-        TRACE2(("already called\n"));
-        return;
-    }
-    halt_called = TRUE;
-#endif
-    printk("GDT: Flushing all host drives .. ");
+
+    printk("GDT-HA: Flushing all host drives .. ");
     for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
         gdth_flush(hanum);
 
 #ifndef __alpha__
         /* controller reset */
         memset(cmnd, 0xff, MAX_COMMAND_SIZE);
-#if LINUX_VERSION_CODE >= 0x020322
+        gdtcmd.BoardNode = LOCALBOARD;
+        gdtcmd.Service = CACHESERVICE;
+        gdtcmd.OpCode = GDT_RESET;
+        TRACE2(("gdth_halt(): reset controller %d\n", hanum));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+        srp  = scsi_allocate_request(sdev, GFP_KERNEL);
+        if (!srp) {
+            unregister_reboot_notifier(&gdth_notifier);
+            return NOTIFY_OK;
+        }
+        srp->sr_cmd_len = 12;
+        srp->sr_use_sg = 0;
+        gdth_do_req(srp, &gdtcmd, cmnd, 10);
+        scsi_release_request(srp);
+        scsi_free_host_dev(sdev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
         scp  = scsi_allocate_device(sdev, 1, FALSE);
+        if (!scp) {
+            unregister_reboot_notifier(&gdth_notifier);
+            return NOTIFY_OK;
+        }
         scp->cmd_len = 12;
         scp->use_sg = 0;
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 10);
+        scsi_release_command(scp);
+        scsi_free_host_dev(sdev);
 #else
         memset(&sdev,0,sizeof(Scsi_Device));
         memset(&scp, 0,sizeof(Scsi_Cmnd));
         sdev.host = scp.host = gdth_ctr_tab[hanum];
         sdev.id = scp.target = sdev.host->this_id;
         scp.device = &sdev;
-#endif
-
-        gdtcmd.BoardNode = LOCALBOARD;
-        gdtcmd.Service = CACHESERVICE;
-        gdtcmd.OpCode = GDT_RESET;
-        TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-#if LINUX_VERSION_CODE >= 0x020322
-        gdth_do_cmd(scp, &gdtcmd, cmnd, 10);
-        scsi_release_command(scp);
-        scsi_free_host_dev(sdev);
-#else
         gdth_do_cmd(&scp, &gdtcmd, cmnd, 10);
 #endif
 #endif
@@ -4743,15 +6190,12 @@
 #ifdef GDTH_STATISTICS
     del_timer(&gdth_timer);
 #endif
-#if LINUX_VERSION_CODE >= 0x020100
     unregister_reboot_notifier(&gdth_notifier);
     return NOTIFY_OK;
-#endif
 }
-#endif
 
 
-#if LINUX_VERSION_CODE < 0x020400 && !defined(MODULE)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) && !defined(MODULE)
 
 GDTH_INITFUNC(void, gdth_setup(char *str,int *ints)) 
 {    
@@ -4762,7 +6206,37 @@
 
 #else
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+static Scsi_Host_Template driver_template = {
+        .proc_name              = "gdth", 
+        .proc_info              = gdth_proc_info,
+        .name                   = "GDT SCSI Disk Array Controller",
+        .detect                 = gdth_detect, 
+        .release                = gdth_release,
+        .info                   = gdth_info, 
+        .queuecommand           = gdth_queuecommand,
+        .eh_abort_handler       = gdth_eh_abort, 
+        .eh_device_reset_handler = gdth_eh_device_reset,
+        .eh_bus_reset_handler   = gdth_eh_bus_reset,
+        .eh_host_reset_handler  = gdth_eh_host_reset,
+        .bios_param             = gdth_bios_param,
+        .can_queue              = GDTH_MAXCMDS,
+        .this_id                = -1,
+        .sg_tablesize           = GDTH_MAXSG,
+        .cmd_per_lun            = GDTH_MAXC_P_L,
+        .unchecked_isa_dma      = 1,
+        .use_clustering         = ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+        .use_new_eh_code        = 1,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
+        .highmem_io             = 1,
+#endif
+#endif
+};
+#else
 static Scsi_Host_Template driver_template = GDTH;
+#endif
+
 #include "scsi_module.c"
 #ifndef MODULE
 __setup("gdth=", option_setup);
diff -urN linux-2.4.28-pre3/drivers/scsi/gdth.h linux-2.4.28-pre4/drivers/scsi/gdth.h
--- linux-2.4.28-pre3/drivers/scsi/gdth.h	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.28-pre4/drivers/scsi/gdth.h	2004-10-08 06:28:25.806265674 -0700
@@ -4,21 +4,18 @@
 /*
  * Header file for the GDT Disk Array/Storage RAID controllers driver for Linux
  * 
- * gdth.h Copyright (C) 1995-02 ICP vortex, an Intel company, Achim Leubner
+ * gdth.h Copyright (C) 1995-03 ICP vortex, Achim Leubner
  * See gdth.c for further informations and 
  * below for supported controller types
  *
- * <achim.leubner@intel.com>
+ * <achim_leubner@adaptec.com>
  *
- * $Id: gdth.h,v 1.46 2002/02/05 09:39:53 achim Exp $
+ * $Id: gdth.h,v 1.57 2004/03/31 11:52:09 achim Exp $
  */
 
 #include <linux/version.h>
 #include <linux/types.h>
 
-#ifndef NULL
-#define NULL 0
-#endif
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -29,16 +26,16 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "2.05"
-#define GDTH_VERSION            2
-#define GDTH_SUBVERSION         5
+#define GDTH_VERSION_STR        "3.04"
+#define GDTH_VERSION            3
+#define GDTH_SUBVERSION         4
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
 
 /* OEM IDs */
-#define OEM_ID_ICP	0x941c
-#define OEM_ID_INTEL	0x8000
+#define OEM_ID_ICP      0x941c
+#define OEM_ID_INTEL    0x8000
 
 /* controller classes */
 #define GDT_ISA         0x01                    /* ISA controller */
@@ -134,18 +131,27 @@
 
 #ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX
 /* new GDT Rx Controller */
-#define PCI_DEVICE_ID_VORTEX_GDTNEWRX	0x300
+#define PCI_DEVICE_ID_VORTEX_GDTNEWRX   0x300
 #endif
-	
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX2
+/* new(2) GDT Rx Controller */
+#define PCI_DEVICE_ID_VORTEX_GDTNEWRX2  0x301
+#endif        
+
 #ifndef PCI_DEVICE_ID_INTEL_SRC
 /* Intel Storage RAID Controller */
-#define PCI_DEVICE_ID_INTEL_SRC		0x600
+#define PCI_DEVICE_ID_INTEL_SRC         0x600
+#endif
+
+#ifndef PCI_DEVICE_ID_INTEL_SRC_XSCALE
+/* Intel Storage RAID Controller */
+#define PCI_DEVICE_ID_INTEL_SRC_XSCALE  0x601
 #endif
 
 /* limits */
 #define GDTH_SCRATCH    PAGE_SIZE               /* 4KB scratch buffer */
-#define GDTH_SCRATCH_ORD 0                      /* order 0 means 1 page */
-#define GDTH_MAXCMDS    124
+#define GDTH_MAXCMDS    120
 #define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
 #define GDTH_MAX_RAW    2                       /* max. cmds per raw device */
 #define MAXOFFSETS      128
@@ -153,8 +159,6 @@
 #define MAXID           127
 #define MAXLUN          8
 #define MAXBUS          6
-#define MAX_HDRIVES     100                     /* max. host drive count */
-#define MAX_LDRIVES     255                     /* max. log. drive count */
 #define MAX_EVENTS      100                     /* event buffer count */
 #define MAX_RES_ARGS    40                      /* device reservation, 
                                                    must be a multiple of 4 */
@@ -221,6 +225,8 @@
 #define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
 #define GDT_FREEZE_IO   25                      /* freezes all IOs */
 #define GDT_UNFREEZE_IO 26                      /* unfreezes all IOs */
+#define GDT_X_INIT_HOST 29                      /* ext. init: 64 bit support */
+#define GDT_X_INFO      30                      /* ext. info for drives>2TB */
 
 /* raw service commands */
 #define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
@@ -230,9 +236,11 @@
 #define GDT_RESET_BUS   18                      /* reset bus */
 #define GDT_SCAN_START  19                      /* start device scan */
 #define GDT_SCAN_END    20                      /* stop device scan */  
+#define GDT_X_INIT_RAW  21                      /* ext. init: 64 bit support */
 
 /* screen service commands */
 #define GDT_REALTIME    3                       /* realtime clock to screens. */
+#define GDT_X_INIT_SCR  4                       /* ext. init: 64 bit support */
 
 /* IOCTL command defines */
 #define SCSI_DR_INFO    0x00                    /* SCSI drive info */                   
@@ -254,6 +262,9 @@
 #define CACHE_DRV_INFO  0x07                    /* cache drive info */
 #define BOARD_FEATURES  0x15                    /* controller features */
 #define BOARD_INFO      0x28                    /* controller info */
+#define SET_PERF_MODES  0x82                    /* set mode (coalescing,..) */
+#define GET_PERF_MODES  0x83                    /* get mode */
+#define CACHE_READ_OEM_STRING_RECORD 0x84       /* read OEM string record */ 
 #define HOST_GET        0x10001L                /* get host drive list */
 #define IO_CHANNEL      0x00020000L             /* default IO channel */
 #define INVALID_CHANNEL 0x0000ffffL             /* invalid channel */
@@ -265,7 +276,8 @@
 #define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
-#define S_CACHE_RESERV	-24			/* cache: reserv. conflict */	
+#define S_NOFUNC        -2                      /* unknown function */
+#define S_CACHE_RESERV  -24                     /* cache: reserv. conflict */   
 
 /* timeout values */
 #define INIT_RETRIES    100000                  /* 100000 * 1ms = 100s */
@@ -292,21 +304,28 @@
 #define MAILBOXREG      0x0c90                  /* mailbox reg. (16 bytes) */
 #define EISAREG         0x0cc0                  /* EISA configuration */
 
+/* DMA memory mappings */
+#define GDTH_MAP_NONE   0
+#define GDTH_MAP_SINGLE 1
+#define GDTH_MAP_SG     2
+#define GDTH_MAP_IOCTL  3 
+
 /* other defines */
 #define LINUX_OS        8                       /* used for cache optim. */
 #define SCATTER_GATHER  1                       /* s/g feature */
-#define GDTH_MAXSG      32                      /* max. s/g elements */
 #define SECS32          0x1f                    /* round capacity */
 #define BIOS_ID_OFFS    0x10                    /* offset contr-ID in ISABIOS */
 #define LOCALBOARD      0                       /* board node always 0 */
 #define ASYNCINDEX      0                       /* cmd index async. event */
 #define SPEZINDEX       1                       /* cmd index unknown service */
-#define GDT_WR_THROUGH  0x100                   /* WRITE_THROUGH supported */
+#define COALINDEX       (GDTH_MAXCMDS + 2)
 
+/* features */
+#define SCATTER_GATHER  1                       /* s/g feature */
+#define GDT_WR_THROUGH  0x100                   /* WRITE_THROUGH supported */
+#define GDT_64BIT       0x200                   /* 64bit / drv>2TB support */
 
-/* typedefs */
-typedef u32     ulong32;
-#define PACKED  __attribute__((packed))
+#include "gdth_ioctl.h"
 
 /* screenservice message */
 typedef struct {                               
@@ -319,7 +338,40 @@
     char        msg_text[MSGLEN+2];             /* the message text */
 } PACKED gdth_msg_str;
 
+
 /* IOCTL data structures */
+
+/* Status coalescing buffer for returning multiple requests per interrupt */
+typedef struct {
+    ulong32     status;
+    ulong32     ext_status;
+    ulong32     info0;
+    ulong32     info1;
+} PACKED gdth_coal_status;
+
+/* performance mode data structure */
+typedef struct {
+    ulong32     version;            /* The version of this IOCTL structure. */
+    ulong32     st_mode;            /* 0=dis., 1=st_buf_addr1 valid, 2=both  */
+    ulong32     st_buff_addr1;      /* physical address of status buffer 1 */
+    ulong32     st_buff_u_addr1;    /* reserved for 64 bit addressing */
+    ulong32     st_buff_indx1;      /* reserved command idx. for this buffer */
+    ulong32     st_buff_addr2;      /* physical address of status buffer 1 */
+    ulong32     st_buff_u_addr2;    /* reserved for 64 bit addressing */
+    ulong32     st_buff_indx2;      /* reserved command idx. for this buffer */
+    ulong32     st_buff_size;       /* size of each buffer in bytes */
+    ulong32     cmd_mode;           /* 0 = mode disabled, 1 = cmd_buff_addr1 */ 
+    ulong32     cmd_buff_addr1;     /* physical address of cmd buffer 1 */   
+    ulong32     cmd_buff_u_addr1;   /* reserved for 64 bit addressing */
+    ulong32     cmd_buff_indx1;     /* cmd buf addr1 unique identifier */
+    ulong32     cmd_buff_addr2;     /* physical address of cmd buffer 1 */   
+    ulong32     cmd_buff_u_addr2;   /* reserved for 64 bit addressing */
+    ulong32     cmd_buff_indx2;     /* cmd buf addr1 unique identifier */
+    ulong32     cmd_buff_size;      /* size of each cmd bufer in bytes */
+    ulong32     reserved1;
+    ulong32     reserved2;
+} PACKED gdth_perf_modes;
+
 /* SCSI drive info */
 typedef struct {
     unchar      vendor[8];                      /* vendor string */
@@ -535,6 +587,50 @@
     unchar      ld_error;                       /* error */
 } PACKED gdth_cdrinfo_str;
 
+/* OEM string */
+typedef struct {
+    ulong32     ctl_version;
+    ulong32     file_major_version;
+    ulong32     file_minor_version;
+    ulong32     buffer_size;
+    ulong32     cpy_count;
+    ulong32     ext_error;
+    ulong32     oem_id;
+    ulong32     board_id;
+} PACKED gdth_oem_str_params;
+
+typedef struct {
+    unchar      product_0_1_name[16];
+    unchar      product_4_5_name[16];
+    unchar      product_cluster_name[16];
+    unchar      product_reserved[16];
+    unchar      scsi_cluster_target_vendor_id[16];
+    unchar      cluster_raid_fw_name[16];
+    unchar      oem_brand_name[16];
+    unchar      oem_raid_type[16];
+    unchar      bios_type[13];
+    unchar      bios_title[50];
+    unchar      oem_company_name[37];
+    ulong32     pci_id_1;
+    ulong32     pci_id_2;
+    unchar      validation_status[80];
+    unchar      reserved_1[4];
+    unchar      scsi_host_drive_inquiry_vendor_id[16];
+    unchar      library_file_template[16];
+    unchar      reserved_2[16];
+    unchar      tool_name_1[32];
+    unchar      tool_name_2[32];
+    unchar      tool_name_3[32];
+    unchar      oem_contact_1[84];
+    unchar      oem_contact_2[84];
+    unchar      oem_contact_3[84];
+} PACKED gdth_oem_str;
+
+typedef struct {
+    gdth_oem_str_params params;
+    gdth_oem_str        text;
+} PACKED gdth_oem_str_ioctl;
+
 /* board features */
 typedef struct {
     unchar      chaining;                       /* Chaining supported */
@@ -594,118 +690,6 @@
     gdth_hentry_str entry[MAX_HDRIVES];         /* entries */
 } PACKED gdth_hget_str;    
 
-/* scatter/gather element */
-typedef struct {
-    ulong32     sg_ptr;                         /* address */
-    ulong32     sg_len;                         /* length */
-} PACKED gdth_sg_str;
-
-/* command structure */
-typedef struct {
-    ulong32     BoardNode;                      /* board node (always 0) */
-    ulong32     CommandIndex;                   /* command number */
-    ushort      OpCode;                         /* the command (READ,..) */
-    union {
-        struct {
-            ushort      DeviceNo;               /* number of cache drive */
-            ulong32     BlockNo;                /* block number */
-            ulong32     BlockCnt;               /* block count */
-            ulong32     DestAddr;               /* dest. addr. (if s/g: -1) */
-            ulong32     sg_canz;                /* s/g element count */
-            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
-        } PACKED cache;                         /* cache service cmd. str. */
-        struct {
-            ushort      param_size;             /* size of p_param buffer */
-            ulong32     subfunc;                /* IOCTL function */
-            ulong32     channel;                /* device */
-            ulong32     p_param;                /* buffer */
-        } PACKED ioctl;                         /* IOCTL command structure */
-        struct {
-            ushort      reserved;
-            union {
-                struct {
-                    ulong32  msg_handle;        /* message handle */
-                    ulong32  msg_addr;          /* message buffer address */
-                } PACKED msg;
-                unchar       data[12];          /* buffer for rtc data, ... */
-            } su;
-        } PACKED screen;                        /* screen service cmd. str. */
-        struct {
-            ushort      reserved;
-            ulong32     direction;              /* data direction */
-            ulong32     mdisc_time;             /* disc. time (0: no timeout)*/
-            ulong32     mcon_time;              /* connect time(0: no to.) */
-            ulong32     sdata;                  /* dest. addr. (if s/g: -1) */
-            ulong32     sdlen;                  /* data length (bytes) */
-            ulong32     clen;                   /* SCSI cmd. length(6,10,12) */
-            unchar      cmd[12];                /* SCSI command */
-            unchar      target;                 /* target ID */
-            unchar      lun;                    /* LUN */
-            unchar      bus;                    /* SCSI bus number */
-            unchar      priority;               /* only 0 used */
-            ulong32     sense_len;              /* sense data length */
-            ulong32     sense_data;             /* sense data addr. */
-            ulong32     link_p;                 /* linked cmds (not supp.) */
-            ulong32     sg_ranz;                /* s/g element count */
-            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
-        } PACKED raw;                           /* raw service cmd. struct. */
-    } u;
-    /* additional variables */
-    unchar      Service;                        /* controller service */
-    ushort      Status;                         /* command result */
-    ulong32     Info;                           /* additional information */
-    Scsi_Cmnd   *RequestBuffer;                 /* request buffer */
-} PACKED gdth_cmd_str;
-
-/* controller event structure */
-#define ES_ASYNC    1
-#define ES_DRIVER   2
-#define ES_TEST     3
-#define ES_SYNC     4
-typedef struct {
-    ushort                  size;               /* size of structure */
-    union {
-        char                stream[16];
-        struct {
-            ushort          ionode;
-            ushort          service;
-            ulong32         index;
-        } PACKED driver;
-        struct {
-            ushort          ionode;
-            ushort          service;
-            ushort          status;
-            ulong32         info;
-            unchar          scsi_coord[3];
-        } PACKED async;
-        struct {
-            ushort          ionode;
-            ushort          service;
-            ushort          status;
-            ulong32         info;
-            ushort          hostdrive;
-            unchar          scsi_coord[3];
-            unchar          sense_key;
-        } PACKED sync;
-        struct {
-            ulong32         l1, l2, l3, l4;
-        } PACKED test;
-    } eu;
-    ulong32                 severity;
-    unchar                  event_string[256];          
-} PACKED gdth_evt_data;
-
-typedef struct {
-    ulong32         first_stamp;
-    ulong32         last_stamp;
-    ushort          same_count;
-    ushort          event_source;
-    ushort          event_idx;
-    unchar          application;
-    unchar          reserved;
-    gdth_evt_data   event_data;
-} PACKED gdth_evt_str;
-
 
 /* DPRAM structures */
 
@@ -860,9 +844,7 @@
 
 /* PCI resources */
 typedef struct {
-#if LINUX_VERSION_CODE >= 0x02015C
     struct pci_dev      *pdev;
-#endif
     ushort              vendor_id;              /* vendor (ICP, Intel, ..) */
     ushort              device_id;              /* device ID (0,..,9) */
     ushort              subdevice_id;           /* sub device ID */
@@ -879,18 +861,28 @@
 typedef struct {
     ushort              oem_id;                 /* OEM */
     ushort              type;                   /* controller class */
-    ushort              raw_feat;               /* feat. raw service (s/g,..) */
     ulong32             stype;                  /* subtype (PCI: device ID) */
     ushort              subdevice_id;           /* sub device ID (PCI) */
     ushort              fw_vers;                /* firmware version */
-    ushort              cache_feat;             /* feat. cache serv. (s/g,..) */
+    ushort              cache_feat;             /* feat. cache serv. (s/g,..)*/
+    ushort              raw_feat;               /* feat. raw service (s/g,..)*/
+    ushort              screen_feat;            /* feat. raw service (s/g,..)*/
     ushort              bmic;                   /* BMIC address (EISA) */
     void                *brd;                   /* DPRAM address */
     ulong32             brd_phys;               /* slot number/BIOS address */
     gdt6c_plx_regs      *plx;                   /* PLX regs (new PCI contr.) */
     gdth_cmd_str        *pccb;                  /* address command structure */
+    ulong32             ccb_phys;               /* phys. address */
+#ifdef INT_COAL
+    gdth_coal_status    *coal_stat;             /* buffer for coalescing int.*/
+    ulong64             coal_stat_phys;         /* phys. address */
+#endif
     char                *pscratch;              /* scratch (DMA) buffer */
+    ulong64             scratch_phys;           /* phys. address */
     unchar              scratch_busy;           /* in use? */
+    unchar              dma64_support;          /* 64-bit DMA supported? */
+    gdth_msg_str        *pmsg;                  /* message buffer */
+    ulong64             msg_phys;               /* phys. address */
     unchar              scan_mode;              /* current scan mode */
     unchar              irq;                    /* IRQ */
     unchar              drq;                    /* DRQ (ISA controllers) */
@@ -911,7 +903,7 @@
         unchar          heads;                  /* mapping */
         unchar          secs;
         ushort          devtype;                /* further information */
-        ulong32         size;                   /* capacity */
+        ulong64         size;                   /* capacity */
         unchar          ldr_no;                 /* log. drive no. */
         unchar          rw_attribs;             /* r/w attributes */
         unchar          cluster_type;           /* cluster properties */
@@ -943,8 +935,18 @@
     gdth_bfeat_str      bfeat;                  /* controller features */
     gdth_binfo_str      binfo;                  /* controller info */
     gdth_evt_data       dvr;                    /* event structure */
-#if LINUX_VERSION_CODE >= 0x02015F
     spinlock_t          smp_lock;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    struct pci_dev      *pdev;
+#endif
+    char                oem_name[8];
+#ifdef GDTH_DMA_STATISTICS
+    ulong               dma32_cnt, dma64_cnt;   /* statistics: DMA buffer */
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Device         *sdev;
+#else
+    Scsi_Device         sdev;
 #endif
 } gdth_ha_str;
 
@@ -983,6 +985,12 @@
     ulong32     block_length;
 } PACKED gdth_rdcap_data;
 
+/* READ_CAPACITY (16) data format */
+typedef struct {
+    ulong64     last_block_no;
+    ulong32     block_length;
+} PACKED gdth_rdcap16_data;
+
 /* REQUEST_SENSE data format */
 typedef struct {
     unchar      errorcode;
@@ -1024,53 +1032,20 @@
 int gdth_detect(Scsi_Host_Template *);
 int gdth_release(struct Scsi_Host *);
 int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
-int gdth_abort(Scsi_Cmnd *);
-#if LINUX_VERSION_CODE >= 0x010346
-int gdth_reset(Scsi_Cmnd *, unsigned int reset_flags);
-#else
-int gdth_reset(Scsi_Cmnd *);
-#endif
 const char *gdth_info(struct Scsi_Host *);
 
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *);
+int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 int gdth_bios_param(Disk *,kdev_t,int *);
 int gdth_proc_info(char *,char **,off_t,int,int,int);
-int gdth_eh_abort(Scsi_Cmnd *scp);
-int gdth_eh_device_reset(Scsi_Cmnd *scp);
-int gdth_eh_bus_reset(Scsi_Cmnd *scp);
-int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#define GDTH { proc_name:       "gdth",                          \
-               proc_info:       gdth_proc_info,                  \
-               name:            "GDT SCSI Disk Array Controller",\
-               detect:          gdth_detect,                     \
-               release:         gdth_release,                    \
-               info:            gdth_info,                       \
-               command:         NULL,                            \
-               queuecommand:    gdth_queuecommand,               \
-               eh_abort_handler: gdth_eh_abort,                  \
-               eh_device_reset_handler: gdth_eh_device_reset,    \
-               eh_bus_reset_handler: gdth_eh_bus_reset,          \
-               eh_host_reset_handler: gdth_eh_host_reset,        \
-               abort:           gdth_abort,                      \
-               reset:           gdth_reset,                      \
-               bios_param:      gdth_bios_param,                 \
-               can_queue:       GDTH_MAXCMDS,                    \
-               this_id:         -1,                              \
-               sg_tablesize:    GDTH_MAXSG,                      \
-               cmd_per_lun:     GDTH_MAXC_P_L,                   \
-               present:         0,                               \
-               unchecked_isa_dma: 1,                             \
-               use_clustering:  ENABLE_CLUSTERING,               \
-               use_new_eh_code: 1       /* use new error code */ }    
-
-#elif LINUX_VERSION_CODE >= 0x02015F
+#else
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
-int gdth_eh_abort(Scsi_Cmnd *scp);
-int gdth_eh_device_reset(Scsi_Cmnd *scp);
-int gdth_eh_bus_reset(Scsi_Cmnd *scp);
-int gdth_eh_host_reset(Scsi_Cmnd *scp);
+int gdth_abort(Scsi_Cmnd *);
+int gdth_reset(Scsi_Cmnd *,unsigned int); 
 #define GDTH { proc_dir:        &proc_scsi_gdth,                 \
                proc_info:       gdth_proc_info,                  \
                name:            "GDT SCSI Disk Array Controller",\
@@ -1094,53 +1069,11 @@
                unchecked_isa_dma: 1,                             \
                use_clustering:  ENABLE_CLUSTERING,               \
                use_new_eh_code: 1       /* use new error code */ }    
-
-#elif LINUX_VERSION_CODE >= 0x010300
-int gdth_bios_param(Disk *,kdev_t,int *);
-extern struct proc_dir_entry proc_scsi_gdth;
-int gdth_proc_info(char *,char **,off_t,int,int,int);
-#define GDTH { NULL, NULL,                              \
-                   &proc_scsi_gdth,                     \
-                   gdth_proc_info,                      \
-                   "GDT SCSI Disk Array Controller",    \
-                   gdth_detect,                         \
-                   gdth_release,                        \
-                   gdth_info,                           \
-                   NULL,                                \
-                   gdth_queuecommand,                   \
-                   gdth_abort,                          \
-                   gdth_reset,                          \
-                   NULL,                                \
-                   gdth_bios_param,                     \
-                   GDTH_MAXCMDS,                        \
-                   -1,                                  \
-                   GDTH_MAXSG,                          \
-                   GDTH_MAXC_P_L,                       \
-                   0,                                   \
-                   1,                                   \
-                   ENABLE_CLUSTERING}
-
-#else
-int gdth_bios_param(Disk *,int,int *);
-#define GDTH { NULL, NULL,                              \
-                   "GDT SCSI Disk Array Controller",    \
-                   gdth_detect,                         \
-                   gdth_release,                        \
-                   gdth_info,                           \
-                   NULL,                                \
-                   gdth_queuecommand,                   \
-                   gdth_abort,                          \
-                   gdth_reset,                          \
-                   NULL,                                \
-                   gdth_bios_param,                     \
-                   GDTH_MAXCMDS,                        \
-                   -1,                                  \
-                   GDTH_MAXSG,                          \
-                   GDTH_MAXC_P_L,                       \
-                   0,                                   \
-                   1,                                   \
-                   ENABLE_CLUSTERING}
 #endif
 
-#endif
+int gdth_eh_abort(Scsi_Cmnd *scp);
+int gdth_eh_device_reset(Scsi_Cmnd *scp);
+int gdth_eh_bus_reset(Scsi_Cmnd *scp);
+int gdth_eh_host_reset(Scsi_Cmnd *scp);
 
+#endif
diff -urN linux-2.4.28-pre3/drivers/scsi/gdth_ioctl.h linux-2.4.28-pre4/drivers/scsi/gdth_ioctl.h
--- linux-2.4.28-pre3/drivers/scsi/gdth_ioctl.h	2001-09-07 09:28:37.000000000 -0700
+++ linux-2.4.28-pre4/drivers/scsi/gdth_ioctl.h	2004-10-08 06:28:25.807265715 -0700
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.10 2001/05/22 06:28:59 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.14 2004/02/19 15:43:15 achim Exp $
  */
 
 /* IOCTLs */
@@ -21,10 +21,172 @@
 #define GDTIOCTL_RESCAN     (GDTIOCTL_MASK |11) /* rescan host drives */
 #define GDTIOCTL_RESET_DRV  (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */
 
-#define GDTIOCTL_MAGIC      0xaffe0004
-#define EVENT_SIZE          294 
-#define MAX_HDRIVES         100                     
+#define GDTIOCTL_MAGIC  0xaffe0004
+#define EVENT_SIZE      294 
+#define GDTH_MAXSG      32                      /* max. s/g elements */
 
+#define MAX_LDRIVES     255                     /* max. log. drive count */
+#ifdef GDTH_IOCTL_PROC
+#define MAX_HDRIVES     100                     /* max. host drive count */
+#else
+#define MAX_HDRIVES     MAX_LDRIVES             /* max. host drive count */
+#endif
+
+/* typedefs */
+#ifdef __KERNEL__
+typedef u32     ulong32;
+typedef u64     ulong64;
+#endif
+
+#define PACKED  __attribute__((packed))
+
+/* scatter/gather element */
+typedef struct {
+    ulong32     sg_ptr;                         /* address */
+    ulong32     sg_len;                         /* length */
+} PACKED gdth_sg_str;
+
+/* scatter/gather element - 64bit addresses */
+typedef struct {
+    ulong64     sg_ptr;                         /* address */
+    ulong32     sg_len;                         /* length */
+} PACKED gdth_sg64_str;
+
+/* command structure */
+typedef struct {
+    ulong32     BoardNode;                      /* board node (always 0) */
+    ulong32     CommandIndex;                   /* command number */
+    ushort      OpCode;                         /* the command (READ,..) */
+    union {
+        struct {
+            ushort      DeviceNo;               /* number of cache drive */
+            ulong32     BlockNo;                /* block number */
+            ulong32     BlockCnt;               /* block count */
+            ulong32     DestAddr;               /* dest. addr. (if s/g: -1) */
+            ulong32     sg_canz;                /* s/g element count */
+            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
+        } PACKED cache;                         /* cache service cmd. str. */
+        struct {
+            ushort      DeviceNo;               /* number of cache drive */
+            ulong64     BlockNo;                /* block number */
+            ulong32     BlockCnt;               /* block count */
+            ulong64     DestAddr;               /* dest. addr. (if s/g: -1) */
+            ulong32     sg_canz;                /* s/g element count */
+            gdth_sg64_str sg_lst[GDTH_MAXSG];   /* s/g list */
+        } PACKED cache64;                       /* cache service cmd. str. */
+        struct {
+            ushort      param_size;             /* size of p_param buffer */
+            ulong32     subfunc;                /* IOCTL function */
+            ulong32     channel;                /* device */
+            ulong64     p_param;                /* buffer */
+        } PACKED ioctl;                         /* IOCTL command structure */
+        struct {
+            ushort      reserved;
+            union {
+                struct {
+                    ulong32  msg_handle;        /* message handle */
+                    ulong64  msg_addr;          /* message buffer address */
+                } PACKED msg;
+                unchar       data[12];          /* buffer for rtc data, ... */
+            } su;
+        } PACKED screen;                        /* screen service cmd. str. */
+        struct {
+            ushort      reserved;
+            ulong32     direction;              /* data direction */
+            ulong32     mdisc_time;             /* disc. time (0: no timeout)*/
+            ulong32     mcon_time;              /* connect time(0: no to.) */
+            ulong32     sdata;                  /* dest. addr. (if s/g: -1) */
+            ulong32     sdlen;                  /* data length (bytes) */
+            ulong32     clen;                   /* SCSI cmd. length(6,10,12) */
+            unchar      cmd[12];                /* SCSI command */
+            unchar      target;                 /* target ID */
+            unchar      lun;                    /* LUN */
+            unchar      bus;                    /* SCSI bus number */
+            unchar      priority;               /* only 0 used */
+            ulong32     sense_len;              /* sense data length */
+            ulong32     sense_data;             /* sense data addr. */
+            ulong32     link_p;                 /* linked cmds (not supp.) */
+            ulong32     sg_ranz;                /* s/g element count */
+            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
+        } PACKED raw;                           /* raw service cmd. struct. */
+        struct {
+            ushort      reserved;
+            ulong32     direction;              /* data direction */
+            ulong32     mdisc_time;             /* disc. time (0: no timeout)*/
+            ulong32     mcon_time;              /* connect time(0: no to.) */
+            ulong64     sdata;                  /* dest. addr. (if s/g: -1) */
+            ulong32     sdlen;                  /* data length (bytes) */
+            ulong32     clen;                   /* SCSI cmd. length(6,..,16) */
+            unchar      cmd[16];                /* SCSI command */
+            unchar      target;                 /* target ID */
+            unchar      lun;                    /* LUN */
+            unchar      bus;                    /* SCSI bus number */
+            unchar      priority;               /* only 0 used */
+            ulong32     sense_len;              /* sense data length */
+            ulong64     sense_data;             /* sense data addr. */
+            ulong32     sg_ranz;                /* s/g element count */
+            gdth_sg64_str sg_lst[GDTH_MAXSG];   /* s/g list */
+        } PACKED raw64;                         /* raw service cmd. struct. */
+    } u;
+    /* additional variables */
+    unchar      Service;                        /* controller service */
+    unchar      reserved;
+    ushort      Status;                         /* command result */
+    ulong32     Info;                           /* additional information */
+    void        *RequestBuffer;                 /* request buffer */
+} PACKED gdth_cmd_str;
+
+/* controller event structure */
+#define ES_ASYNC    1
+#define ES_DRIVER   2
+#define ES_TEST     3
+#define ES_SYNC     4
+typedef struct {
+    ushort                  size;               /* size of structure */
+    union {
+        char                stream[16];
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ulong32         index;
+        } PACKED driver;
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ushort          status;
+            ulong32         info;
+            unchar          scsi_coord[3];
+        } PACKED async;
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ushort          status;
+            ulong32         info;
+            ushort          hostdrive;
+            unchar          scsi_coord[3];
+            unchar          sense_key;
+        } PACKED sync;
+        struct {
+            ulong32         l1, l2, l3, l4;
+        } PACKED test;
+    } eu;
+    ulong32                 severity;
+    unchar                  event_string[256];          
+} PACKED gdth_evt_data;
+
+typedef struct {
+    ulong32         first_stamp;
+    ulong32         last_stamp;
+    ushort          same_count;
+    ushort          event_source;
+    ushort          event_idx;
+    unchar          application;
+    unchar          reserved;
+    gdth_evt_data   event_data;
+} PACKED gdth_evt_str;
+
+
+#ifdef GDTH_IOCTL_PROC
 /* IOCTL structure (write) */
 typedef struct {
     ulong32                 magic;              /* IOCTL magic */
@@ -106,7 +268,80 @@
         } hdr_list[MAX_HDRIVES];                /* index is host drive number */
     } iu;
 } gdth_iord_str;
+#endif
 
+/* GDTIOCTL_GENERAL */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    ushort timeout;                             /* timeout */
+    ulong32 info;                               /* error info */ 
+    ushort status;                              /* status */
+    ulong data_len;                             /* data buffer size */
+    ulong sense_len;                            /* sense buffer size */
+    gdth_cmd_str command;                       /* command */                   
+} gdth_ioctl_general;
 
-#endif
+/* GDTIOCTL_LOCKDRV */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar lock;                                /* lock/unlock */
+    unchar drive_cnt;                           /* drive count */
+    ushort drives[MAX_HDRIVES];                 /* drives */
+} gdth_ioctl_lockdrv;
+
+/* GDTIOCTL_LOCKCHN */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar lock;                                /* lock/unlock */
+    unchar channel;                             /* channel */
+} gdth_ioctl_lockchn;
+
+/* GDTIOCTL_OSVERS */
+typedef struct {
+    unchar version;                             /* OS version */
+    unchar subversion;                          /* OS subversion */
+    ushort revision;                            /* revision */
+} gdth_ioctl_osvers;
 
+/* GDTIOCTL_CTRTYPE */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar type;                                /* controller type */
+    ushort info;                                /* slot etc. */
+    ushort oem_id;                              /* OEM ID */
+    ushort bios_ver;                            /* not used */
+    ushort access;                              /* not used */
+    ushort ext_type;                            /* extended type */
+    ushort device_id;                           /* device ID */
+    ushort sub_device_id;                       /* sub device ID */
+} gdth_ioctl_ctrtype;
+
+/* GDTIOCTL_EVENT */
+typedef struct {
+    ushort ionode;
+    int erase;                                  /* erase event? */
+    int handle;                                 /* event handle */
+    gdth_evt_str event;
+} gdth_ioctl_event;
+
+/* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar flag;                                /* add/remove */
+    ushort hdr_no;                              /* drive no. */
+    struct {
+        unchar bus;                             /* SCSI bus */
+        unchar target;                          /* target ID */
+        unchar lun;                             /* LUN */
+        unchar cluster_type;                    /* cluster properties */
+    } hdr_list[MAX_HDRIVES];                    /* index is host drive number */
+} gdth_ioctl_rescan;
+
+/* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    ushort number;                              /* bus/host drive number */
+    ushort status;                              /* status */
+} gdth_ioctl_reset;
+
+#endif
diff -urN linux-2.4.28-pre3/drivers/scsi/gdth_proc.c linux-2.4.28-pre4/drivers/scsi/gdth_proc.c
--- linux-2.4.28-pre3/drivers/scsi/gdth_proc.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.28-pre4/drivers/scsi/gdth_proc.c	2004-10-08 06:28:25.812265919 -0700
@@ -1,53 +1,80 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.33 2001/08/10 07:54:39 achim Exp $
+ * $Id: gdth_proc.c,v 1.42 2004/03/05 15:50:20 achim Exp $
  */
 
-#include "gdth_ioctl.h"
-#if LINUX_VERSION_CODE >= 0x020407
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
 #include <linux/completion.h>
 #endif
 
-int gdth_proc_info(char *buffer,char **start,off_t offset,int length,   
-                   int hostno,int inout)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,   
+                   int inout)
+{
+    int hanum,busnum;
+
+    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
+            length,(int)offset,inout));
+
+    hanum = NUMDATA(host)->hanum;
+    busnum= NUMDATA(host)->busnum;
+
+    if (inout)
+        return(gdth_set_info(buffer,length,host,hanum,busnum));
+    else
+        return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
+}
+#else
+int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,   
+                   int inout)
 {
     int hanum,busnum,i;
 
-    TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
-            length,hostno,(int)offset,inout));
+    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
+            length,(int)offset,inout));
 
-    for (i=0; i<gdth_ctr_vcount; ++i) {
+    for (i = 0; i < gdth_ctr_vcount; ++i) {
         if (gdth_ctr_vtab[i]->host_no == hostno)
             break;
     }
-    if (i==gdth_ctr_vcount)
+    if (i == gdth_ctr_vcount)
         return(-EINVAL);
 
     hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
     busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
 
     if (inout)
-        return(gdth_set_info(buffer,length,i,hanum,busnum));
+        return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
     else
-        return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum));
+        return(gdth_get_info(buffer,start,offset,length,
+                             gdth_ctr_vtab[i],hanum,busnum));
 }
+#endif
 
-static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
+static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
+                         int hanum,int busnum)
 {
-    int             ret_val;
-#if LINUX_VERSION_CODE >= 0x020322
+    int             ret_val = -EINVAL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request    *scp;
+    Scsi_Device     *sdev;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd       *scp;
     Scsi_Device     *sdev;
 #else
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
 #endif
-    gdth_iowr_str   *piowr;
-
     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
-    piowr = (gdth_iowr_str *)buffer;
 
-#if LINUX_VERSION_CODE >= 0x020322
-    sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(host);
+    scp  = scsi_allocate_request(sdev, GFP_KERNEL);
+    if (!scp)
+        return -ENOMEM;
+    scp->sr_cmd_len = 12;
+    scp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    sdev = scsi_get_host_dev(host);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
     if (!scp)
         return -ENOMEM;
@@ -56,7 +83,7 @@
 #else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.host = scp.host = host;
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
 #endif
@@ -66,28 +93,21 @@
             buffer += 5;
             length -= 5;
             ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
-        } else if (piowr->magic == GDTIOCTL_MAGIC) {
-            ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
-        } else {
-            printk("GDT: Wrong signature %x (%x required)!\n",
-                   piowr->magic, GDTIOCTL_MAGIC);
-            if (piowr->magic > GDTIOCTL_MAGIC)
-                printk("GDT: Please update your driver.\n");
-            else
-                printk("GDT: Please update your tool.\n");
-            ret_val = -EINVAL;
         }
-    } else {
-        ret_val = -EINVAL;
     }
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(scp);
+    scsi_free_host_dev(sdev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
 #endif
     return ret_val;
 }
          
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
 #else
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
@@ -98,6 +118,7 @@
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
+    ulong64         paddr;
 
     char            cmnd[MAX_COMMAND_SIZE];
     memset(cmnd, 0xff, 12);
@@ -131,9 +152,16 @@
                 found = TRUE;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_FLUSH;
-                gdtcmd.u.cache.DeviceNo = i;
-                gdtcmd.u.cache.BlockNo = 1;
-#if LINUX_VERSION_CODE >= 0x020322
+                if (ha->cache_feat & GDT_64BIT) {
+                    gdtcmd.u.cache64.DeviceNo = i;
+                    gdtcmd.u.cache64.BlockNo = 1;
+                } else {
+                    gdtcmd.u.cache.DeviceNo = i;
+                    gdtcmd.u.cache.BlockNo = 1;
+                }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                gdth_do_req(scp, &gdtcmd, cmnd, 30);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
 #else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
@@ -178,23 +206,25 @@
     }
 
     if (wb_mode) {
-        if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE))
+        if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
             return(-EBUSY);
         pcpar = (gdth_cpar_str *)ha->pscratch;
         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_IOCTL;
-        gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar);
+        gdtcmd.u.ioctl.p_param = paddr;
         gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(scp, &gdtcmd, cmnd, 30);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
         gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
 #else
         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
 #endif
-        gdth_ioctl_free(hanum, ha->pscratch);
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
         printk("Done.\n");
         return(orig_length);
     }
@@ -203,489 +233,23 @@
     return(-EINVAL);
 }
 
-#if LINUX_VERSION_CODE >= 0x020322
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
-#else
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
-#endif
-{
-    unchar          i, j;
-    ushort          k, hdr_cnt, status;
-    gdth_ha_str     *ha;
-    gdth_iowr_str   *piowr;
-    gdth_iord_str   *piord;
-    gdth_cmd_str    *pcmd;
-    gdth_evt_str    *pevt;
-    ulong32         *ppadd, add_size, *ppadd2, add_size2, info;
-    ulong           flags;
-    gdth_cmd_str    gdtcmd;
-    int             drv_cyls, drv_hds, drv_secs;
- 
-    char            cmnd[MAX_COMMAND_SIZE];   
-    memset(cmnd, 0xff, 12);
-    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
-
-    TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
-    ha = HADATA(gdth_ctr_tab[hanum]);
-    piowr = (gdth_iowr_str *)buffer;
-    piord = NULL;
-    pcmd = NULL;
-    ppadd = ppadd2 = NULL;
-    add_size = add_size2 = 0;
-
-    if (length < GDTOFFSOF(gdth_iowr_str,iu))
-        return(-EINVAL);
-
-    switch (piowr->ioctl) {
-      case GDTIOCTL_GENERAL:
-        if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0]))
-            return(-EINVAL);
-        pcmd = (gdth_cmd_str *)piowr->iu.general.command;
-        pcmd->Service = piowr->service;
-        if (pcmd->OpCode == GDT_IOCTL) {
-            ppadd = &pcmd->u.ioctl.p_param;
-            add_size = pcmd->u.ioctl.param_size;
-        } else if (piowr->service == CACHESERVICE) {
-            add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE;
-            if (ha->cache_feat & SCATTER_GATHER) {
-                ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr;
-                pcmd->u.cache.DestAddr = 0xffffffff;
-                pcmd->u.cache.sg_lst[0].sg_len = add_size;
-                pcmd->u.cache.sg_canz = 1;
-            } else {
-                ppadd = &pcmd->u.cache.DestAddr;
-                pcmd->u.cache.sg_canz = 0;
-            }
-        } else if (piowr->service == SCSIRAWSERVICE) {
-            add_size = pcmd->u.raw.sdlen;
-            add_size2 = pcmd->u.raw.sense_len;
-            if (ha->raw_feat & SCATTER_GATHER) {
-                ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr;
-                pcmd->u.raw.sdata = 0xffffffff;
-                pcmd->u.raw.sg_lst[0].sg_len = add_size;
-                pcmd->u.raw.sg_ranz = 1;
-            } else {
-                ppadd = &pcmd->u.raw.sdata;
-                pcmd->u.raw.sg_ranz = 0;
-            }
-            ppadd2 = &pcmd->u.raw.sense_data;
-        } else {
-            return(-EINVAL);
-        }
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2,
-                               TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-
-        piord->size = sizeof(gdth_iord_str) + add_size + add_size2;
-        if (add_size > 0) {
-            memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
-            *ppadd = virt_to_bus(piord->iu.general.data);
-        }
-        if (add_size2 > 0) {
-            memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2);
-            *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
-        }
-        /* do IOCTL */
-#if LINUX_VERSION_CODE >= 0x020322
-        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
-#else
-        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
-#endif
-        break;
-
-      case GDTIOCTL_DRVERS:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
-        break;
-
-      case GDTIOCTL_CTRTYPE:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
-            piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 0x10);
-        } else {
-            if (ha->type != GDT_PCIMPR) {
-                piord->iu.ctrtype.type = (unchar)((ha->stype<<4) + 6);
-            } else {
-                piord->iu.ctrtype.type = 
-                    (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
-                if (ha->stype >= 0x300)
-                    piord->iu.ctrtype.ext_type = 0x6000 | ha->subdevice_id;
-                else 
-                    piord->iu.ctrtype.ext_type = 0x6000 | ha->stype;
-            }
-            piord->iu.ctrtype.device_id = ha->stype;
-            piord->iu.ctrtype.sub_device_id = ha->subdevice_id;
-        }
-        piord->iu.ctrtype.info = ha->brd_phys;
-        piord->iu.ctrtype.oem_id = ha->oem_id;
-        break;
-
-      case GDTIOCTL_CTRCNT:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        piord->iu.ctrcnt.count = (ushort)gdth_ctr_count;
-        break;
-
-      case GDTIOCTL_OSVERS:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16);
-        piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
-        piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
-        break;
-
-      case GDTIOCTL_LOCKDRV:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        for (i = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) {
-            j = piowr->iu.lockdrv.drives[i];
-            if (j >= MAX_HDRIVES || !ha->hdr[j].present) 
-                continue;
-            if (piowr->iu.lockdrv.lock) {
-                GDTH_LOCK_HA(ha, flags);
-                ha->hdr[j].lock = 1;
-                GDTH_UNLOCK_HA(ha, flags);
-                gdth_wait_completion( hanum, ha->bus_cnt, j );
-                gdth_stop_timeout( hanum, ha->bus_cnt, j );
-            } else {
-                GDTH_LOCK_HA(ha, flags);
-                ha->hdr[j].lock = 0;
-                GDTH_UNLOCK_HA(ha, flags);
-                gdth_start_timeout( hanum, ha->bus_cnt, j );
-                gdth_next( hanum );
-            }
-        }
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        break;
-
-      case GDTIOCTL_LOCKCHN:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        i = piowr->iu.lockchn.channel;
-        if (i < ha->bus_cnt) {
-            if (piowr->iu.lockchn.lock) {
-                GDTH_LOCK_HA(ha, flags);
-                ha->raw[i].lock = 1;
-                GDTH_UNLOCK_HA(ha, flags);
-                for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_wait_completion( hanum, i, j );
-                    gdth_stop_timeout( hanum, i, j );
-                }
-            } else {
-                GDTH_LOCK_HA(ha, flags);
-                ha->raw[i].lock = 0;
-                GDTH_UNLOCK_HA(ha, flags);
-                for (j = 0; j < ha->tid_cnt; ++j) {
-                    gdth_start_timeout( hanum, i, j );
-                    gdth_next( hanum );
-                }
-            }
-        }
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        break;
-
-      case GDTIOCTL_EVENT:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        if (piowr->iu.event.erase == 0xff) {
-            pevt = (gdth_evt_str *)piowr->iu.event.evt;
-            if (pevt->event_source == ES_TEST) 
-                pevt->event_data.size = sizeof(pevt->event_data.eu.test);
-            else if (pevt->event_source == ES_DRIVER) 
-                pevt->event_data.size = sizeof(pevt->event_data.eu.driver);
-            else if (pevt->event_source == ES_SYNC) 
-                pevt->event_data.size = sizeof(pevt->event_data.eu.sync);
-            else {
-                pevt->event_data.size = sizeof(pevt->event_data.eu.async);
-                gdth_log_event(&pevt->event_data, NULL);
-            }
-            GDTH_LOCK_HA(ha, flags);
-            gdth_store_event(ha, pevt->event_source, pevt->event_idx,
-                             &pevt->event_data);
-            GDTH_UNLOCK_HA(ha, flags);
-        } else if (piowr->iu.event.erase == 0xfe) {
-            gdth_clear_events();
-        } else if (piowr->iu.event.erase == 0) {
-            piord->iu.event.handle = 
-                gdth_read_event(ha,piowr->iu.event.handle,
-                                (gdth_evt_str *)piord->iu.event.evt);
-        } else {
-            piord->iu.event.handle = piowr->iu.event.handle;
-            gdth_readapp_event(ha, (unchar)piowr->iu.event.erase,
-                               (gdth_evt_str *)piord->iu.event.evt);
-        }
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        break;
-
-      case GDTIOCTL_SCSI:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        memcpy(cmnd, piowr->iu.scsi.cmd, 12);
-#if LINUX_VERSION_CODE >= 0x020322
-        scp->target = piowr->iu.scsi.target;
-        scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        scp->cmd_len = piowr->iu.scsi.cmd_len;
-        gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
-#else
-        scp.target = piowr->iu.scsi.target;
-        scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        scp.cmd_len = piowr->iu.scsi.cmd_len;
-        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
-        piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
-#endif
-        break;
-
-      case GDTIOCTL_RESET_BUS:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-#if LINUX_VERSION_CODE >= 0x020322
-        scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        piord->status = (ulong32)gdth_eh_bus_reset( scp );
-        if (piord->status == SUCCESS)
-            piord->status = S_OK;
-        else
-            piord->status = S_GENERR;
-#elif LINUX_VERSION_CODE >= 0x02015F
-        scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
-        piord->status = (ulong32)gdth_eh_bus_reset( &scp );
-        if (piord->status == SUCCESS)
-            piord->status = S_OK;
-        else
-            piord->status = S_GENERR;
-#else
-        piord->status = S_OK;
-#endif
-        break;
-
-      case GDTIOCTL_HDRLIST:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        for (i = 0; i < MAX_HDRIVES; ++i) {
-            if (ha->hdr[i].present) {
-                piord->iu.hdr_list[i].bus = ha->virt_bus;
-                piord->iu.hdr_list[i].target = i;
-                piord->iu.hdr_list[i].lun = 0;
-                piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
-                if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) {  
-                    gdtcmd.Service = CACHESERVICE;
-                    gdtcmd.OpCode = GDT_CLUST_INFO;
-                    gdtcmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020322
-                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                    if (scp->SCp.Status == S_OK)
-                        piord->iu.hdr_list[i].cluster_type = 
-                            (unchar)scp->SCp.Message;
-#else
-                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if (scp.SCp.Status == S_OK)
-                        piord->iu.hdr_list[i].cluster_type = 
-                            (unchar)scp.SCp.Message;
-#endif
-                }
-            } else {
-                piord->iu.hdr_list[i].bus = 0xff;
-            }
-        }
-        break;
-
-      case GDTIOCTL_RESCAN:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        if (piowr->iu.rescan.flag == 0) {
-            /* old method: scan all host drives 
-               re-initialize cache service to get host drive count
-            */
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_INIT;
-            gdtcmd.u.cache.DeviceNo = LINUX_OS;
-#if LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            if (status != S_OK)
-                break;
-            k = 0;
-            hdr_cnt = (ushort)info;
-        } else {
-            k = piowr->iu.rescan.hdr_no;
-            hdr_cnt = k + 1;
-        }
-        if (hdr_cnt > MAX_HDRIVES)
-            hdr_cnt = MAX_HDRIVES;
-        /* scanning for host drives */
-        for (; k < hdr_cnt; ++k) {
-            /* info about host drive */
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_INFO;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            piord->iu.hdr_list[k].bus = ha->virt_bus;
-            piord->iu.hdr_list[k].target = k;
-            piord->iu.hdr_list[k].lun = 0;
-            if (status != S_OK) {
-                ha->hdr[k].present = FALSE;
-            } else {
-                ha->hdr[k].present = TRUE;
-                ha->hdr[k].size = info;
-                /* evaluate mapping (sectors per head, heads per cylinder) */
-                ha->hdr[k].size &= ~SECS32;
-                gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs);
-                ha->hdr[k].heads = (unchar)drv_hds;
-                ha->hdr[k].secs = (unchar)drv_secs;
-                /* round size */
-                ha->hdr[k].size = drv_cyls * drv_hds * drv_secs;
-            }
-            GDTH_UNLOCK_HA(ha, flags);
-            if (status != S_OK)
-                continue;       /* next host drive */
-
-            /* devtype, cluster info, R/W attributes */
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_DEVTYPE;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[k].devtype = 0;
-            if (status == S_OK)
-                ha->hdr[k].devtype = (ushort)info;
-            GDTH_UNLOCK_HA(ha, flags);
-
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_CLUST_INFO;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[k].cluster_type = 0;
-            if (status == S_OK && !shared_access)
-                ha->hdr[k].cluster_type = (ushort)info;
-            GDTH_UNLOCK_HA(ha, flags);
-            piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type;
-
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_RW_ATTRIBS;
-            gdtcmd.u.cache.DeviceNo = k;
-#if LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp->SCp.Status; 
-            info = (ulong32)scp->SCp.Message;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            status = (ushort)scp.SCp.Status;
-            info = (ulong32)scp.SCp.Message;
-#endif
-            GDTH_LOCK_HA(ha, flags);
-            ha->hdr[k].rw_attribs = 0;
-            if (status == S_OK)
-                ha->hdr[k].rw_attribs = (ushort)info;
-            GDTH_UNLOCK_HA(ha, flags);
-        }
-        break;
-
-      case GDTIOCTL_RESET_DRV:
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
-            return(-EBUSY);
-        piord = (gdth_iord_str *)ha->pscratch;
-        piord->size = sizeof(gdth_iord_str);
-        piord->status = S_OK;
-        i = piowr->iu.scsi.target;
-        if (ha->hdr[i].present) {
-            gdtcmd.Service = CACHESERVICE;
-            gdtcmd.OpCode = GDT_CLUST_RESET;
-            gdtcmd.u.cache.DeviceNo = i;
-#if LINUX_VERSION_CODE >= 0x020322
-            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-            piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
-#else
-            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-            piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
-#endif
-        }
-        break;
-
-      default:
-        return(-EINVAL);
-    }
-    return length;
-}
-
-static int gdth_get_info(char *buffer,char **start,off_t offset,
-                         int length,int vh,int hanum,int busnum)
+static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
+                         struct Scsi_Host *host,int hanum,int busnum)
 {
     int size = 0,len = 0;
     off_t begin = 0,pos = 0;
     gdth_ha_str *ha;
-    gdth_iord_str *piord;
     int id, i, j, k, sec, flag;
     int no_mdrv = 0, drv_no, is_mirr;
     ulong32 cnt;
+    ulong64 paddr;
 
     gdth_cmd_str gdtcmd;
     gdth_evt_str estr;
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *scp;
+    Scsi_Device *sdev; 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     Scsi_Cmnd *scp;
     Scsi_Device *sdev;
 #else
@@ -710,8 +274,15 @@
     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
     ha = HADATA(gdth_ctr_tab[hanum]);
 
-#if LINUX_VERSION_CODE >= 0x020322
-    sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(host);
+    scp  = scsi_allocate_request(sdev, GFP_KERNEL);
+    if (!scp)
+        return -ENOMEM;
+    scp->sr_cmd_len = 12;
+    scp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    sdev = scsi_get_host_dev(host);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
     if (!scp)
         return -ENOMEM;
@@ -720,465 +291,415 @@
 #else
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.host = scp.host = host;
     sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
 #endif
-
-    /* ioctl from tool? */
-    if (!gdth_ioctl_check_bin(hanum, (ushort)length)) {
-        /* request is i.e. "cat /proc/scsi/gdth/0" */ 
-        /* format: %-15s\t%-10s\t%-15s\t%s */
-        /* driver parameters */
-        size = sprintf(buffer+len,"Driver Parameters:\n");
-        len += size;  pos = begin + len;
-        if (reserve_list[0] == 0xff)
-            strcpy(hrec, "--");
-        else {
-            sprintf(hrec, "%d", reserve_list[0]);
-            for (i = 1;  i < MAX_RES_ARGS; i++) {
-                if (reserve_list[i] == 0xff) 
-                    break;
-                sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
-            }
+    
+    
+    /* request is i.e. "cat /proc/scsi/gdth/0" */ 
+    /* format: %-15s\t%-10s\t%-15s\t%s */
+    /* driver parameters */
+    size = sprintf(buffer+len,"Driver Parameters:\n");
+    len += size;  pos = begin + len;
+    if (reserve_list[0] == 0xff)
+        strcpy(hrec, "--");
+    else {
+        sprintf(hrec, "%d", reserve_list[0]);
+        for (i = 1;  i < MAX_RES_ARGS; i++) {
+            if (reserve_list[i] == 0xff) 
+                break;
+            sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
         }
-        size = sprintf(buffer+len,
-                       " reserve_mode: \t%d         \treserve_list:  \t%s\n",
-                       reserve_mode, hrec);
-        len += size;  pos = begin + len;
-        size = sprintf(buffer+len,
-                       " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
-                       max_ids, hdr_channel);
-        len += size;  pos = begin + len;
+    }
+    size = sprintf(buffer+len,
+                   " reserve_mode: \t%d         \treserve_list:  \t%s\n",
+                   reserve_mode, hrec);
+    len += size;  pos = begin + len;
+    size = sprintf(buffer+len,
+                   " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
+                   max_ids, hdr_channel);
+    len += size;  pos = begin + len;
+
+    /* controller information */
+    size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
+    len += size;  pos = begin + len;
+    if (virt_ctr)
+        sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
+    else
+        strcpy(hrec, ha->binfo.type_string);
+    size = sprintf(buffer+len,
+                   " Number:       \t%d         \tName:          \t%s\n",
+                   hanum, hrec);
+    len += size;  pos = begin + len;
+
+    if (ha->more_proc)
+        sprintf(hrec, "%d.%02d.%02d-%c%03X", 
+                (unchar)(ha->binfo.upd_fw_ver>>24),
+                (unchar)(ha->binfo.upd_fw_ver>>16),
+                (unchar)(ha->binfo.upd_fw_ver),
+                ha->bfeat.raid ? 'R':'N',
+                ha->binfo.upd_revision);
+    else
+        sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
+                (unchar)(ha->cpar.version));
 
-        /* controller information */
-        size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
-        len += size;  pos = begin + len;
-        if (virt_ctr)
-            sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
-        else
-            strcpy(hrec, ha->binfo.type_string);
+    size = sprintf(buffer+len,
+                   " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
+                   GDTH_VERSION_STR, hrec);
+    len += size;  pos = begin + len;
+ 
+    if (ha->more_proc) {
+        /* more information: 1. about controller */
         size = sprintf(buffer+len,
-                       " Number:       \t%d         \tName:          \t%s\n",
-                       hanum, hrec);
+                       " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
+                       ha->binfo.ser_no, ha->binfo.memsize / 1024);
         len += size;  pos = begin + len;
+    }
 
-        if (ha->more_proc)
-            sprintf(hrec, "%d.%02d.%02d-%c%03X", 
-                    (unchar)(ha->binfo.upd_fw_ver>>24),
-                    (unchar)(ha->binfo.upd_fw_ver>>16),
-                    (unchar)(ha->binfo.upd_fw_ver),
-                    ha->bfeat.raid ? 'R':'N',
-                    ha->binfo.upd_revision);
-        else
-            sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
-                    (unchar)(ha->cpar.version));
+#ifdef GDTH_DMA_STATISTICS
+    /* controller statistics */
+    size = sprintf(buffer+len,"\nController Statistics:\n");
+    len += size;  pos = begin + len;
+    size = sprintf(buffer+len,
+                   " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
+                   ha->dma32_cnt, ha->dma64_cnt);
+    len += size;  pos = begin + len;
+#endif
 
-        size = sprintf(buffer+len,
-                       " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
-                       GDTH_VERSION_STR, hrec);
+    if (pos < offset) {
+        len = 0;
+        begin = pos;
+    }
+    if (pos > offset + length)
+        goto stop_output;
+
+    if (ha->more_proc) {
+        /* more information: 2. about physical devices */
+        size = sprintf(buffer+len,"\nPhysical Devices:");
         len += size;  pos = begin + len;
- 
-        if (pos < offset) {
-            len = 0;
-            begin = pos;
-        }
-        if (pos > offset + length)
+        flag = FALSE;
+            
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
             goto stop_output;
+        for (i = 0; i < ha->bus_cnt; ++i) {
+            /* 2.a statistics (and retries/reassigns) */
+            TRACE2(("pdr_statistics() chn %d\n",i));                
+            pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_IOCTL;
+            gdtcmd.u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
+            gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
+            gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
+            gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
+            pds->bid = ha->raw[i].local_no;
+            pds->first = 0;
+            pds->entries = ha->raw[i].pdev_cnt;
+            cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
+                sizeof(pds->list[0]);
+            if (pds->entries > cnt)
+                pds->entries = cnt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, &gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status != S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            if (scp->SCp.Status != S_OK) 
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            if (scp.SCp.Status != S_OK) 
+#endif
+            { 
+                pds->count = 0;
+            }
 
-        if (ha->more_proc) {
-            /* more information: 1. about controller */
-            size = sprintf(buffer+len,
-                           " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
-                           ha->binfo.ser_no, ha->binfo.memsize / 1024);
-            len += size;  pos = begin + len;
-
-            /* 2. about physical devices */
-            size = sprintf(buffer+len,"\nPhysical Devices:");
-            len += size;  pos = begin + len;
-            flag = FALSE;
-            
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
-            if (!buf) 
-                goto stop_output;
-            for (i = 0; i < ha->bus_cnt; ++i) {
-                /* 2.a statistics (and retries/reassigns) */
-                TRACE2(("pdr_statistics() chn %d\n",i));                
-                pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
+            /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
+            for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
+                /* 2.b drive info */
+                TRACE2(("scsi_drv_info() chn %d dev %d\n",
+                    i, ha->raw[i].id_list[j]));             
+                pdi = (gdth_diskinfo_str *)buf;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
-                gdtcmd.u.ioctl.p_param = virt_to_bus(pds);
-                gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
-                gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
-                gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
-                pds->bid = ha->raw[i].local_no;
-                pds->first = 0;
-                pds->entries = ha->raw[i].pdev_cnt;
-                cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
-                    sizeof(pds->list[0]);
-                if (pds->entries > cnt)
-                    pds->entries = cnt;
-#if LINUX_VERSION_CODE >= 0x020322
+                gdtcmd.u.ioctl.p_param = paddr;
+                gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
+                gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
+                gdtcmd.u.ioctl.channel = 
+                    ha->raw[i].address | ha->raw[i].id_list[j];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                gdth_do_req(scp, &gdtcmd, cmnd, 30);
+                if (scp->sr_command->SCp.Status == S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                if (scp->SCp.Status != S_OK) 
+                if (scp->SCp.Status == S_OK) 
 #else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if (scp.SCp.Status != S_OK) 
+                if (scp.SCp.Status == S_OK) 
 #endif
-                { 
-                    pds->count = 0;
+                {
+                    strncpy(hrec,pdi->vendor,8);
+                    strncpy(hrec+8,pdi->product,16);
+                    strncpy(hrec+24,pdi->revision,4);
+                    hrec[28] = 0;
+                    size = sprintf(buffer+len,
+                                   "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
+                                   'A'+i,pdi->target_id,pdi->lun,hrec);
+                    len += size;  pos = begin + len;
+                    flag = TRUE;
+                    pdi->no_ldrive &= 0xffff;
+                    if (pdi->no_ldrive == 0xffff)
+                        strcpy(hrec,"--");
+                    else
+                        sprintf(hrec,"%d",pdi->no_ldrive);
+                    size = sprintf(buffer+len,
+                                   " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
+                                   pdi->blkcnt/(1024*1024/pdi->blksize),
+                                   hrec);
+                    len += size;  pos = begin + len;
+                } else {
+                    pdi->devtype = 0xff;
                 }
-
-                /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
-                for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
-                    /* 2.b drive info */
-                    TRACE2(("scsi_drv_info() chn %d dev %d\n",
-                        i, ha->raw[i].id_list[j]));             
-                    pdi = (gdth_diskinfo_str *)buf;
-                    gdtcmd.Service = CACHESERVICE;
-                    gdtcmd.OpCode = GDT_IOCTL;
-                    gdtcmd.u.ioctl.p_param = virt_to_bus(pdi);
-                    gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
-                    gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
-                    gdtcmd.u.ioctl.channel = 
-                        ha->raw[i].address | ha->raw[i].id_list[j];
-#if LINUX_VERSION_CODE >= 0x020322
-                    gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                    if (scp->SCp.Status == S_OK) 
-#else
-                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if (scp.SCp.Status == S_OK) 
-#endif
-                    {
-                        strncpy(hrec,pdi->vendor,8);
-                        strncpy(hrec+8,pdi->product,16);
-                        strncpy(hrec+24,pdi->revision,4);
-                        hrec[28] = 0;
-                        size = sprintf(buffer+len,
-                                       "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
-                                       'A'+i,pdi->target_id,pdi->lun,hrec);
-                        len += size;  pos = begin + len;
-                        flag = TRUE;
-                        pdi->no_ldrive &= 0xffff;
-                        if (pdi->no_ldrive == 0xffff)
-                            strcpy(hrec,"--");
-                        else
-                            sprintf(hrec,"%d",pdi->no_ldrive);
-                        size = sprintf(buffer+len,
-                                       " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
-                                       pdi->blkcnt/(1024*1024/pdi->blksize),
-                                       hrec);
-                        len += size;  pos = begin + len;
-                    } else {
-                        pdi->devtype = 0xff;
-                    }
                     
-                    if (pdi->devtype == 0) {
-                        /* search retries/reassigns */
-                        for (k = 0; k < pds->count; ++k) {
-                            if (pds->list[k].tid == pdi->target_id &&
-                                pds->list[k].lun == pdi->lun) {
-                                size = sprintf(buffer+len,
-                                               " Retries:      \t%-6d    \tReassigns:     \t%d\n",
-                                               pds->list[k].retries,
-                                               pds->list[k].reassigns);
-                                len += size;  pos = begin + len;
-                                break;
-                            }
-                        }
-                        /* 2.c grown defects */
-                        TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
-                                i, ha->raw[i].id_list[j]));             
-                        pdef = (gdth_defcnt_str *)buf;
-                        gdtcmd.Service = CACHESERVICE;
-                        gdtcmd.OpCode = GDT_IOCTL;
-                        gdtcmd.u.ioctl.p_param = virt_to_bus(pdef);
-                        gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
-                        gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
-                        gdtcmd.u.ioctl.channel = 
-                            ha->raw[i].address | ha->raw[i].id_list[j];
-                        pdef->sddc_type = 0x08;
-#if LINUX_VERSION_CODE >= 0x020322
-                        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                        if (scp->SCp.Status == S_OK) 
-#else
-                        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                        if (scp.SCp.Status == S_OK) 
-#endif
-                        {
+                if (pdi->devtype == 0) {
+                    /* search retries/reassigns */
+                    for (k = 0; k < pds->count; ++k) {
+                        if (pds->list[k].tid == pdi->target_id &&
+                            pds->list[k].lun == pdi->lun) {
                             size = sprintf(buffer+len,
-                                           " Grown Defects:\t%d\n",
-                                           pdef->sddc_cnt);
+                                           " Retries:      \t%-6d    \tReassigns:     \t%d\n",
+                                           pds->list[k].retries,
+                                           pds->list[k].reassigns);
                             len += size;  pos = begin + len;
+                            break;
                         }
                     }
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
-                }
-            }
-            gdth_ioctl_free(hanum, buf);
-
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
-                len += size;  pos = begin + len;
-            }
-
-            /* 3. about logical drives */
-            size = sprintf(buffer+len,"\nLogical Drives:");
-            len += size;  pos = begin + len;
-            flag = FALSE;
-
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
-            if (!buf) 
-                goto stop_output;
-            for (i = 0; i < MAX_LDRIVES; ++i) {
-                if (!ha->hdr[i].is_logdrv)
-                    continue;
-                drv_no = i;
-                j = k = 0;
-                is_mirr = FALSE;
-                do {
-                    /* 3.a log. drive info */
-                    TRACE2(("cache_drv_info() drive no %d\n",drv_no));
-                    pcdi = (gdth_cdrinfo_str *)buf;
+                    /* 2.c grown defects */
+                    TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
+                            i, ha->raw[i].id_list[j]));             
+                    pdef = (gdth_defcnt_str *)buf;
                     gdtcmd.Service = CACHESERVICE;
                     gdtcmd.OpCode = GDT_IOCTL;
-                    gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi);
-                    gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
-                    gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
-                    gdtcmd.u.ioctl.channel = drv_no;
-#if LINUX_VERSION_CODE >= 0x020322
+                    gdtcmd.u.ioctl.p_param = paddr;
+                    gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
+                    gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
+                    gdtcmd.u.ioctl.channel = 
+                        ha->raw[i].address | ha->raw[i].id_list[j];
+                    pdef->sddc_type = 0x08;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                    gdth_do_req(scp, &gdtcmd, cmnd, 30);
+                    if (scp->sr_command->SCp.Status == S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                     gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                    if (scp->SCp.Status != S_OK)
+                    if (scp->SCp.Status == S_OK) 
 #else
                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                    if (scp.SCp.Status != S_OK)
+                    if (scp.SCp.Status == S_OK) 
 #endif
                     {
-                        break;
-                    }
-                    pcdi->ld_dtype >>= 16;
-                    j++;
-                    if (pcdi->ld_dtype > 2) {
-                        strcpy(hrec, "missing");
-                    } else if (pcdi->ld_error & 1) {
-                        strcpy(hrec, "fault");
-                    } else if (pcdi->ld_error & 2) {
-                        strcpy(hrec, "invalid");
-                        k++; j--;
-                    } else {
-                        strcpy(hrec, "ok");
-                    }
-                    
-                    if (drv_no == i) {
-                        size = sprintf(buffer+len,
-                                       "\n Number:       \t%-2d        \tStatus:        \t%s\n",
-                                       drv_no, hrec);
-                        len += size;  pos = begin + len;
-                        flag = TRUE;
-                        no_mdrv = pcdi->cd_ldcnt;
-                        if (no_mdrv > 1 || pcdi->ld_slave != -1) {
-                            is_mirr = TRUE;
-                            strcpy(hrec, "RAID-1");
-                        } else if (pcdi->ld_dtype == 0) {
-                            strcpy(hrec, "Disk");
-                        } else if (pcdi->ld_dtype == 1) {
-                            strcpy(hrec, "RAID-0");
-                        } else if (pcdi->ld_dtype == 2) {
-                            strcpy(hrec, "Chain");
-                        } else {
-                            strcpy(hrec, "???");
-                        }
-                        size = sprintf(buffer+len,
-                                       " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
-                                       pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
-                                       hrec);
-                        len += size;  pos = begin + len;
-                    } else {
                         size = sprintf(buffer+len,
-                                       " Slave Number: \t%-2d        \tStatus:        \t%s\n",
-                                       drv_no & 0x7fff, hrec);
+                                       " Grown Defects:\t%d\n",
+                                       pdef->sddc_cnt);
                         len += size;  pos = begin + len;
                     }
-                    drv_no = pcdi->ld_slave;
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
-                } while (drv_no != -1);
-                
-                if (is_mirr) {
-                    size = sprintf(buffer+len,
-                                   " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
-                                   no_mdrv - j - k, k);
-                    len += size;  pos = begin + len;
                 }
-                
-                if (!ha->hdr[i].is_arraydrv)
-                    strcpy(hrec, "--");
-                else
-                    sprintf(hrec, "%d", ha->hdr[i].master_no);
-                size = sprintf(buffer+len,
-                               " To Array Drv.:\t%s\n", hrec);
-                len += size;  pos = begin + len;
                 if (pos < offset) {
                     len = 0;
                     begin = pos;
                 }
                 if (pos > offset + length)
                     goto stop_output;
-            }       
-            gdth_ioctl_free(hanum, buf);
-        
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
-                len += size;  pos = begin + len;
-            }   
+            }
+        }
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
 
-            /* 4. about array drives */
-            size = sprintf(buffer+len,"\nArray Drives:");
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
             len += size;  pos = begin + len;
-            flag = FALSE;
+        }
 
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
-            if (!buf) 
-                goto stop_output;
-            for (i = 0; i < MAX_LDRIVES; ++i) {
-                if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
-                    continue;
-                /* 4.a array drive info */
-                TRACE2(("array_info() drive no %d\n",i));
-                pai = (gdth_arrayinf_str *)buf;
+        /* 3. about logical drives */
+        size = sprintf(buffer+len,"\nLogical Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!ha->hdr[i].is_logdrv)
+                continue;
+            drv_no = i;
+            j = k = 0;
+            is_mirr = FALSE;
+            do {
+                /* 3.a log. drive info */
+                TRACE2(("cache_drv_info() drive no %d\n",drv_no));
+                pcdi = (gdth_cdrinfo_str *)buf;
                 gdtcmd.Service = CACHESERVICE;
                 gdtcmd.OpCode = GDT_IOCTL;
-                gdtcmd.u.ioctl.p_param = virt_to_bus(pai);
-                gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
-                gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
-                gdtcmd.u.ioctl.channel = i;
-#if LINUX_VERSION_CODE >= 0x020322
+                gdtcmd.u.ioctl.p_param = paddr;
+                gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
+                gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
+                gdtcmd.u.ioctl.channel = drv_no;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                gdth_do_req(scp, &gdtcmd, cmnd, 30);
+                if (scp->sr_command->SCp.Status != S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                if (scp->SCp.Status == S_OK) 
+                if (scp->SCp.Status != S_OK)
 #else
                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if (scp.SCp.Status == S_OK) 
+                if (scp.SCp.Status != S_OK)
 #endif
                 {
-                    if (pai->ai_state == 0)
-                        strcpy(hrec, "idle");
-                    else if (pai->ai_state == 2)
-                        strcpy(hrec, "build");
-                    else if (pai->ai_state == 4)
-                        strcpy(hrec, "ready");
-                    else if (pai->ai_state == 6)
-                        strcpy(hrec, "fail");
-                    else if (pai->ai_state == 8 || pai->ai_state == 10)
-                        strcpy(hrec, "rebuild");
-                    else
-                        strcpy(hrec, "error");
-                    if (pai->ai_ext_state & 0x10)
-                        strcat(hrec, "/expand");
-                    else if (pai->ai_ext_state & 0x1)
-                        strcat(hrec, "/patch");
+                    break;
+                }
+                pcdi->ld_dtype >>= 16;
+                j++;
+                if (pcdi->ld_dtype > 2) {
+                    strcpy(hrec, "missing");
+                } else if (pcdi->ld_error & 1) {
+                    strcpy(hrec, "fault");
+                } else if (pcdi->ld_error & 2) {
+                    strcpy(hrec, "invalid");
+                    k++; j--;
+                } else {
+                    strcpy(hrec, "ok");
+                }
+                    
+                if (drv_no == i) {
                     size = sprintf(buffer+len,
                                    "\n Number:       \t%-2d        \tStatus:        \t%s\n",
-                                   i,hrec);
+                                   drv_no, hrec);
                     len += size;  pos = begin + len;
                     flag = TRUE;
-
-                    if (pai->ai_type == 0)
+                    no_mdrv = pcdi->cd_ldcnt;
+                    if (no_mdrv > 1 || pcdi->ld_slave != -1) {
+                        is_mirr = TRUE;
+                        strcpy(hrec, "RAID-1");
+                    } else if (pcdi->ld_dtype == 0) {
+                        strcpy(hrec, "Disk");
+                    } else if (pcdi->ld_dtype == 1) {
                         strcpy(hrec, "RAID-0");
-                    else if (pai->ai_type == 4)
-                        strcpy(hrec, "RAID-4");
-                    else if (pai->ai_type == 5)
-                        strcpy(hrec, "RAID-5");
-                    else 
-                        strcpy(hrec, "RAID-10");
+                    } else if (pcdi->ld_dtype == 2) {
+                        strcpy(hrec, "Chain");
+                    } else {
+                        strcpy(hrec, "???");
+                    }
                     size = sprintf(buffer+len,
                                    " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
-                                   pai->ai_size/(1024*1024/pai->ai_secsize),
+                                   pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
                                    hrec);
                     len += size;  pos = begin + len;
-                    if (pos < offset) {
-                        len = 0;
-                        begin = pos;
-                    }
-                    if (pos > offset + length)
-                        goto stop_output;
+                } else {
+                    size = sprintf(buffer+len,
+                                   " Slave Number: \t%-2d        \tStatus:        \t%s\n",
+                                   drv_no & 0x7fff, hrec);
+                    len += size;  pos = begin + len;
                 }
-            }
-            gdth_ioctl_free(hanum, buf);
-        
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
+                drv_no = pcdi->ld_slave;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
+            } while (drv_no != -1);
+             
+            if (is_mirr) {
+                size = sprintf(buffer+len,
+                               " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
+                               no_mdrv - j - k, k);
                 len += size;  pos = begin + len;
             }
-
-            /* 5. about host drives */
-            size = sprintf(buffer+len,"\nHost Drives:");
+              
+            if (!ha->hdr[i].is_arraydrv)
+                strcpy(hrec, "--");
+            else
+                sprintf(hrec, "%d", ha->hdr[i].master_no);
+            size = sprintf(buffer+len,
+                           " To Array Drv.:\t%s\n", hrec);
             len += size;  pos = begin + len;
-            flag = FALSE;
-
-            buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
-            if (!buf) 
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
                 goto stop_output;
-            for (i = 0; i < MAX_LDRIVES; ++i) {
-                if (!ha->hdr[i].is_logdrv || 
-                    (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
-                    continue;
-                /* 5.a get host drive list */
-                TRACE2(("host_get() drv_no %d\n",i));           
-                phg = (gdth_hget_str *)buf;
-                gdtcmd.Service = CACHESERVICE;
-                gdtcmd.OpCode = GDT_IOCTL;
-                gdtcmd.u.ioctl.p_param = virt_to_bus(phg);
-                gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
-                gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
-                gdtcmd.u.ioctl.channel = i;
-                phg->entries = MAX_HDRIVES;
-                phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
-#if LINUX_VERSION_CODE >= 0x020322
-                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
-                if (scp->SCp.Status != S_OK) 
+        }       
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }   
+
+        /* 4. about array drives */
+        size = sprintf(buffer+len,"\nArray Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
+                continue;
+            /* 4.a array drive info */
+            TRACE2(("array_info() drive no %d\n",i));
+            pai = (gdth_arrayinf_str *)buf;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_IOCTL;
+            gdtcmd.u.ioctl.p_param = paddr;
+            gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
+            gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
+            gdtcmd.u.ioctl.channel = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, &gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status == S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            if (scp->SCp.Status == S_OK) 
 #else
-                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
-                if (scp.SCp.Status != S_OK) 
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            if (scp.SCp.Status == S_OK) 
 #endif
-                {
-                    ha->hdr[i].ldr_no = i;
-                    ha->hdr[i].rw_attribs = 0;
-                    ha->hdr[i].start_sec = 0;
-                } else {
-                    for (j = 0; j < phg->entries; ++j) {
-                        k = phg->entry[j].host_drive;
-                        if (k >= MAX_LDRIVES)
-                            continue;
-                        ha->hdr[k].ldr_no = phg->entry[j].log_drive;
-                        ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
-                        ha->hdr[k].start_sec = phg->entry[j].start_sec;
-                    }
-                }
-            }
-            gdth_ioctl_free(hanum, buf);
-
-            for (i = 0; i < MAX_HDRIVES; ++i) {
-                if (!(ha->hdr[i].present))
-                    continue;
-                
+            {
+                if (pai->ai_state == 0)
+                    strcpy(hrec, "idle");
+                else if (pai->ai_state == 2)
+                    strcpy(hrec, "build");
+                else if (pai->ai_state == 4)
+                    strcpy(hrec, "ready");
+                else if (pai->ai_state == 6)
+                    strcpy(hrec, "fail");
+                else if (pai->ai_state == 8 || pai->ai_state == 10)
+                    strcpy(hrec, "rebuild");
+                else
+                    strcpy(hrec, "error");
+                if (pai->ai_ext_state & 0x10)
+                    strcat(hrec, "/expand");
+                else if (pai->ai_ext_state & 0x1)
+                    strcat(hrec, "/patch");
                 size = sprintf(buffer+len,
-                               "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
-                               i, ha->hdr[i].ldr_no);
+                               "\n Number:       \t%-2d        \tStatus:        \t%s\n",
+                               i,hrec);
                 len += size;  pos = begin + len;
                 flag = TRUE;
 
+                if (pai->ai_type == 0)
+                    strcpy(hrec, "RAID-0");
+                else if (pai->ai_type == 4)
+                    strcpy(hrec, "RAID-4");
+                else if (pai->ai_type == 5)
+                    strcpy(hrec, "RAID-5");
+                else 
+                    strcpy(hrec, "RAID-10");
                 size = sprintf(buffer+len,
-                               " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
-                               ha->hdr[i].size/2048, ha->hdr[i].start_sec);
+                               " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
+                               pai->ai_size/(1024*1024/pai->ai_secsize),
+                               hrec);
                 len += size;  pos = begin + len;
                 if (pos < offset) {
                     len = 0;
@@ -1187,53 +708,125 @@
                 if (pos > offset + length)
                     goto stop_output;
             }
+        }
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
         
-            if (!flag) {
-                size = sprintf(buffer+len, "\n --\n");
-                len += size;  pos = begin + len;
-            }
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
         }
 
-        /* controller events */
-        size = sprintf(buffer+len,"\nController Events:\n");
+        /* 5. about host drives */
+        size = sprintf(buffer+len,"\nHost Drives:");
         len += size;  pos = begin + len;
+        flag = FALSE;
 
-        for (id = -1;;) {
-            id = gdth_read_event(ha, id, &estr);
-            if (estr.event_source == 0)
-                break;
-            if (estr.event_data.eu.driver.ionode == hanum &&
-                estr.event_source == ES_ASYNC) { 
-                gdth_log_event(&estr.event_data, hrec);
-                do_gettimeofday(&tv);
-                sec = (int)(tv.tv_sec - estr.first_stamp);
-                if (sec < 0) sec = 0;
-                size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
-                               sec/3600, sec%3600/60, sec%60, hrec);
-                len += size;  pos = begin + len;
-                if (pos < offset) {
-                    len = 0;
-                    begin = pos;
+        buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!ha->hdr[i].is_logdrv || 
+                (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
+                continue;
+            /* 5.a get host drive list */
+            TRACE2(("host_get() drv_no %d\n",i));           
+            phg = (gdth_hget_str *)buf;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_IOCTL;
+            gdtcmd.u.ioctl.p_param = paddr;
+            gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
+            gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
+            gdtcmd.u.ioctl.channel = i;
+            phg->entries = MAX_HDRIVES;
+            phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, &gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status != S_OK) 
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            if (scp->SCp.Status != S_OK) 
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            if (scp.SCp.Status != S_OK) 
+#endif
+            {
+                ha->hdr[i].ldr_no = i;
+                ha->hdr[i].rw_attribs = 0;
+                ha->hdr[i].start_sec = 0;
+            } else {
+                for (j = 0; j < phg->entries; ++j) {
+                    k = phg->entry[j].host_drive;
+                    if (k >= MAX_LDRIVES)
+                        continue;
+                    ha->hdr[k].ldr_no = phg->entry[j].log_drive;
+                    ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
+                    ha->hdr[k].start_sec = phg->entry[j].start_sec;
                 }
-                if (pos > offset + length)
-                    goto stop_output;
             }
-            if (id == -1)
-                break;
         }
-    } else {
-        /* request from tool (GDTMON,..) */
-        piord = (gdth_iord_str *)ha->pscratch;
-        if (piord == NULL)
-            goto stop_output;
-        length = piord->size;
-        memcpy(buffer+len, (char *)piord, length);
-        gdth_ioctl_free(hanum, ha->pscratch);
-        len = length; 
+        gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
+
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (!(ha->hdr[i].present))
+                continue;
+              
+            size = sprintf(buffer+len,
+                           "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
+                           i, ha->hdr[i].ldr_no);
+            len += size;  pos = begin + len;
+            flag = TRUE;
+
+            size = sprintf(buffer+len,
+                           " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
+                           (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }
+    }
+
+    /* controller events */
+    size = sprintf(buffer+len,"\nController Events:\n");
+    len += size;  pos = begin + len;
+
+    for (id = -1;;) {
+        id = gdth_read_event(ha, id, &estr);
+        if (estr.event_source == 0)
+            break;
+        if (estr.event_data.eu.driver.ionode == hanum &&
+            estr.event_source == ES_ASYNC) { 
+            gdth_log_event(&estr.event_data, hrec);
+            do_gettimeofday(&tv);
+            sec = (int)(tv.tv_sec - estr.first_stamp);
+            if (sec < 0) sec = 0;
+            size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
+                           sec/3600, sec%3600/60, sec%60, hrec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+        if (id == -1)
+            break;
     }
 
 stop_output:
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(scp);
+    scsi_free_host_dev(sdev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_release_command(scp);
     scsi_free_host_dev(sdev);
 #endif
@@ -1246,13 +839,34 @@
     return(len);
 }
 
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static void gdth_do_req(Scsi_Request *scp, gdth_cmd_str *gdtcmd, 
+                        char *cmnd, int timeout)
+{
+    unsigned bufflen;
+    DECLARE_COMPLETION(wait);
+
+    TRACE2(("gdth_do_req()\n"));
+    if (gdtcmd != NULL) { 
+        bufflen = sizeof(gdth_cmd_str);
+    } else {
+        bufflen = 0;
+    }
+    scp->sr_request->rq_status = RQ_SCSI_BUSY;
+    scp->sr_request->waiting = &wait;
+    scsi_do_req(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
+    wait_for_completion(&wait);
+}
+
+#else
 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
                         char *cmnd, int timeout)
 {
     unsigned bufflen;
-#if LINUX_VERSION_CODE >= 0x020407
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
     DECLARE_COMPLETION(wait);
-#elif LINUX_VERSION_CODE >= 0x020322
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     DECLARE_MUTEX_LOCKED(sem);
 #else
     struct semaphore sem = MUTEX_LOCKED;
@@ -1266,63 +880,73 @@
         scp->SCp.this_residual = DEFAULT_PRI;
         bufflen = 0;
     }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
     scp->request.rq_status = RQ_SCSI_BUSY;
-#if LINUX_VERSION_CODE >= 0x020407
     scp->request.waiting = &wait;
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
     wait_for_completion(&wait);
 #else
     scp->request.sem = &sem;
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
 #else
-    GDTH_LOCK_SCSI_DOCMD();
+    spin_lock_irq(&io_request_lock);
     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
-    GDTH_UNLOCK_SCSI_DOCMD();
+    spin_unlock_irq(&io_request_lock);
 #endif
     down(&sem);
 #endif
 }
+#endif
 
 void gdth_scsi_done(Scsi_Cmnd *scp)
 {
     TRACE2(("gdth_scsi_done()\n"));
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scp->request->rq_status = RQ_SCSI_DONE;
+    if (scp->request->waiting != NULL)
+        complete(scp->request->waiting);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
     scp->request.rq_status = RQ_SCSI_DONE;
-
-#if LINUX_VERSION_CODE >= 0x020407
     if (scp->request.waiting != NULL)
         complete(scp->request.waiting);
 #else
+    scp->request.rq_status = RQ_SCSI_DONE;
     if (scp->request.sem != NULL)
         up(scp->request.sem);
 #endif
 }
 
-static char *gdth_ioctl_alloc(int hanum, ushort size, int scratch)
+static char *gdth_ioctl_alloc(int hanum, int size, int scratch, 
+                              ulong64 *paddr)
 {
     gdth_ha_str *ha;
     ulong flags;
     char *ret_val;
 
-    if (size == 0 || size > GDTH_SCRATCH)
-        return FALSE;
+    if (size == 0)
+        return NULL;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
-    if (scratch) { 
-        if (!ha->scratch_busy) {
-            ha->scratch_busy = TRUE;
-            ret_val = ha->pscratch;
-        } else
-            ret_val = NULL;
+    if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
+        ha->scratch_busy = TRUE;
+        ret_val = ha->pscratch;
+        *paddr = ha->scratch_phys;
+    } else if (scratch) {
+        ret_val = NULL;
     } else {
-#if LINUX_VERSION_CODE >= 0x020322
-        ret_val = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
-                                            GDTH_SCRATCH_ORD);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        dma_addr_t dma_addr;
+
+        ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr);
+        *paddr = dma_addr;
 #else
-        ret_val = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
+        ret_val = scsi_init_malloc(size, GFP_ATOMIC | GFP_DMA);
+        if (ret_val)
+            *paddr = virt_to_bus(ret_val);
 #endif
     }
 
@@ -1330,7 +954,7 @@
     return ret_val;
 }
 
-static void gdth_ioctl_free(int hanum, char *buf)
+static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
 {
     gdth_ha_str *ha;
     ulong flags;
@@ -1341,16 +965,17 @@
     if (buf == ha->pscratch) {
         ha->scratch_busy = FALSE;
     } else {
-#if LINUX_VERSION_CODE >= 0x020322
-        free_pages((unsigned long)buf, GDTH_SCRATCH_ORD);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        pci_free_consistent(ha->pdev, size, buf, paddr);
 #else
-        scsi_init_free((void *)buf, GDTH_SCRATCH);
+        scsi_init_free((void *)buf, size);
 #endif
     }
 
     GDTH_UNLOCK_HA(ha, flags);
 }
 
+#ifdef GDTH_IOCTL_PROC
 static int gdth_ioctl_check_bin(int hanum, ushort size)
 {
     gdth_ha_str *ha;
@@ -1368,7 +993,7 @@
     GDTH_UNLOCK_HA(ha, flags);
     return ret_val;
 }
-
+#endif
 
 static void gdth_wait_completion(int hanum, int busnum, int id)
 {
@@ -1376,23 +1001,35 @@
     ulong flags;
     int i;
     Scsi_Cmnd *scp;
-    unchar b;
+    unchar b, t;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         scp = ha->cmd_tab[i].cmnd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+#else
         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
-        if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && 
+        t = scp->target;
+#endif
+        if (!SPECIAL_SCP(scp) && t == (unchar)id && 
             b == (unchar)busnum) {
             scp->SCp.have_data_in = 0;
             GDTH_UNLOCK_HA(ha, flags);
             while (!scp->SCp.have_data_in)
                 barrier();
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
+            scp->scsi_done(scp);
+            GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
+#else
             GDTH_LOCK_SCSI_DONE(flags);
             scp->scsi_done(scp);
             GDTH_UNLOCK_SCSI_DONE(flags);
+#endif
         GDTH_LOCK_HA(ha, flags);
         }
     }
@@ -1404,14 +1041,20 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
-    unchar b;
+    unchar b, t;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+#else
         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
-        if (scp->target == (unchar)id && b == (unchar)busnum) {
+        t = scp->target;
+#endif
+        if (t == (unchar)id && b == (unchar)busnum) {
             TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
         }
@@ -1424,14 +1067,20 @@
     gdth_ha_str *ha;
     ulong flags;
     Scsi_Cmnd *scp;
-    unchar b;
+    unchar b, t;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);
 
     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+#else
         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
-        if (scp->target == (unchar)id && b == (unchar)busnum) {
+        t = scp->target;
+#endif
+        if (t == (unchar)id && b == (unchar)busnum) {
             TRACE2(("gdth_start_timeout(): update_timeout()\n"));
             gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
         }
@@ -1446,7 +1095,6 @@
     oldto = scp->timeout_per_command;
     scp->timeout_per_command = timeout;
 
-#if LINUX_VERSION_CODE >= 0x02014B
     if (timeout == 0) {
         del_timer(&scp->eh_timeout);
         scp->eh_timeout.data = (unsigned long) NULL;
@@ -1458,17 +1106,6 @@
         scp->eh_timeout.expires = jiffies + timeout;
         add_timer(&scp->eh_timeout);
     }
-#else
-    if (timeout > 0) {
-        if (timer_table[SCSI_TIMER].expires == 0) {
-            timer_table[SCSI_TIMER].expires = jiffies + timeout;
-            timer_active |= 1 << SCSI_TIMER;
-        } else {
-            if (time_before(jiffies + timeout < timer_table[SCSI_TIMER].expires))
-                timer_table[SCSI_TIMER].expires = jiffies + timeout;
-        }
-    }
-#endif
 
     return oldto;
 }
diff -urN linux-2.4.28-pre3/drivers/scsi/gdth_proc.h linux-2.4.28-pre4/drivers/scsi/gdth_proc.h
--- linux-2.4.28-pre3/drivers/scsi/gdth_proc.h	2001-09-07 09:28:37.000000000 -0700
+++ linux-2.4.28-pre4/drivers/scsi/gdth_proc.h	2004-10-08 06:28:25.812265919 -0700
@@ -2,26 +2,31 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.11 2001/07/25 15:37:40 achim Exp $
+ * $Id: gdth_proc.h,v 1.16 2004/01/14 13:09:01 achim Exp $
  */
 
-static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
-static int gdth_get_info(char *buffer,char **start,off_t offset,
-                         int length,int vh,int hanum,int busnum);
+static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
+                         int hanum,int busnum);
+static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
+                         struct Scsi_Host *host,int hanum,int busnum);
 
-#if LINUX_VERSION_CODE >= 0x020322
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static void gdth_do_req(Scsi_Request *srp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
 #else 
-static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
-static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
-#endif
 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
                         char *cmnd, int timeout);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp);
+#endif
 
-static char *gdth_ioctl_alloc(int hanum, ushort size, int scratch);
-static void gdth_ioctl_free(int hanum, char *buf);
-static int gdth_ioctl_check_bin(int hanum, ushort size);
+static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
+                              ulong64 *paddr);  
+static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr);
 static void gdth_wait_completion(int hanum, int busnum, int id);
 static void gdth_stop_timeout(int hanum, int busnum, int id);
 static void gdth_start_timeout(int hanum, int busnum, int id);
diff -urN linux-2.4.28-pre3/drivers/scsi/ips.h linux-2.4.28-pre4/drivers/scsi/ips.h
--- linux-2.4.28-pre3/drivers/scsi/ips.h	2004-10-08 06:28:21.780101873 -0700
+++ linux-2.4.28-pre4/drivers/scsi/ips.h	2004-10-08 06:28:25.820266244 -0700
@@ -95,15 +95,13 @@
       #define scsi_set_pci_device(sh,dev) (0)
    #endif
 
-   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-   
-      #ifndef irqreturn_t
-         typedef void irqreturn_t;
-      #endif 
-      
+   #ifndef IRQ_NONE
+      typedef void irqreturn_t;
       #define IRQ_NONE
       #define IRQ_HANDLED
       #define IRQ_RETVAL(x)
+   #endif
+   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
       #define IPS_REGISTER_HOSTS(SHT)      scsi_register_module(MODULE_SCSI_HA,SHT)
       #define IPS_UNREGISTER_HOSTS(SHT)    scsi_unregister_module(MODULE_SCSI_HA,SHT)
       #define IPS_ADD_HOST(shost,device)
diff -urN linux-2.4.28-pre3/drivers/scsi/libata-core.c linux-2.4.28-pre4/drivers/scsi/libata-core.c
--- linux-2.4.28-pre3/drivers/scsi/libata-core.c	2004-10-08 06:28:21.785102077 -0700
+++ linux-2.4.28-pre4/drivers/scsi/libata-core.c	2004-10-08 06:28:25.827266529 -0700
@@ -90,17 +90,17 @@
 }
 
 /**
- *	ata_tf_load_pio - send taskfile registers to host controller
+ *	ata_tf_load - send taskfile registers to host controller
  *	@ap: Port to which output is sent
  *	@tf: ATA taskfile register set
  *
- *	Outputs ATA taskfile to standard ATA host controller using PIO.
+ *	Outputs ATA taskfile to standard ATA host controller.
  *
  *	LOCKING:
  *	Inherited from caller.
  */
 
-void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf)
+static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
@@ -158,23 +158,23 @@
  *	Inherited from caller.
  */
 
-void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
 
 	if (tf->ctl != ap->last_ctl) {
-		writeb(tf->ctl, ap->ioaddr.ctl_addr);
+		writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
 		ap->last_ctl = tf->ctl;
 		ata_wait_idle(ap);
 	}
 
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
-		writeb(tf->hob_feature, (void *) ioaddr->feature_addr);
-		writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr);
-		writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr);
-		writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr);
-		writeb(tf->hob_lbah, (void *) ioaddr->lbah_addr);
+		writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+		writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+		writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+		writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+		writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
 		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
 			tf->hob_feature,
 			tf->hob_nsect,
@@ -184,11 +184,11 @@
 	}
 
 	if (is_addr) {
-		writeb(tf->feature, (void *) ioaddr->feature_addr);
-		writeb(tf->nsect, (void *) ioaddr->nsect_addr);
-		writeb(tf->lbal, (void *) ioaddr->lbal_addr);
-		writeb(tf->lbam, (void *) ioaddr->lbam_addr);
-		writeb(tf->lbah, (void *) ioaddr->lbah_addr);
+		writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+		writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+		writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+		writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+		writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
 		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
 			tf->feature,
 			tf->nsect,
@@ -198,26 +198,34 @@
 	}
 
 	if (tf->flags & ATA_TFLAG_DEVICE) {
-		writeb(tf->device, (void *) ioaddr->device_addr);
+		writeb(tf->device, (void __iomem *) ioaddr->device_addr);
 		VPRINTK("device 0x%X\n", tf->device);
 	}
 
 	ata_wait_idle(ap);
 }
 
+void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_tf_load_mmio(ap, tf);
+	else
+		ata_tf_load_pio(ap, tf);
+}
+
 /**
- *	ata_exec_command_pio - issue ATA command to host controller
+ *	ata_exec_command - issue ATA command to host controller
  *	@ap: port to which command is being issued
  *	@tf: ATA taskfile register set
  *
- *	Issues PIO write to ATA command register, with proper
+ *	Issues PIO/MMIO write to ATA command register, with proper
  *	synchronization with interrupt handler / other threads.
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  */
 
-void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf)
+static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
 
@@ -238,20 +246,28 @@
  *	spin_lock_irqsave(host_set lock)
  */
 
-void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
 
-       	writeb(tf->command, (void *) ap->ioaddr.command_addr);
+       	writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
 	ata_pause(ap);
 }
 
+void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_exec_command_mmio(ap, tf);
+	else
+		ata_exec_command_pio(ap, tf);
+}
+
 /**
  *	ata_exec - issue ATA command to host controller
  *	@ap: port to which command is being issued
  *	@tf: ATA taskfile register set
  *
- *	Issues PIO write to ATA command register, with proper
+ *	Issues PIO/MMIO write to ATA command register, with proper
  *	synchronization with interrupt handler / other threads.
  *
  *	LOCKING:
@@ -274,7 +290,7 @@
  *	@tf: ATA taskfile register set
  *
  *	Issues ATA taskfile register set to ATA host controller,
- *	via PIO, with proper synchronization with interrupt handler and
+ *	with proper synchronization with interrupt handler and
  *	other threads.
  *
  *	LOCKING:
@@ -294,7 +310,7 @@
  *	@tf: ATA taskfile register set
  *
  *	Issues ATA taskfile register set to ATA host controller,
- *	via PIO, with proper synchronization with interrupt handler and
+ *	with proper synchronization with interrupt handler and
  *	other threads.
  *
  *	LOCKING:
@@ -308,18 +324,18 @@
 }
 
 /**
- *	ata_tf_read_pio - input device's ATA taskfile shadow registers
+ *	ata_tf_read - input device's ATA taskfile shadow registers
  *	@ap: Port from which input is read
  *	@tf: ATA taskfile register set for storing input
  *
  *	Reads ATA taskfile registers for currently-selected device
- *	into @tf via PIO.
+ *	into @tf.
  *
  *	LOCKING:
  *	Inherited from caller.
  */
 
-void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 
@@ -351,38 +367,46 @@
  *	Inherited from caller.
  */
 
-void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 
-	tf->nsect = readb((void *)ioaddr->nsect_addr);
-	tf->lbal = readb((void *)ioaddr->lbal_addr);
-	tf->lbam = readb((void *)ioaddr->lbam_addr);
-	tf->lbah = readb((void *)ioaddr->lbah_addr);
-	tf->device = readb((void *)ioaddr->device_addr);
+	tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+	tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+	tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+	tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+	tf->device = readb((void __iomem *)ioaddr->device_addr);
 
 	if (tf->flags & ATA_TFLAG_LBA48) {
-		writeb(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr);
-		tf->hob_feature = readb((void *)ioaddr->error_addr);
-		tf->hob_nsect = readb((void *)ioaddr->nsect_addr);
-		tf->hob_lbal = readb((void *)ioaddr->lbal_addr);
-		tf->hob_lbam = readb((void *)ioaddr->lbam_addr);
-		tf->hob_lbah = readb((void *)ioaddr->lbah_addr);
+		writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+		tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+		tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+		tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+		tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+		tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
 	}
 }
 
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_tf_read_mmio(ap, tf);
+	else
+		ata_tf_read_pio(ap, tf);
+}
+
 /**
- *	ata_check_status_pio - Read device status reg & clear interrupt
+ *	ata_check_status - Read device status reg & clear interrupt
  *	@ap: port where the device is
  *
  *	Reads ATA taskfile status register for currently-selected device
- *	via PIO and return it's value. This also clears pending interrupts
+ *	and return it's value. This also clears pending interrupts
  *      from this device
  *
  *	LOCKING:
  *	Inherited from caller.
  */
-u8 ata_check_status_pio(struct ata_port *ap)
+static u8 ata_check_status_pio(struct ata_port *ap)
 {
 	return inb(ap->ioaddr.status_addr);
 }
@@ -398,9 +422,16 @@
  *	LOCKING:
  *	Inherited from caller.
  */
-u8 ata_check_status_mmio(struct ata_port *ap)
+static u8 ata_check_status_mmio(struct ata_port *ap)
 {
-       	return readb((void *) ap->ioaddr.status_addr);
+       	return readb((void __iomem *) ap->ioaddr.status_addr);
+}
+
+u8 ata_check_status(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		return ata_check_status_mmio(ap);
+	return ata_check_status_pio(ap);
 }
 
 /**
@@ -674,17 +705,17 @@
 
 	__ata_dev_select(ap, device);
 
-	writeb(0x55, (void *) ioaddr->nsect_addr);
-	writeb(0xaa, (void *) ioaddr->lbal_addr);
+	writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+	writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
 
-	writeb(0xaa, (void *) ioaddr->nsect_addr);
-	writeb(0x55, (void *) ioaddr->lbal_addr);
+	writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
+	writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
 
-	writeb(0x55, (void *) ioaddr->nsect_addr);
-	writeb(0xaa, (void *) ioaddr->lbal_addr);
+	writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+	writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
 
-	nsect = readb((void *) ioaddr->nsect_addr);
-	lbal = readb((void *) ioaddr->lbal_addr);
+	nsect = readb((void __iomem *) ioaddr->nsect_addr);
+	lbal = readb((void __iomem *) ioaddr->lbal_addr);
 
 	if ((nsect == 0x55) && (lbal == 0xaa))
 		return 1;	/* we found a device */
@@ -693,7 +724,7 @@
 }
 
 /**
- *	ata_dev_devchk - PATA device presence detection
+ *	ata_devchk - PATA device presence detection
  *	@ap: ATA channel to examine
  *	@device: Device to examine (starting at zero)
  *
@@ -705,7 +736,7 @@
  *	caller.
  */
 
-static unsigned int ata_dev_devchk(struct ata_port *ap,
+static unsigned int ata_devchk(struct ata_port *ap,
 				    unsigned int device)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
@@ -863,7 +894,7 @@
 		tmp = ATA_DEVICE_OBS | ATA_DEV1;
 
 	if (ap->flags & ATA_FLAG_MMIO) {
-		writeb(tmp, (void *) ap->ioaddr.device_addr);
+		writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
 	} else {
 		outb(tmp, ap->ioaddr.device_addr);
 	}
@@ -1461,13 +1492,13 @@
 	unsigned int dev1 = devmask & (1 << 1);
 	unsigned long timeout;
 
-	/* if device 0 was found in ata_dev_devchk, wait for its
+	/* if device 0 was found in ata_devchk, wait for its
 	 * BSY bit to clear
 	 */
 	if (dev0)
 		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
 
-	/* if device 1 was found in ata_dev_devchk, wait for
+	/* if device 1 was found in ata_devchk, wait for
 	 * register access, then wait for BSY to clear
 	 */
 	timeout = jiffies + ATA_TMOUT_BOOT;
@@ -1476,8 +1507,8 @@
 
 		__ata_dev_select(ap, 1);
 		if (ap->flags & ATA_FLAG_MMIO) {
-			nsect = readb((void *) ioaddr->nsect_addr);
-			lbal = readb((void *) ioaddr->lbal_addr);
+			nsect = readb((void __iomem *) ioaddr->nsect_addr);
+			lbal = readb((void __iomem *) ioaddr->lbal_addr);
 		} else {
 			nsect = inb(ioaddr->nsect_addr);
 			lbal = inb(ioaddr->lbal_addr);
@@ -1541,11 +1572,11 @@
 
 	/* software reset.  causes dev0 to be selected */
 	if (ap->flags & ATA_FLAG_MMIO) {
-		writeb(ap->ctl, ioaddr->ctl_addr);
+		writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
 		udelay(20);	/* FIXME: flush */
-		writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+		writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
 		udelay(20);	/* FIXME: flush */
-		writeb(ap->ctl, ioaddr->ctl_addr);
+		writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
 	} else {
 		outb(ap->ctl, ioaddr->ctl_addr);
 		udelay(10);
@@ -1602,9 +1633,9 @@
 	if (ap->flags & ATA_FLAG_SATA_RESET)
 		dev0 = 1;
 	else {
-		dev0 = ata_dev_devchk(ap, 0);
+		dev0 = ata_devchk(ap, 0);
 		if (slave_possible)
-			dev1 = ata_dev_devchk(ap, 1);
+			dev1 = ata_devchk(ap, 1);
 	}
 
 	if (dev0)
@@ -1621,7 +1652,7 @@
 	else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
 		/* set up device control */
 		if (ap->flags & ATA_FLAG_MMIO)
-			writeb(ap->ctl, ioaddr->ctl_addr);
+			writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
 		else
 			outb(ap->ctl, ioaddr->ctl_addr);
 		rc = ata_bus_edd(ap);
@@ -1654,7 +1685,7 @@
 	if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
 		/* set up device control for ATA_FLAG_SATA_RESET */
 		if (ap->flags & ATA_FLAG_MMIO)
-			writeb(ap->ctl, ioaddr->ctl_addr);
+			writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
 		else
 			outb(ap->ctl, ioaddr->ctl_addr);
 	}
@@ -2101,7 +2132,7 @@
 	unsigned int i;
 	unsigned int words = buflen >> 1;
 	u16 *buf16 = (u16 *) buf;
-	void *mmio = (void *)ap->ioaddr.data_addr;
+	void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
 
 	if (write_data) {
 		for (i = 0; i < words; i++)
@@ -2182,7 +2213,7 @@
 	/* shall be cleared to zero, indicating xfer of data */
 	if (ireason & (1 << 0))
 		goto err_out;
-	
+
 	/* make sure transfer direction matches expected */
 	i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
 	if (do_write != i_write)
@@ -2198,7 +2229,7 @@
 
 	for (i = 0; i < (bytes >> 9); i++)
 		ata_pio_sector(qc);
-	
+
 	return;
 
 err_out:
@@ -2627,19 +2658,19 @@
 }
 
 /**
- *	ata_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
+ *	ata_bmdma_setup - Set up PCI IDE BMDMA transaction
  *	@qc: Info associated with this ATA transaction.
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  */
 
-void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
 	u8 dmactl;
-	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+	void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
 
 	/* load PRD table addr. */
 	mb();	/* make sure PRD table writes are visible to controller */
@@ -2657,17 +2688,17 @@
 }
 
 /**
- *	ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
+ *	ata_bmdma_start - Start a PCI IDE BMDMA transaction
  *	@qc: Info associated with this ATA transaction.
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  */
 
-void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
-	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+	void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
 	u8 dmactl;
 
 	/* start host DMA transaction */
@@ -2695,7 +2726,7 @@
  *	spin_lock_irqsave(host_set lock)
  */
 
-void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
+static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
@@ -2723,7 +2754,7 @@
  *	spin_lock_irqsave(host_set lock)
  */
 
-void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
+static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
 	u8 dmactl;
@@ -2734,6 +2765,22 @@
 	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
+void ata_bmdma_start(struct ata_queued_cmd *qc)
+{
+	if (qc->ap->flags & ATA_FLAG_MMIO)
+		ata_bmdma_start_mmio(qc);
+	else
+		ata_bmdma_start_pio(qc);
+}
+
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	if (qc->ap->flags & ATA_FLAG_MMIO)
+		ata_bmdma_setup_mmio(qc);
+	else
+		ata_bmdma_setup_pio(qc);
+}
+
 void ata_bmdma_irq_clear(struct ata_port *ap)
 {
 	ata_bmdma_ack_irq(ap);
@@ -3244,6 +3291,95 @@
 	ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
 }
 
+static struct ata_probe_ent *
+ata_probe_ent_alloc(int n, struct pci_dev *pdev, struct ata_port_info **port)
+{
+	struct ata_probe_ent *probe_ent;
+	int i;
+
+	probe_ent = kmalloc(sizeof(*probe_ent) * n, GFP_KERNEL);
+	if (!probe_ent) {
+		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+		       pci_name(pdev));
+		return NULL;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent) * n);
+
+	for (i = 0; i < n; i++) {
+		INIT_LIST_HEAD(&probe_ent[i].node);
+		probe_ent[i].pdev = pdev;
+
+		probe_ent[i].sht = port[i]->sht;
+		probe_ent[i].host_flags = port[i]->host_flags;
+		probe_ent[i].pio_mask = port[i]->pio_mask;
+		probe_ent[i].mwdma_mask = port[i]->mwdma_mask;
+		probe_ent[i].udma_mask = port[i]->udma_mask;
+		probe_ent[i].port_ops = port[i]->port_ops;
+
+	}
+
+	return probe_ent;
+}
+
+struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
+{
+	struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(1, pdev, port);
+	if (!probe_ent)
+		return NULL;
+
+	probe_ent->n_ports = 2;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+
+	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 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);
+
+	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+	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) + 8;
+
+	ata_std_ports(&probe_ent->port[0]);
+	ata_std_ports(&probe_ent->port[1]);
+
+	return probe_ent;
+}
+
+struct ata_probe_ent *
+ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port)
+{
+	struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(2, pdev, port);
+	if (!probe_ent)
+		return NULL;
+
+	probe_ent[0].n_ports = 1;
+	probe_ent[0].irq = 14;
+
+	probe_ent[1].n_ports = 1;
+	probe_ent[1].irq = 15;
+
+	probe_ent[0].port[0].cmd_addr = 0x1f0;
+	probe_ent[0].port[0].altstatus_addr =
+	probe_ent[0].port[0].ctl_addr = 0x3f6;
+	probe_ent[0].port[0].bmdma_addr = pci_resource_start(pdev, 4);
+
+	probe_ent[1].port[0].cmd_addr = 0x170;
+	probe_ent[1].port[0].altstatus_addr =
+	probe_ent[1].port[0].ctl_addr = 0x376;
+	probe_ent[1].port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
+
+	ata_std_ports(&probe_ent[0].port[0]);
+	ata_std_ports(&probe_ent[1].port[0]);
+
+	return probe_ent;
+}
+
 /**
  *	ata_pci_init_one - Initialize/register PCI IDE host controller
  *	@pdev: Controller to be initialized
@@ -3261,20 +3397,20 @@
 		      unsigned int n_ports)
 {
 	struct ata_probe_ent *probe_ent, *probe_ent2 = NULL;
-	struct ata_port_info *port0, *port1;
+	struct ata_port_info *port[2];
 	u8 tmp8, mask;
 	unsigned int legacy_mode = 0;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	port0 = port_info[0];
+	port[0] = port_info[0];
 	if (n_ports > 1)
-		port1 = port_info[1];
+		port[1] = port_info[1];
 	else
-		port1 = port0;
+		port[1] = port[0];
 
-	if ((port0->host_flags & ATA_FLAG_NO_LEGACY) == 0) {
+	if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0) {
 		/* TODO: support transitioning to native mode? */
 		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
 		mask = (1 << 2) | (1 << 0);
@@ -3318,89 +3454,32 @@
 	if (rc)
 		goto err_out_regions;
 
-	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (legacy_mode) {
+		probe_ent = ata_pci_init_legacy_mode(pdev, port);
+		if (probe_ent)
+			probe_ent2 = &probe_ent[1];
+	} else
+		probe_ent = ata_pci_init_native_mode(pdev, port);
 	if (!probe_ent) {
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
 
-	memset(probe_ent, 0, sizeof(*probe_ent));
-	probe_ent->pdev = pdev;
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	if (legacy_mode) {
-		probe_ent2 = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
-		if (!probe_ent2) {
-			rc = -ENOMEM;
-			goto err_out_free_ent;
-		}
-
-		memset(probe_ent2, 0, sizeof(*probe_ent));
-		probe_ent2->pdev = pdev;
-		INIT_LIST_HEAD(&probe_ent2->node);
-	}
-
-	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
-	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;
-
-	if (legacy_mode) {
-		probe_ent->port[0].cmd_addr = 0x1f0;
-		probe_ent->port[0].altstatus_addr =
-		probe_ent->port[0].ctl_addr = 0x3f6;
-		probe_ent->n_ports = 1;
-		probe_ent->irq = 14;
-		ata_std_ports(&probe_ent->port[0]);
-
-		probe_ent2->port[0].cmd_addr = 0x170;
-		probe_ent2->port[0].altstatus_addr =
-		probe_ent2->port[0].ctl_addr = 0x376;
-		probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
-		probe_ent2->n_ports = 1;
-		probe_ent2->irq = 15;
-		ata_std_ports(&probe_ent2->port[0]);
-
-		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 {
-		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[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) + 8;
-
-		probe_ent->n_ports = 2;
-		probe_ent->irq = pdev->irq;
-		probe_ent->irq_flags = SA_SHIRQ;
-	}
-
 	pci_set_master(pdev);
 
 	spin_lock(&ata_module_lock);
 	if (legacy_mode) {
+		int free = 0;
 		if (legacy_mode & (1 << 0))
 			list_add_tail(&probe_ent->node, &ata_probe_list);
 		else
-			kfree(probe_ent);
+			free++;
 		if (legacy_mode & (1 << 1))
 			list_add_tail(&probe_ent2->node, &ata_probe_list);
 		else
-			kfree(probe_ent2);
+			free++;
+		if (free > 1)
+			kfree(probe_ent);
 	} else {
 		list_add_tail(&probe_ent->node, &ata_probe_list);
 	}
@@ -3408,8 +3487,6 @@
 
 	return 0;
 
-err_out_free_ent:
-	kfree(probe_ent);
 err_out_regions:
 	if (legacy_mode & (1 << 0))
 		release_region(0x1f0, 8);
@@ -3567,24 +3644,20 @@
 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);
-EXPORT_SYMBOL_GPL(ata_tf_read_pio);
-EXPORT_SYMBOL_GPL(ata_tf_read_mmio);
+EXPORT_SYMBOL_GPL(ata_tf_load);
+EXPORT_SYMBOL_GPL(ata_tf_read);
 EXPORT_SYMBOL_GPL(ata_tf_to_fis);
 EXPORT_SYMBOL_GPL(ata_tf_from_fis);
-EXPORT_SYMBOL_GPL(ata_check_status_pio);
-EXPORT_SYMBOL_GPL(ata_check_status_mmio);
-EXPORT_SYMBOL_GPL(ata_exec_command_pio);
-EXPORT_SYMBOL_GPL(ata_exec_command_mmio);
+EXPORT_SYMBOL_GPL(ata_pci_init_legacy_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_check_status);
+EXPORT_SYMBOL_GPL(ata_exec_command);
 EXPORT_SYMBOL_GPL(ata_port_start);
 EXPORT_SYMBOL_GPL(ata_port_stop);
 EXPORT_SYMBOL_GPL(ata_interrupt);
 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_setup);
+EXPORT_SYMBOL_GPL(ata_bmdma_start);
 EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_nv.c linux-2.4.28-pre4/drivers/scsi/sata_nv.c
--- linux-2.4.28-pre3/drivers/scsi/sata_nv.c	2004-10-08 06:28:21.827103786 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_nv.c	2004-10-08 06:28:25.850267465 -0700
@@ -50,8 +50,6 @@
 #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
 
@@ -184,7 +182,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -201,13 +199,13 @@
 
 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,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
 	.phy_reset		= sata_phy_reset,
-	.bmdma_setup		= ata_bmdma_setup_pio,
-	.bmdma_start		= ata_bmdma_start_pio,
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
@@ -220,6 +218,18 @@
 	.host_stop		= nv_host_stop,
 };
 
+static struct ata_port_info nv_port_info = {
+	.sht		= &nv_sht,
+	.host_flags	= ATA_FLAG_SATA |
+			  ATA_FLAG_SATA_RESET |
+			  ATA_FLAG_SRST |
+			  ATA_FLAG_NO_LEGACY,
+	.pio_mask	= NV_PIO_MASK,
+	.mwdma_mask	= NV_MWDMA_MASK,
+	.udma_mask	= NV_UDMA_MASK,
+	.port_ops	= &nv_ops,
+};
+
 MODULE_AUTHOR("NVIDIA");
 MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
 MODULE_LICENSE("GPL");
@@ -300,6 +310,7 @@
 {
 	static int printed_version = 0;
 	struct nv_host *host;
+	struct ata_port_info *ppi;
 	struct ata_probe_ent *probe_ent = NULL;
 	int rc;
 
@@ -318,7 +329,8 @@
 	if (rc)
 		goto err_out_regions;
 
-	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	ppi = &nv_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
 	if (!probe_ent) {
 		rc = -ENOMEM;
 		goto err_out_regions;
@@ -332,40 +344,6 @@
 
 	host->host_desc = &nv_device_tbl[ent->driver_data];
 
-	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[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->private_data = host;
 
 	if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_promise.c linux-2.4.28-pre4/drivers/scsi/sata_promise.c
--- linux-2.4.28-pre3/drivers/scsi/sata_promise.c	2004-10-08 06:28:21.828103826 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_promise.c	2004-10-08 06:28:25.851267505 -0700
@@ -91,7 +91,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -109,8 +109,8 @@
 static struct ata_port_operations pdc_sata_ops = {
 	.port_disable		= ata_port_disable,
 	.tf_load		= pdc_tf_load_mmio,
-	.tf_read		= ata_tf_read_mmio,
-	.check_status		= ata_check_status_mmio,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
 	.exec_command		= pdc_exec_command_mmio,
 	.phy_reset		= pdc_phy_reset,
 	.qc_prep		= pdc_qc_prep,
@@ -470,7 +470,7 @@
 {
 	WARN_ON (tf->protocol == ATA_PROT_DMA ||
 		 tf->protocol == ATA_PROT_NODATA);
-	ata_tf_load_mmio(ap, tf);
+	ata_tf_load(ap, tf);
 }
 
 
@@ -478,7 +478,7 @@
 {
 	WARN_ON (tf->protocol == ATA_PROT_DMA ||
 		 tf->protocol == ATA_PROT_NODATA);
-	ata_exec_command_mmio(ap, tf);
+	ata_exec_command(ap, tf);
 }
 
 
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_sil.c linux-2.4.28-pre4/drivers/scsi/sata_sil.c
--- linux-2.4.28-pre3/drivers/scsi/sata_sil.c	2004-10-08 06:28:21.829103867 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_sil.c	2004-10-08 06:28:25.852267546 -0700
@@ -108,7 +108,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -126,14 +126,14 @@
 static struct ata_port_operations sil_ops = {
 	.port_disable		= ata_port_disable,
 	.dev_config		= sil_dev_config,
-	.tf_load		= ata_tf_load_mmio,
-	.tf_read		= ata_tf_read_mmio,
-	.check_status		= ata_check_status_mmio,
-	.exec_command		= ata_exec_command_mmio,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
 	.phy_reset		= sata_phy_reset,
 	.post_set_mode		= sil_post_set_mode,
-	.bmdma_setup            = ata_bmdma_setup_mmio,
-	.bmdma_start            = ata_bmdma_start_mmio,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_sis.c linux-2.4.28-pre4/drivers/scsi/sata_sis.c
--- linux-2.4.28-pre3/drivers/scsi/sata_sis.c	2004-10-08 06:28:21.829103867 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_sis.c	2004-10-08 06:28:25.852267546 -0700
@@ -78,7 +78,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -95,13 +95,13 @@
 
 static struct ata_port_operations sis_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,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
 	.phy_reset		= sata_phy_reset,
-	.bmdma_setup            = ata_bmdma_setup_pio,
-	.bmdma_start            = ata_bmdma_start_pio,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
@@ -113,6 +113,16 @@
 	.port_stop		= ata_port_stop,
 };
 
+static struct ata_port_info sis_port_info = {
+	.sht		= &sis_sht,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+			  ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x7,
+	.udma_mask	= 0x7f,
+	.port_ops	= &sis_ops,
+};
+
 
 MODULE_AUTHOR("Uwe Koziolek");
 MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
@@ -186,6 +196,7 @@
 	struct ata_probe_ent *probe_ent = NULL;
 	int rc;
 	u32 genctl;
+	struct ata_port_info *ppi;
 
 	rc = pci_enable_device(pdev);
 	if (rc)
@@ -199,20 +210,13 @@
 	if (rc)
 		goto err_out_regions;
 
-	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	ppi = &sis_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
 	if (!probe_ent) {
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
 
-	memset(probe_ent, 0, sizeof(*probe_ent));
-	probe_ent->pdev = pdev;
-	INIT_LIST_HEAD(&probe_ent->node);
-
-	probe_ent->sht = &sis_sht;
-	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
-				ATA_FLAG_NO_LEGACY;
-
 	/* check and see if the SCRs are in IO space or PCI cfg space */
 	pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
 	if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
@@ -229,32 +233,12 @@
 		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
 	}
 
-	probe_ent->pio_mask = 0x1f;
-	probe_ent->mwdma_mask = 0x7;
-	probe_ent->udma_mask = 0x7f;
-	probe_ent->port_ops = &sis_ops;
-
-	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
-	ata_std_ports(&probe_ent->port[0]);
-	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);
-	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR))
+	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
 		probe_ent->port[0].scr_addr =
 			pci_resource_start(pdev, SIS_SCR_PCI_BAR);
-
-	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
-	ata_std_ports(&probe_ent->port[1]);
-	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) + 8;
-	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR))
 		probe_ent->port[1].scr_addr =
 			pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64;
-
-	probe_ent->n_ports = 2;
-	probe_ent->irq = pdev->irq;
-	probe_ent->irq_flags = SA_SHIRQ;
+	}
 
 	pci_set_master(pdev);
 	pci_enable_intx(pdev);
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_svw.c linux-2.4.28-pre4/drivers/scsi/sata_svw.c
--- linux-2.4.28-pre3/drivers/scsi/sata_svw.c	2004-10-08 06:28:21.830103908 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_svw.c	2004-10-08 06:28:25.853267587 -0700
@@ -148,7 +148,73 @@
         }
 }
 
+/**
+ *	k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dmactl;
+	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+	/* load PRD table addr. */
+	mb();	/* make sure PRD table writes are visible to controller */
+	writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	writeb(dmactl, mmio + ATA_DMA_CMD);
+
+	/* issue r/w command if this is not a ATA DMA command*/
+	if (qc->tf.protocol != ATA_PROT_DMA)
+		ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ *	k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+	u8 dmactl;
+
+	/* start host DMA transaction */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+	/* There is a race condition in certain SATA controllers that can 
+	   be seen when the r/w command is given to the controller before the 
+	   host DMA is started. On a Read command, the controller would initiate
+	   the command to the drive even before it sees the DMA start. When there
+	   are very fast drives connected to the controller, or when the data request 
+	   hits in the drive cache, there is the possibility that the drive returns a part
+	   or all of the requested data to the controller before the DMA start is issued.
+	   In this case, the controller would become confused as to what to do with the data.
+	   In the worst case when all the data is returned back to the controller, the
+	   controller could hang. In other cases it could return partial data returning
+	   in data corruption. This problem has been seen in PPC systems and can also appear
+	   on an system with very fast disks, where the SATA controller is sitting behind a 
+	   number of bridges, and hence there is significant latency between the r/w command
+	   and the start command. */
+	/* issue r/w command if the access is to ATA*/
+	if (qc->tf.protocol == ATA_PROT_DMA)
+		ap->ops->exec_command(ap, &qc->tf);
+}
 
+									      
 static u8 k2_stat_check_status(struct ata_port *ap)
 {
        	return readl((void *) ap->ioaddr.status_addr);
@@ -207,7 +273,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -231,10 +297,10 @@
 	.tf_load		= k2_sata_tf_load,
 	.tf_read		= k2_sata_tf_read,
 	.check_status		= k2_stat_check_status,
-	.exec_command		= ata_exec_command_mmio,
+	.exec_command		= ata_exec_command,
 	.phy_reset		= sata_phy_reset,
-	.bmdma_setup            = ata_bmdma_setup_mmio,
-	.bmdma_start            = ata_bmdma_start_mmio,
+	.bmdma_setup		= k2_bmdma_setup_mmio,
+	.bmdma_start		= k2_bmdma_start_mmio,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
@@ -369,6 +435,8 @@
 
 static struct pci_device_id k2_sata_pci_tbl[] = {
 	{ 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	{ }
 };
 
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_sx4.c linux-2.4.28-pre4/drivers/scsi/sata_sx4.c
--- linux-2.4.28-pre3/drivers/scsi/sata_sx4.c	2004-10-08 06:28:21.832103989 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_sx4.c	2004-10-08 06:28:25.855267668 -0700
@@ -176,7 +176,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -194,8 +194,8 @@
 static struct ata_port_operations pdc_20621_ops = {
 	.port_disable		= ata_port_disable,
 	.tf_load		= pdc_tf_load_mmio,
-	.tf_read		= ata_tf_read_mmio,
-	.check_status		= ata_check_status_mmio,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
 	.exec_command		= pdc_exec_command_mmio,
 	.phy_reset		= pdc_20621_phy_reset,
 	.qc_prep		= pdc20621_qc_prep,
@@ -888,7 +888,7 @@
 {
 	WARN_ON (tf->protocol == ATA_PROT_DMA ||
 		 tf->protocol == ATA_PROT_NODATA);
-	ata_tf_load_mmio(ap, tf);
+	ata_tf_load(ap, tf);
 }
 
 
@@ -896,7 +896,7 @@
 {
 	WARN_ON (tf->protocol == ATA_PROT_DMA ||
 		 tf->protocol == ATA_PROT_NODATA);
-	ata_exec_command_mmio(ap, tf);
+	ata_exec_command(ap, tf);
 }
 
 
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_via.c linux-2.4.28-pre4/drivers/scsi/sata_via.c
--- linux-2.4.28-pre3/drivers/scsi/sata_via.c	2004-10-08 06:28:21.832103989 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_via.c	2004-10-08 06:28:25.856267709 -0700
@@ -83,7 +83,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -101,15 +101,15 @@
 static struct ata_port_operations svia_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,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
 
 	.phy_reset		= sata_phy_reset,
 
-	.bmdma_setup            = ata_bmdma_setup_pio,
-	.bmdma_start            = ata_bmdma_start_pio,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 
@@ -125,6 +125,15 @@
 	.port_stop		= ata_port_stop,
 };
 
+static struct ata_port_info svia_port_info = {
+	.sht		= &svia_sht,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x07,
+	.udma_mask	= 0x7f,
+	.port_ops	= &svia_sata_ops,
+};
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
 MODULE_LICENSE("GPL");
@@ -158,6 +167,7 @@
 	static int printed_version;
 	unsigned int i;
 	int rc;
+	struct ata_port_info *ppi;
 	struct ata_probe_ent *probe_ent;
 	u8 tmp8;
 
@@ -195,42 +205,17 @@
 	if (rc)
 		goto err_out_regions;
 
-	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	ppi = &svia_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
 	if (!probe_ent) {
 		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
 		       pci_name(pdev));
 		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 = &svia_sht;
-	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
-				ATA_FLAG_NO_LEGACY;
-	probe_ent->port_ops = &svia_sata_ops;
-	probe_ent->n_ports = 2;
-	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);
-	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);
+
 	probe_ent->port[0].scr_addr =
 		svia_scr_addr(pci_resource_start(pdev, 5), 0);
-
-	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) + 8;
 	probe_ent->port[1].scr_addr =
 		svia_scr_addr(pci_resource_start(pdev, 5), 1);
 
diff -urN linux-2.4.28-pre3/drivers/scsi/sata_vsc.c linux-2.4.28-pre4/drivers/scsi/sata_vsc.c
--- linux-2.4.28-pre3/drivers/scsi/sata_vsc.c	2004-10-08 06:28:21.833104030 -0700
+++ linux-2.4.28-pre4/drivers/scsi/sata_vsc.c	2004-10-08 06:28:25.857267749 -0700
@@ -192,7 +192,7 @@
 	.name			= DRV_NAME,
 	.detect			= ata_scsi_detect,
 	.release		= ata_scsi_release,
-	.ioctl                  = ata_scsi_ioctl,
+	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
 	.can_queue		= ATA_DEF_QUEUE,
@@ -212,11 +212,11 @@
 	.port_disable		= ata_port_disable,
 	.tf_load		= vsc_sata_tf_load,
 	.tf_read		= vsc_sata_tf_read,
-	.exec_command		= ata_exec_command_mmio,
-	.check_status		= ata_check_status_mmio,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
 	.phy_reset		= sata_phy_reset,
-	.bmdma_setup            = ata_bmdma_setup_mmio,
-	.bmdma_start            = ata_bmdma_start_mmio,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
 	.qc_prep		= ata_qc_prep,
 	.qc_issue		= ata_qc_issue_prot,
 	.eng_timeout		= ata_eng_timeout,
diff -urN linux-2.4.28-pre3/drivers/usb/audio.c linux-2.4.28-pre4/drivers/usb/audio.c
--- linux-2.4.28-pre3/drivers/usb/audio.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/usb/audio.c	2004-10-08 06:28:25.894269255 -0700
@@ -593,9 +593,10 @@
 	return 0;
 }
 
-static void dmabuf_copyin(struct dmabuf *db, const void *buffer, unsigned int size)
+static void dmabuf_copyin(struct dmabuf *db, const void *_buffer, unsigned int size)
 {
 	unsigned int pgrem, rem;
+	const char *buffer = _buffer;
 
 	db->total_bytes += size;
 	for (;;) {
@@ -609,16 +610,17 @@
 			pgrem = rem;
 		memcpy((db->sgbuf[db->wrptr >> PAGE_SHIFT]) + (db->wrptr & (PAGE_SIZE-1)), buffer, pgrem);
 		size -= pgrem;
-		(char *)buffer += pgrem;
+		buffer += pgrem;
 		db->wrptr += pgrem;
 		if (db->wrptr >= db->dmasize)
 			db->wrptr = 0;
 	}
 }
 
-static void dmabuf_copyout(struct dmabuf *db, void *buffer, unsigned int size)
+static void dmabuf_copyout(struct dmabuf *db, void *_buffer, unsigned int size)
 {
 	unsigned int pgrem, rem;
+	char *buffer = _buffer;
 
 	db->total_bytes += size;
 	for (;;) {
@@ -632,16 +634,17 @@
 			pgrem = rem;
 		memcpy(buffer, (db->sgbuf[db->rdptr >> PAGE_SHIFT]) + (db->rdptr & (PAGE_SIZE-1)), pgrem);
 		size -= pgrem;
-		(char *)buffer += pgrem;
+		buffer += pgrem;
 		db->rdptr += pgrem;
 		if (db->rdptr >= db->dmasize)
 			db->rdptr = 0;
 	}
 }
 
-static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *buffer, unsigned int size)
+static int dmabuf_copyin_user(struct dmabuf *db, unsigned int ptr, const void *_buffer, unsigned int size)
 {
 	unsigned int pgrem, rem;
+	const char *buffer = _buffer;
 
 	if (!db->ready || db->mapped)
 		return -EINVAL;
@@ -657,16 +660,17 @@
 		if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem))
 			return -EFAULT;
 		size -= pgrem;
-		(char *)buffer += pgrem;
+		buffer += pgrem;
 		ptr += pgrem;
 		if (ptr >= db->dmasize)
 			ptr = 0;
 	}
 }
 
-static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *buffer, unsigned int size)
+static int dmabuf_copyout_user(struct dmabuf *db, unsigned int ptr, void *_buffer, unsigned int size)
 {
 	unsigned int pgrem, rem;
+	char *buffer = _buffer;
 
 	if (!db->ready || db->mapped)
 		return -EINVAL;
@@ -682,7 +686,7 @@
 		if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem))
 			return -EFAULT;
 		size -= pgrem;
-		(char *)buffer += pgrem;
+		buffer += pgrem;
 		ptr += pgrem;
 		if (ptr >= db->dmasize)
 			ptr = 0;
diff -urN linux-2.4.28-pre3/drivers/usb/hpusbscsi.c linux-2.4.28-pre4/drivers/usb/hpusbscsi.c
--- linux-2.4.28-pre3/drivers/usb/hpusbscsi.c	2003-06-13 07:51:36.000000000 -0700
+++ linux-2.4.28-pre4/drivers/usb/hpusbscsi.c	2004-10-08 06:28:26.011274015 -0700
@@ -182,7 +182,7 @@
 
 	memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template,
 		sizeof (hpusbscsi_scsi_host_template));
-	(struct hpusbscsi *) new->ctempl.proc_dir = new;
+	new->ctempl.proc_dir = (void *) new;
 	new->ctempl.module = THIS_MODULE;
 
 	if (scsi_register_module (MODULE_SCSI_HA, &(new->ctempl)))
diff -urN linux-2.4.28-pre3/drivers/usb/microtek.c linux-2.4.28-pre4/drivers/usb/microtek.c
--- linux-2.4.28-pre3/drivers/usb/microtek.c	2002-11-28 15:53:14.000000000 -0800
+++ linux-2.4.28-pre4/drivers/usb/microtek.c	2004-10-08 06:28:26.021274422 -0700
@@ -987,7 +987,7 @@
 	/* Initialize the host template based on the default one */
 	memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template));
 	/* HACK from usb-storage - this is needed for scsi detection */
-	(struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */
+	new_desc->ctempl.proc_dir = (void *)new_desc; /* FIXME */
 
 	MTS_DEBUG("registering SCSI module\n");
 
diff -urN linux-2.4.28-pre3/drivers/usb/uss720.c linux-2.4.28-pre4/drivers/usb/uss720.c
--- linux-2.4.28-pre3/drivers/usb/uss720.c	2001-10-20 19:13:11.000000000 -0700
+++ linux-2.4.28-pre4/drivers/usb/uss720.c	2004-10-08 06:28:26.082276904 -0700
@@ -327,13 +327,14 @@
 {
 	struct parport_uss720_private *priv = pp->private_data;	
 	size_t got = 0;
+	char *buff = buf;
 
 	if (change_mode(pp, ECR_EPP))
 		return 0;
 	for (; got < length; got++) {
-		if (get_1284_register(pp, 4, (char *)buf))
+		if (get_1284_register(pp, 4, buff))
 			break;
-		((char*)buf)++;
+		buff++;
 		if (priv->reg[0] & 0x01) {
 			clear_epp_timeout(pp);
 			break;
@@ -348,13 +349,14 @@
 #if 0
 	struct parport_uss720_private *priv = pp->private_data;	
 	size_t written = 0;
+	const char *buff = buf;
 
 	if (change_mode(pp, ECR_EPP))
 		return 0;
 	for (; written < length; written++) {
-		if (set_1284_register(pp, 4, (char *)buf))
+		if (set_1284_register(pp, 4, *buff))
 			break;
-		((char*)buf)++;
+		buff++;
 		if (get_1284_register(pp, 1, NULL))
 			break;
 		if (priv->reg[0] & 0x01) {
@@ -386,13 +388,14 @@
 {
 	struct parport_uss720_private *priv = pp->private_data;	
 	size_t got = 0;
+	char *buff = buf;
 
 	if (change_mode(pp, ECR_EPP))
 		return 0;
 	for (; got < length; got++) {
-		if (get_1284_register(pp, 3, (char *)buf))
+		if (get_1284_register(pp, 3, buff))
 			break;
-		((char*)buf)++;
+		buff++;
 		if (priv->reg[0] & 0x01) {
 			clear_epp_timeout(pp);
 			break;
@@ -406,13 +409,14 @@
 {
 	struct parport_uss720_private *priv = pp->private_data;	
 	size_t written = 0;
+	const char *buff = buf;
 
 	if (change_mode(pp, ECR_EPP))
 		return 0;
 	for (; written < length; written++) {
-		if (set_1284_register(pp, 3, *(char *)buf))
+		if (set_1284_register(pp, 3, *buff))
 			break;
-		((char*)buf)++;
+		buff++;
 		if (get_1284_register(pp, 1, NULL))
 			break;
 		if (priv->reg[0] & 0x01) {
@@ -463,13 +467,14 @@
 static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
 {
 	size_t written = 0;
+	const char *buff = buffer;
 
 	if (change_mode(pp, ECR_ECP))
 		return 0;
 	for (; written < len; written++) {
-		if (set_1284_register(pp, 5, *(char *)buffer))
+		if (set_1284_register(pp, 5, *buff))
 			break;
-		((char*)buffer)++;
+		buff++;
 	}
 	change_mode(pp, ECR_PS2);
 	return written;
diff -urN linux-2.4.28-pre3/drivers/video/amifb.c linux-2.4.28-pre4/drivers/video/amifb.c
--- linux-2.4.28-pre3/drivers/video/amifb.c	2004-04-14 06:05:37.000000000 -0700
+++ linux-2.4.28-pre4/drivers/video/amifb.c	2004-10-08 06:28:26.090277229 -0700
@@ -1605,19 +1605,6 @@
 		return -ENXIO;
 
 	/*
-	 * TODO: where should we put this? The DMI Resolver doesn't have a
-	 *	 frame buffer accessible by the CPU
-	 */
-
-#ifdef CONFIG_GSP_RESOLVER
-	if (amifb_resolver){
-		custom.dmacon = DMAF_MASTER | DMAF_RASTER | DMAF_COPPER |
-				DMAF_BLITTER | DMAF_SPRITE;
-		return 0;
-	}
-#endif
-
-	/*
 	 * We request all registers starting from bplpt[0]
 	 */
 	if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
diff -urN linux-2.4.28-pre3/drivers/video/fbcon.c linux-2.4.28-pre4/drivers/video/fbcon.c
--- linux-2.4.28-pre3/drivers/video/fbcon.c	2004-10-08 06:28:21.892106430 -0700
+++ linux-2.4.28-pre4/drivers/video/fbcon.c	2004-10-08 06:28:26.091277270 -0700
@@ -660,9 +660,8 @@
     
     if (logo) {
     	/* Need to make room for the logo */
-	int cnt;
-	int step;
-    
+	int cnt, step, erase_char;
+
     	logo_lines = (LOGO_H + fontheight(p) - 1) / fontheight(p);
     	q = (unsigned short *)(conp->vc_origin + conp->vc_size_row * old_rows);
     	step = logo_lines * old_cols;
@@ -692,8 +691,10 @@
     		conp->vc_pos += logo_lines * conp->vc_size_row;
     	    }
     	}
-    	scr_memsetw((unsigned short *)conp->vc_origin,
-		    conp->vc_video_erase_char, 
+	erase_char = conp->vc_video_erase_char;
+	if (! conp->vc_can_do_color)
+	    erase_char &= ~0x400; /* disable underline */
+	scr_memsetw((unsigned short *)conp->vc_origin, erase_char,
 		    conp->vc_size_row * logo_lines);
     }
     
diff -urN linux-2.4.28-pre3/drivers/video/matrox/matroxfb_base.h linux-2.4.28-pre4/drivers/video/matrox/matroxfb_base.h
--- linux-2.4.28-pre3/drivers/video/matrox/matroxfb_base.h	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.28-pre4/drivers/video/matrox/matroxfb_base.h	2004-10-08 06:28:26.092277311 -0700
@@ -253,21 +253,21 @@
 #ifdef MEMCPYTOIO_WORKS
 	memcpy_toio(va.vaddr + offs, src, len);
 #elif defined(MEMCPYTOIO_WRITEL)
-#define srcd ((const u_int32_t*)src)
 	if (offs & 3) {
 		while (len >= 4) {
-			mga_writel(va, offs, get_unaligned(srcd++));
+			mga_writel(va, offs, get_unaligned((u32 *)src));
 			offs += 4;
 			len -= 4;
+			src += 4;
 		}
 	} else {
 		while (len >= 4) {
-			mga_writel(va, offs, *srcd++);
+			mga_writel(va, offs, *(u32 *)src);
 			offs += 4;
 			len -= 4;
+			src += 4;
 		}
 	}
-#undef srcd
 	if (len) {
 		u_int32_t tmp;
 
diff -urN linux-2.4.28-pre3/drivers/video/radeonfb.c linux-2.4.28-pre4/drivers/video/radeonfb.c
--- linux-2.4.28-pre3/drivers/video/radeonfb.c	2004-04-14 06:05:39.000000000 -0700
+++ linux-2.4.28-pre4/drivers/video/radeonfb.c	2004-10-08 06:28:26.120278450 -0700
@@ -935,6 +935,7 @@
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
 static struct fb_ops radeon_fb_ops = {
+	owner:			THIS_MODULE,
 	fb_get_fix:		radeonfb_get_fix,
 	fb_get_var:		radeonfb_get_var,
 	fb_set_var:		radeonfb_set_var,
@@ -2368,7 +2369,7 @@
 			disp->visual = FB_VISUAL_DIRECTCOLOR;
 			v.red.offset = 10;
 			v.green.offset = 5;
-			v.red.offset = 0;
+			v.blue.offset = 0;
 			v.red.length = v.green.length = v.blue.length = 5;
 			v.transp.offset = v.transp.length = 0;
 			break;
diff -urN linux-2.4.28-pre3/drivers/video/riva/accel.c linux-2.4.28-pre4/drivers/video/riva/accel.c
--- linux-2.4.28-pre3/drivers/video/riva/accel.c	2004-08-07 16:26:05.000000000 -0700
+++ linux-2.4.28-pre4/drivers/video/riva/accel.c	2004-10-08 06:28:26.121278491 -0700
@@ -153,8 +153,10 @@
 		for (j = 0; j < cnt; j++) {
 			if (w <= 8) 
 				cdat2 = *cdat++;
-			else
-				cdat2 = *((u16*)cdat)++;
+			else {
+				cdat2 = *(u16*)cdat;
+				cdat += sizeof(u16);
+			}
 			fbcon_reverse_order(&cdat2);
 			d[j] = cdat2;
 		}
diff -urN linux-2.4.28-pre3/fs/dcache.c linux-2.4.28-pre4/fs/dcache.c
--- linux-2.4.28-pre3/fs/dcache.c	2003-06-13 07:51:37.000000000 -0700
+++ linux-2.4.28-pre4/fs/dcache.c	2004-10-08 06:28:26.130278857 -0700
@@ -55,7 +55,10 @@
 /* Statistics gathering. */
 struct dentry_stat_t dentry_stat = {0, 0, 45, 0,};
 
-/* no dcache_lock, please */
+/*
+ * no dcache_lock, please.  The caller must decrement dentry_stat.nr_dentry
+ * inside dcache_lock.
+ */
 static inline void d_free(struct dentry *dentry)
 {
 	if (dentry->d_op && dentry->d_op->d_release)
@@ -63,7 +66,6 @@
 	if (dname_external(dentry)) 
 		kfree(dentry->d_name.name);
 	kmem_cache_free(dentry_cache, dentry); 
-	dentry_stat.nr_dentry--;
 }
 
 /*
@@ -148,6 +150,7 @@
 kill_it: {
 		struct dentry *parent;
 		list_del(&dentry->d_child);
+		dentry_stat.nr_dentry--;	/* For d_free, below */
 		/* drops the lock, at that point nobody can reach this dentry */
 		dentry_iput(dentry);
 		parent = dentry->d_parent;
@@ -297,6 +300,7 @@
 
 	list_del_init(&dentry->d_hash);
 	list_del(&dentry->d_child);
+	dentry_stat.nr_dentry--;	/* For d_free, below */
 	dentry_iput(dentry);
 	parent = dentry->d_parent;
 	d_free(dentry);
@@ -623,13 +627,15 @@
 	if (parent) {
 		dentry->d_parent = dget(parent);
 		dentry->d_sb = parent->d_sb;
-		spin_lock(&dcache_lock);
-		list_add(&dentry->d_child, &parent->d_subdirs);
-		spin_unlock(&dcache_lock);
 	} else
 		INIT_LIST_HEAD(&dentry->d_child);
 
+	spin_lock(&dcache_lock);
+	if (parent)
+		list_add(&dentry->d_child, &parent->d_subdirs);
 	dentry_stat.nr_dentry++;
+	spin_unlock(&dcache_lock);
+
 	return dentry;
 }
 
diff -urN linux-2.4.28-pre3/include/linux/compiler.h linux-2.4.28-pre4/include/linux/compiler.h
--- linux-2.4.28-pre3/include/linux/compiler.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.28-pre4/include/linux/compiler.h	2004-10-08 06:28:26.238283251 -0700
@@ -37,5 +37,6 @@
 
 /* no checker support, so we unconditionally define this as (null) */
 #define __user
+#define __iomem
 
 #endif /* __LINUX_COMPILER_H */
diff -urN linux-2.4.28-pre3/include/linux/libata.h linux-2.4.28-pre4/include/linux/libata.h
--- linux-2.4.28-pre3/include/linux/libata.h	2004-10-08 06:28:22.017111516 -0700
+++ linux-2.4.28-pre4/include/linux/libata.h	2004-10-08 06:28:26.248283658 -0700
@@ -197,7 +197,7 @@
 	unsigned long		irq;
 	unsigned int		irq_flags;
 	unsigned long		host_flags;
-	void			*mmio_base;
+	void __iomem		*mmio_base;
 	void			*private_data;
 };
 
@@ -205,7 +205,7 @@
 	spinlock_t		lock;
 	struct pci_dev		*pdev;
 	unsigned long		irq;
-	void			*mmio_base;
+	void __iomem		*mmio_base;
 	unsigned int		n_ports;
 	void			*private_data;
 	struct ata_port_operations *ops;
@@ -380,19 +380,19 @@
 /*
  * Default driver ops implementations
  */
-extern void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf);
+extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
 extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp);
 extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf);
-extern u8 ata_check_status_pio(struct ata_port *ap);
-extern u8 ata_check_status_mmio(struct ata_port *ap);
-extern void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+extern u8 ata_check_status(struct ata_port *ap);
+extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf);
 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 struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port);
+extern struct ata_probe_ent *
+ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port);
 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,
@@ -401,10 +401,8 @@
 		 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_setup (struct ata_queued_cmd *qc);
+extern void ata_bmdma_start (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);
@@ -433,7 +431,7 @@
 static inline u8 ata_chk_err(struct ata_port *ap)
 {
 	if (ap->flags & ATA_FLAG_MMIO) {
-		return readb((void *) ap->ioaddr.error_addr);
+		return readb((void __iomem *) ap->ioaddr.error_addr);
 	}
 	return inb(ap->ioaddr.error_addr);
 }
@@ -446,7 +444,7 @@
 static inline u8 ata_altstatus(struct ata_port *ap)
 {
 	if (ap->flags & ATA_FLAG_MMIO)
-		return readb(ap->ioaddr.altstatus_addr);
+		return readb((void __iomem *)ap->ioaddr.altstatus_addr);
 	return inb(ap->ioaddr.altstatus_addr);
 }
 
@@ -517,7 +515,7 @@
 	ap->last_ctl = ap->ctl;
 
 	if (ap->flags & ATA_FLAG_MMIO)
-		writeb(ap->ctl, ioaddr->ctl_addr);
+		writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
 	else
 		outb(ap->ctl, ioaddr->ctl_addr);
 	tmp = ata_wait_idle(ap);
@@ -538,7 +536,7 @@
 
 	/* get controller status; clear intr, err bits */
 	if (ap->flags & ATA_FLAG_MMIO) {
-		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+		void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
 		host_stat = readb(mmio + ATA_DMA_STATUS);
 		writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
 		       mmio + ATA_DMA_STATUS);
@@ -576,7 +574,7 @@
 static inline void ata_bmdma_stop(struct ata_port *ap)
 {
 	if (ap->flags & ATA_FLAG_MMIO) {
-		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+		void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
 
 		/* clear start/stop bit */
 		writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
@@ -594,7 +592,7 @@
 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;
+		void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
 		writeb(readb(mmio), mmio);
 	} else {
 		unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
@@ -606,7 +604,7 @@
 {
 	u8 host_stat;
 	if (ap->flags & ATA_FLAG_MMIO) {
-		void *mmio = (void *) ap->ioaddr.bmdma_addr;
+		void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
 		host_stat = readb(mmio + ATA_DMA_STATUS);
 	} else
 		host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
diff -urN linux-2.4.28-pre3/include/linux/socket.h linux-2.4.28-pre4/include/linux/socket.h
--- linux-2.4.28-pre3/include/linux/socket.h	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.28-pre4/include/linux/socket.h	2004-10-08 06:28:26.306286017 -0700
@@ -137,7 +137,6 @@
 
 #define	SCM_RIGHTS	0x01		/* rw: access rights (array of int) */
 #define SCM_CREDENTIALS 0x02		/* rw: struct ucred		*/
-#define SCM_CONNECT	0x03		/* rw: struct scm_connect	*/
 
 struct ucred {
 	__u32	pid;
diff -urN linux-2.4.28-pre3/include/linux/string.h linux-2.4.28-pre4/include/linux/string.h
--- linux-2.4.28-pre3/include/linux/string.h	2001-11-22 11:46:19.000000000 -0800
+++ linux-2.4.28-pre4/include/linux/string.h	2004-10-08 06:28:26.323286709 -0700
@@ -7,6 +7,7 @@
 
 #include <linux/types.h>	/* for size_t */
 #include <linux/stddef.h>	/* for NULL */
+#include <linux/compiler.h>	/* for inline ((always_inline)) */
 
 #ifdef __cplusplus
 extern "C" {
diff -urN linux-2.4.28-pre3/include/linux/tcp_diag.h linux-2.4.28-pre4/include/linux/tcp_diag.h
--- linux-2.4.28-pre3/include/linux/tcp_diag.h	2001-12-21 09:42:04.000000000 -0800
+++ linux-2.4.28-pre4/include/linux/tcp_diag.h	2004-10-08 06:28:26.324286750 -0700
@@ -98,9 +98,10 @@
 	TCPDIAG_NONE,
 	TCPDIAG_MEMINFO,
 	TCPDIAG_INFO,
+	TCPDIAG_VEGASINFO,
 };
 
-#define TCPDIAG_MAX TCPDIAG_INFO
+#define TCPDIAG_MAX TCPDIAG_VEGASINFO
 
 
 /* TCPDIAG_MEM */
@@ -113,4 +114,14 @@
 	__u32	tcpdiag_tmem;
 };
 
+/* TCPDIAG_VEGASINFO */
+
+struct tcpvegas_info {
+	__u32	tcpv_enabled;
+	__u32	tcpv_rttcnt;
+	__u32	tcpv_rtt;
+	__u32	tcpv_minrtt;
+};
+
+
 #endif /* _TCP_DIAG_H_ */
diff -urN linux-2.4.28-pre3/include/net/pkt_sched.h linux-2.4.28-pre4/include/net/pkt_sched.h
--- linux-2.4.28-pre3/include/net/pkt_sched.h	2004-10-08 06:28:22.034112208 -0700
+++ linux-2.4.28-pre4/include/net/pkt_sched.h	2004-10-08 06:28:26.330286994 -0700
@@ -81,6 +81,7 @@
 #define TCQ_F_INGRES	4
 	struct Qdisc_ops	*ops;
 	u32			handle;
+	u32			parent;
 	atomic_t		refcnt;
 	struct sk_buff_head	q;
 	struct net_device	*dev;
diff -urN linux-2.4.28-pre3/include/net/sock.h linux-2.4.28-pre4/include/net/sock.h
--- linux-2.4.28-pre3/include/net/sock.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.28-pre4/include/net/sock.h	2004-10-08 06:28:26.333287116 -0700
@@ -256,6 +256,13 @@
 	__u32	end_seq;
 };
 
+enum tcp_congestion_algo {
+ 	TCP_RENO=0,
+ 	TCP_VEGAS,
+ 	TCP_WESTWOOD,
+ 	TCP_BIC,
+};
+ 
 struct tcp_opt {
 	int	tcp_header_len;	/* Bytes of tcp header to send		*/
 
@@ -428,7 +435,8 @@
 	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
 	int			linger2;
 
-	int                     frto_counter; /* Number of new acks after RTO */
+	__u8			adv_cong;    /* Using Vegas, Westwood, or BIC */
+	__u8                    frto_counter; /* Number of new acks after RTO */
 	__u32                   frto_highmark; /* snd_nxt when RTO occurred */
 
 	unsigned long last_synq_overflow; 
@@ -465,7 +473,6 @@
 		__u32	beg_snd_nxt;	/* right edge during last RTT */
 		__u32	beg_snd_una;	/* left edge  during last RTT */
 		__u32	beg_snd_cwnd;	/* saves the size of the cwnd */
-		__u8	do_vegas;	/* do vegas for this connection */
 		__u8	doing_vegas_now;/* if true, do vegas for this RTT */
 		__u16	cntRTT;		/* # of RTTs measured within last RTT */
 		__u32	minRTT;		/* min of RTTs measured within last RTT (in usec) */
diff -urN linux-2.4.28-pre3/include/net/tcp.h linux-2.4.28-pre4/include/net/tcp.h
--- linux-2.4.28-pre3/include/net/tcp.h	2004-08-07 16:26:06.000000000 -0700
+++ linux-2.4.28-pre4/include/net/tcp.h	2004-10-08 06:28:26.335287197 -0700
@@ -1110,6 +1110,13 @@
 	return tp->packets_out - tp->left_out + tp->retrans_out;
 }
 
+/*
+ * Which congestion algorithim is in use on the connection.
+ */
+#define tcp_is_vegas(__tp)	((__tp)->adv_cong == TCP_VEGAS)
+#define tcp_is_westwood(__tp)	((__tp)->adv_cong == TCP_WESTWOOD)
+#define tcp_is_bic(__tp)	((__tp)->adv_cong == TCP_BIC)
+
 /* Recalculate snd_ssthresh, we want to set it to:
  *
  * Reno:
@@ -1122,7 +1129,7 @@
  */
 static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
 {
-	if (sysctl_tcp_bic) {
+	if (tcp_is_bic(tp)) {
 		if (sysctl_tcp_bic_fast_convergence &&
 		    tp->snd_cwnd < tp->bictcp.last_max_cwnd)
 			tp->bictcp.last_max_cwnd
@@ -1141,11 +1148,6 @@
 
 /* Stop taking Vegas samples for now. */
 #define tcp_vegas_disable(__tp)	((__tp)->vegas.doing_vegas_now = 0)
-
-/* Is this TCP connection using Vegas (regardless of whether it is taking
- * Vegas measurements at the current time)?
- */
-#define tcp_is_vegas(__tp)	((__tp)->vegas.do_vegas)
     
 static inline void tcp_vegas_enable(struct tcp_opt *tp)
 {
@@ -1179,7 +1181,7 @@
 /* Should we be taking Vegas samples right now? */
 #define tcp_vegas_enabled(__tp)	((__tp)->vegas.doing_vegas_now)
 
-extern void tcp_vegas_init(struct tcp_opt *tp);
+extern void tcp_ca_init(struct tcp_opt *tp);
 
 static inline void tcp_set_ca_state(struct tcp_opt *tp, u8 ca_state)
 {
@@ -1978,7 +1980,7 @@
 
 static inline void tcp_westwood_update_rtt(struct tcp_opt *tp, __u32 rtt_seq)
 {
-	if (sysctl_tcp_westwood)
+	if (tcp_is_westwood(tp))
 		tp->westwood.rtt = rtt_seq;
 }
 
@@ -2015,13 +2017,13 @@
 
 static inline void tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb)
 {
-	if (sysctl_tcp_westwood)
+	if (tcp_is_westwood(&(sk->tp_pinfo.af_tcp)))
 		__tcp_westwood_fast_bw(sk, skb);
 }
 
 static inline void tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb)
 {
-	if (sysctl_tcp_westwood)
+	if (tcp_is_westwood(&(sk->tp_pinfo.af_tcp)))
 		__tcp_westwood_slow_bw(sk, skb);
 }
 
@@ -2035,7 +2037,7 @@
 {
 	__u32 ret = 0;
 
-	if (sysctl_tcp_westwood)
+	if (tcp_is_westwood(tp))
 		ret = (__u32) (max(__tcp_westwood_bw_rttmin(tp), 2U));
 
 	return ret;
@@ -2046,7 +2048,7 @@
 	int ret = 0;
 	__u32 ssthresh;
 
-	if (sysctl_tcp_westwood) {
+	if (tcp_is_westwood(tp)) {
 		if (!(ssthresh = tcp_westwood_bw_rttmin(tp)))
 			return ret;
 
@@ -2062,7 +2064,7 @@
 	int ret = 0;
 	__u32 cwnd;
 
-	if (sysctl_tcp_westwood) {
+	if (tcp_is_westwood(tp)) {
 		if (!(cwnd = tcp_westwood_bw_rttmin(tp)))
 			return ret;
 
@@ -2077,7 +2079,7 @@
 {
 	int ret = 0;
 
-	if (sysctl_tcp_westwood) {
+	if (tcp_is_westwood(tp)) {
 		if (tcp_westwood_cwnd(tp)) {
 			tp->snd_ssthresh = tp->snd_cwnd;
 			ret = 1;
diff -urN linux-2.4.28-pre3/include/pcmcia/mem_op.h linux-2.4.28-pre4/include/pcmcia/mem_op.h
--- linux-2.4.28-pre3/include/pcmcia/mem_op.h	2001-02-16 16:02:37.000000000 -0800
+++ linux-2.4.28-pre4/include/pcmcia/mem_op.h	2004-10-08 06:28:26.335287197 -0700
@@ -81,7 +81,9 @@
     n -= odd;
     while (n) {
 	*(u_short *)to = __raw_readw(from);
-	(char *)to += 2; (char *)from += 2; n -= 2;
+	to = (void *)((long)to + 2);
+	from = (const void *)((long)from + 2);
+	n -= 2;
     }
     if (odd)
 	*(u_char *)to = readb(from);
@@ -93,7 +95,9 @@
     n -= odd;
     while (n) {
 	__raw_writew(*(u_short *)from, to);
-	(char *)to += 2; (char *)from += 2; n -= 2;
+	to = (void *)((long)to + 2);
+	from = (const void *)((long)from + 2);
+	n -= 2;
     }
     if (odd)
 	writeb(*(u_char *)from, to);
@@ -105,7 +109,9 @@
     n -= odd;
     while (n) {
 	put_user(__raw_readw(from), (short *)to);
-	(char *)to += 2; (char *)from += 2; n -= 2;
+	to = (void *)((long)to + 2);
+	from = (const void *)((long)from + 2);
+	n -= 2;
     }
     if (odd)
 	put_user(readb(from), (char *)to);
@@ -120,7 +126,9 @@
     while (n) {
 	get_user(s, (short *)from);
 	__raw_writew(s, to);
-	(char *)to += 2; (char *)from += 2; n -= 2;
+	to = (void *)((long)to + 2);
+	from = (const void *)((long)from + 2);
+	n -= 2;
     }
     if (odd) {
 	get_user(c, (char *)from);
diff -urN linux-2.4.28-pre3/net/ipv4/ipconfig.c linux-2.4.28-pre4/net/ipv4/ipconfig.c
--- linux-2.4.28-pre3/net/ipv4/ipconfig.c	2003-11-28 10:26:21.000000000 -0800
+++ linux-2.4.28-pre4/net/ipv4/ipconfig.c	2004-10-08 06:28:26.364288377 -0700
@@ -899,6 +899,9 @@
 				break;
 
 			case DHCPACK:
+				if (memcmp(dev->dev_addr, b->hw_addr, dev->addr_len) != 0)
+					goto drop;
+
 				/* Yeah! */
 				break;
 
diff -urN linux-2.4.28-pre3/net/ipv4/tcp_diag.c linux-2.4.28-pre4/net/ipv4/tcp_diag.c
--- linux-2.4.28-pre3/net/ipv4/tcp_diag.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.28-pre4/net/ipv4/tcp_diag.c	2004-10-08 06:28:26.372288703 -0700
@@ -49,6 +49,7 @@
 	struct nlmsghdr  *nlh;
 	struct tcp_info  *info = NULL;
 	struct tcpdiag_meminfo  *minfo = NULL;
+	struct tcpvegas_info *vinfo = NULL;
 	unsigned char	 *b = skb->tail;
 
 	nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
@@ -58,6 +59,10 @@
 			minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo));
 		if (ext & (1<<(TCPDIAG_INFO-1)))
 			info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
+
+		if ((tcp_is_westwood(tp) || tcp_is_vegas(tp))
+		    && (ext & (1<<(TCPDIAG_VEGASINFO-1))))
+			vinfo = TCPDIAG_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*vinfo));
 	}
 	r->tcpdiag_family = sk->family;
 	r->tcpdiag_state = sk->state;
@@ -186,6 +191,20 @@
 		info->tcpi_reordering = tp->reordering;
 	}
 
+	if (vinfo) {
+		if (tcp_is_vegas(tp)) {
+			vinfo->tcpv_enabled = tp->vegas.doing_vegas_now;
+			vinfo->tcpv_rttcnt = tp->vegas.cntRTT;
+			vinfo->tcpv_rtt = (1000000*tp->vegas.baseRTT)/HZ;
+			vinfo->tcpv_minrtt = (1000000*tp->vegas.minRTT)/HZ;
+		} else {
+			vinfo->tcpv_enabled = 0;
+			vinfo->tcpv_rttcnt = 0;
+			vinfo->tcpv_rtt = (1000000*tp->westwood.rtt)/HZ;
+			vinfo->tcpv_minrtt = (1000000*tp->westwood.rtt_min)/HZ;
+		}
+	}
+
 	nlh->nlmsg_len = skb->tail - b;
 	return skb->len;
 
diff -urN linux-2.4.28-pre3/net/ipv4/tcp_input.c linux-2.4.28-pre4/net/ipv4/tcp_input.c
--- linux-2.4.28-pre3/net/ipv4/tcp_input.c	2004-10-08 06:28:22.082114161 -0700
+++ linux-2.4.28-pre4/net/ipv4/tcp_input.c	2004-10-08 06:28:26.375288825 -0700
@@ -549,17 +549,20 @@
 		tcp_grow_window(sk, tp, skb);
 }
 
-/* Set up a new TCP connection, depending on whether it should be
- * using Vegas or not.
- */    
-void tcp_vegas_init(struct tcp_opt *tp)
+/* When starting a new connection, pin down the current choice of 
+ * congestion algorithm.
+ */
+void tcp_ca_init(struct tcp_opt *tp)
 {
-	if (sysctl_tcp_vegas_cong_avoid) {
-		tp->vegas.do_vegas = 1;
+	if (sysctl_tcp_westwood) 
+		tp->adv_cong = TCP_WESTWOOD;
+	else if (sysctl_tcp_bic)
+		tp->adv_cong = TCP_BIC;
+	else if (sysctl_tcp_vegas_cong_avoid) {
+		tp->adv_cong = TCP_VEGAS;
 		tp->vegas.baseRTT = 0x7fffffff;
 		tcp_vegas_enable(tp);
-	} else 
-		tcp_vegas_disable(tp);
+	} 
 }
 
 /* Do RTT sampling needed for Vegas.
@@ -2007,7 +2010,7 @@
 static inline __u32 bictcp_cwnd(struct tcp_opt *tp)
 {
 	/* orignal Reno behaviour */
-	if (!sysctl_tcp_bic)
+	if (!tcp_is_bic(tp))
 		return tp->snd_cwnd;
 
 	if (tp->bictcp.last_cwnd == tp->snd_cwnd &&
@@ -2553,15 +2556,13 @@
  * WESTWOOD_RTT_MIN minimum bound since we could be on a LAN!
  */
 
-static inline __u32 westwood_update_rttmin(struct sock *sk)
+static inline __u32 westwood_update_rttmin(const struct sock *sk)
 {
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	const struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	__u32 rttmin = tp->westwood.rtt_min;
 
-	if (tp->westwood.rtt == 0)
-		return rttmin;
-
-	if (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin)
+	if (tp->westwood.rtt != 0 && 
+	    (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin))
 		rttmin = tp->westwood.rtt;
 
 	return rttmin;
@@ -2572,9 +2573,9 @@
  * Evaluate increases for dk. 
  */
 
-static __u32 westwood_acked(struct sock *sk)
+static __u32 westwood_acked(const struct sock *sk)
 {
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	const struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	return ((tp->snd_una) - (tp->westwood.snd_una));
 }
@@ -2588,9 +2589,9 @@
  * window, 1 if the sample has to be considered in the next window.
  */
 
-static int westwood_new_window(struct sock *sk)
+static int westwood_new_window(const struct sock *sk)
 {
-	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+	const struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	__u32 left_bound;
 	__u32 rtt;
 	int ret = 0;
@@ -2624,14 +2625,13 @@
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 	__u32 delta = now - tp->westwood.rtt_win_sx;
 
-	if (!delta)
-		return;
-
-	if (tp->westwood.rtt)
-		westwood_filter(sk, delta);
+	if (delta) {
+		if (tp->westwood.rtt)
+			westwood_filter(sk, delta);
 
-	tp->westwood.bk = 0;
-	tp->westwood.rtt_win_sx = tcp_time_stamp;
+		tp->westwood.bk = 0;
+		tp->westwood.rtt_win_sx = tcp_time_stamp;
+	}
 }
 
 static void westwood_update_window(struct sock *sk, __u32 now)
@@ -2685,7 +2685,7 @@
 
 static inline int westwood_may_change_cumul(struct tcp_opt *tp)
 {
-	return ((tp->westwood.cumul_ack) > westwood_mss(tp));
+	return (tp->westwood.cumul_ack > westwood_mss(tp));
 }
 
 static inline void westwood_partial_update(struct tcp_opt *tp)
@@ -2706,7 +2706,7 @@
  * delayed or partial acks.
  */
 
-static __u32 westwood_acked_count(struct sock *sk)
+static inline __u32 westwood_acked_count(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
@@ -2720,7 +2720,7 @@
 
 	if (westwood_may_change_cumul(tp)) {
 		/* Partial or delayed ack */
-		if ((tp->westwood.accounted) >= (tp->westwood.cumul_ack))
+		if (tp->westwood.accounted >= tp->westwood.cumul_ack)
 			westwood_partial_update(tp);
 		else 
 			westwood_complete_update(tp);
diff -urN linux-2.4.28-pre3/net/ipv4/tcp_ipv4.c linux-2.4.28-pre4/net/ipv4/tcp_ipv4.c
--- linux-2.4.28-pre3/net/ipv4/tcp_ipv4.c	2004-04-14 06:05:41.000000000 -0700
+++ linux-2.4.28-pre4/net/ipv4/tcp_ipv4.c	2004-10-08 06:28:26.377288906 -0700
@@ -1025,11 +1025,7 @@
 
 	switch (type) {
 	case ICMP_SOURCE_QUENCH:
-		/* This is deprecated, but if someone generated it,
-		 * we have no reasons to ignore it.
-		 */
-		if (sk->lock.users == 0)
-			tcp_enter_cwr(tp);
+		/* Just silently ignore these. */
 		goto out;
 	case ICMP_PARAMETERPROB:
 		err = EPROTO;
diff -urN linux-2.4.28-pre3/net/ipv4/tcp_minisocks.c linux-2.4.28-pre4/net/ipv4/tcp_minisocks.c
--- linux-2.4.28-pre3/net/ipv4/tcp_minisocks.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.28-pre4/net/ipv4/tcp_minisocks.c	2004-10-08 06:28:26.378288947 -0700
@@ -788,7 +788,7 @@
 		newtp->mss_clamp = req->mss;
 		TCP_ECN_openreq_child(newtp, req);
 
-		tcp_vegas_init(newtp);
+		tcp_ca_init(newtp);
 		TCP_INC_STATS_BH(TcpPassiveOpens);
 	}
 	return newsk;
diff -urN linux-2.4.28-pre3/net/ipv4/tcp_output.c linux-2.4.28-pre4/net/ipv4/tcp_output.c
--- linux-2.4.28-pre3/net/ipv4/tcp_output.c	2004-08-07 16:26:07.000000000 -0700
+++ linux-2.4.28-pre4/net/ipv4/tcp_output.c	2004-10-08 06:28:26.379288987 -0700
@@ -1197,7 +1197,7 @@
 		tp->window_clamp = dst->window;
 	tp->advmss = dst->advmss;
 	tcp_initialize_rcv_mss(sk);
-	tcp_vegas_init(tp);
+	tcp_ca_init(tp);
 
 	tcp_select_initial_window(tcp_full_space(sk),
 				  tp->advmss - (tp->ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
@@ -1248,7 +1248,7 @@
 	TCP_SKB_CB(buff)->end_seq = tp->write_seq;
 	tp->snd_nxt = tp->write_seq;
 	tp->pushed_seq = tp->write_seq;
-	tcp_vegas_init(tp);
+	tcp_ca_init(tp);
 
 	/* Send it off. */
 	TCP_SKB_CB(buff)->when = tcp_time_stamp;
diff -urN linux-2.4.28-pre3/net/ipv6/exthdrs.c linux-2.4.28-pre4/net/ipv6/exthdrs.c
--- linux-2.4.28-pre3/net/ipv6/exthdrs.c	2004-10-08 06:28:22.086114323 -0700
+++ linux-2.4.28-pre4/net/ipv6/exthdrs.c	2004-10-08 06:28:26.383289150 -0700
@@ -293,9 +293,11 @@
 	dst_release(xchg(&skb->dst, NULL));
 	ip6_route_input(skb);
 	if (skb->dst->error) {
+		skb_push(skb, skb->data - skb->nh.raw);
 		skb->dst->input(skb);
 		return -1;
 	}
+
 	if (skb->dst->dev->flags&IFF_LOOPBACK) {
 		if (skb->nh.ipv6h->hop_limit <= 1) {
 			icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
@@ -307,6 +309,7 @@
 		goto looped_back;
 	}
 
+	skb_push(skb, skb->data - skb->nh.raw);
 	skb->dst->input(skb);
 	return -1;
 }
diff -urN linux-2.4.28-pre3/net/ipv6/sit.c linux-2.4.28-pre4/net/ipv6/sit.c
--- linux-2.4.28-pre3/net/ipv6/sit.c	2004-10-08 06:28:22.096114730 -0700
+++ linux-2.4.28-pre4/net/ipv6/sit.c	2004-10-08 06:28:26.393289557 -0700
@@ -500,6 +500,7 @@
 		goto tx_error_icmp;
 	}
 	if (rt->rt_type != RTN_UNICAST) {
+		ip_rt_put(rt);
 		tunnel->stat.tx_carrier_errors++;
 		goto tx_error_icmp;
 	}
diff -urN linux-2.4.28-pre3/net/ipv6/tcp_ipv6.c linux-2.4.28-pre4/net/ipv6/tcp_ipv6.c
--- linux-2.4.28-pre3/net/ipv6/tcp_ipv6.c	2004-10-08 06:28:22.098114812 -0700
+++ linux-2.4.28-pre4/net/ipv6/tcp_ipv6.c	2004-10-08 06:28:26.395289638 -0700
@@ -978,11 +978,11 @@
 	 * and then put it into the queue to be sent.
 	 */
 
-	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC);
+	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr), GFP_ATOMIC);
 	if (buff == NULL) 
 	  	return;
 
-	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr));
+	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + sizeof(struct tcphdr));
 
 	t1 = (struct tcphdr *) skb_push(buff,sizeof(struct tcphdr));
 
@@ -1037,14 +1037,14 @@
 	struct flowi fl;
 	int tot_len = sizeof(struct tcphdr);
 
-	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr), GFP_ATOMIC);
+	if (ts)
+		tot_len += 3*4;
+
+	buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, GFP_ATOMIC);
 	if (buff == NULL)
 		return;
 
-	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr));
-
-	if (ts)
-		tot_len += 3*4;
+	skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len);
 
 	t1 = (struct tcphdr *) skb_push(buff,tot_len);
 
diff -urN linux-2.4.28-pre3/net/sched/sch_api.c linux-2.4.28-pre4/net/sched/sch_api.c
--- linux-2.4.28-pre3/net/sched/sch_api.c	2004-10-08 06:28:22.106115137 -0700
+++ linux-2.4.28-pre4/net/sched/sch_api.c	2004-10-08 06:28:26.403289964 -0700
@@ -371,6 +371,8 @@
 			unsigned long cl = cops->get(parent, classid);
 			if (cl) {
 				err = cops->graft(parent, cl, new, old);
+				if (new)
+					new->parent = classid;
 				cops->put(parent, cl);
 			}
 		}
@@ -812,7 +814,7 @@
 				q_idx++;
 				continue;
 			}
-			if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid,
+			if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
 					  cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
 				read_unlock(&qdisc_tree_lock);
 				goto done;
diff -urN linux-2.4.28-pre3/net/sched/sch_cbq.c linux-2.4.28-pre4/net/sched/sch_cbq.c
--- linux-2.4.28-pre3/net/sched/sch_cbq.c	2004-10-08 06:28:22.108115218 -0700
+++ linux-2.4.28-pre4/net/sched/sch_cbq.c	2004-10-08 06:28:26.405290045 -0700
@@ -1736,10 +1736,6 @@
 #ifdef CONFIG_NET_CLS_POLICE
 	q->rx_class = NULL;
 #endif
-	for (h = 0; h < 16; h++) {
-		for (cl = q->classes[h]; cl; cl = cl->next)
-			cbq_destroy_filters(cl);
-	}
 
 	for (h = 0; h < 16; h++) {
 		struct cbq_class *next;
@@ -1750,7 +1746,6 @@
 		}
 	}
 
-	qdisc_put_rtab(q->link.R_tab);
 	MOD_DEC_USE_COUNT;
 }
 
diff -urN linux-2.4.28-pre3/net/sched/sch_netem.c linux-2.4.28-pre4/net/sched/sch_netem.c
--- linux-2.4.28-pre3/net/sched/sch_netem.c	2004-10-08 06:28:22.116115544 -0700
+++ linux-2.4.28-pre4/net/sched/sch_netem.c	2004-10-08 06:28:26.414290411 -0700
@@ -22,6 +22,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
+#include <linux/init.h>
 
 #include <net/pkt_sched.h>
 
diff -urN linux-2.4.28-pre3/scripts/Menuconfig linux-2.4.28-pre4/scripts/Menuconfig
--- linux-2.4.28-pre3/scripts/Menuconfig	2002-08-02 17:39:46.000000000 -0700
+++ linux-2.4.28-pre4/scripts/Menuconfig	2004-10-08 06:28:26.432291144 -0700
@@ -714,7 +714,7 @@
 
 function parser(ifile,menu) {
 
-	while (getline <ifile) {
+	while ((getline <ifile) > 0) {
 		if ($1 == "mainmenu_option") {
 			comment_is_option = "1"
 		}
@@ -761,7 +761,7 @@
 
 function parser(ifile,menu) {
 
-	while (getline <ifile) {
+	while ((getline <ifile) > 0) {
 		if ($0 ~ /^#|$MAKE|mainmenu_name/) {
 			printf("") >>menu
 		}
