## Automatically generated incremental diff
## From:   linux-2.2.19-pre9
## To:     linux-2.2.19-pre10
## Robot:  $Id: make-incremental-diff,v 1.6 2001/12/04 04:41:15 hpa Exp $

diff -urN linux-2.2.19-pre9/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.19-pre9/Documentation/Configure.help	Mon Dec  3 21:00:53 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 21:01:13 2001
@@ -6314,6 +6314,18 @@
 
   If you don't have this card, of course say N.
 
+Adaptec Starfire support (EXPERIMENTAL)
+CONFIG_ADAPTEC_STARFIRE
+  Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
+  adapter. The DuraLAN chip is used on the 64 bit PCI boards from
+  Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
+  driver.
+  
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called starfire.o.
+  
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
diff -urN linux-2.2.19-pre9/MAINTAINERS linux/MAINTAINERS
--- linux-2.2.19-pre9/MAINTAINERS	Mon Dec  3 21:00:54 2001
+++ linux/MAINTAINERS	Mon Dec  3 21:01:13 2001
@@ -938,6 +938,11 @@
 W:	http://www.stallion.com
 S:	Supported
 
+STARFIRE/DURALAN NETWORK DRIVER
+P:	Ion Badulescu
+M:	ionut@cs.columbia.edu
+S:	Maintained
+
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
 W:	http://mosquitonet.Stanford.EDU/strip.html
 S:	Unsupported ?
diff -urN linux-2.2.19-pre9/Makefile linux/Makefile
--- linux-2.2.19-pre9/Makefile	Mon Dec  3 21:00:54 2001
+++ linux/Makefile	Mon Dec  3 21:01:13 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 19
-EXTRAVERSION = pre9
+EXTRAVERSION = pre10
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.19-pre9/aic7xxx-5.1.32.patch linux/aic7xxx-5.1.32.patch
--- linux-2.2.19-pre9/aic7xxx-5.1.32.patch	Wed Dec 31 16:00:00 1969
+++ linux/aic7xxx-5.1.32.patch	Mon Dec  3 21:01:13 2001
@@ -0,0 +1,7633 @@
+diff -U 3 -rN linux-2.2.17/drivers/scsi/Config.in linux/drivers/scsi/Config.in
+--- linux-2.2.17/drivers/scsi/Config.in	Wed May  3 20:16:44 2000
++++ linux/drivers/scsi/Config.in	Tue Feb  6 03:50:13 2001
+@@ -28,10 +28,9 @@
+ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
+ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
+-    bool '   Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+-    int  '   Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
+-    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+-    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
++    bool '   Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT y
++    int  '   Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 24
++    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS y
+ fi
+ dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
+ dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
+diff -U 3 -rN linux-2.2.17/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx
+--- linux-2.2.17/drivers/scsi/README.aic7xxx	Wed May  3 20:16:44 2000
++++ linux/drivers/scsi/README.aic7xxx	Tue Feb  6 03:49:36 2001
+@@ -14,50 +14,17 @@
+     Adaptec Cards
+     ----------------------------
+     AHA-274x
+-    AHA-274xT               
+-    AHA-2842
+-    AHA-2910B               
+-    AHA-2920C
+-    AHA-2930
+-    AHA-2930U
+-    AHA-2930CU
+-    AHA-2930U2
+-    AHA-2940               
+-    AHA-2940W              
+-    AHA-2940U              
+-    AHA-2940UW
+-    AHA-2940UW-PRO
+-    AHA-2940AU 
+-    AHA-2940U2W
+-    AHA-2940U2
+-    AHA-2940U2B
+-    AHA-2940U2BOEM
+-    AHA-2944D              
+-    AHA-2944WD
+-    AHA-2944UD
+-    AHA-2944UWD
+-    AHA-2950U2
+-    AHA-2950U2W
+-    AHA-2950U2B
+-    AHA-29160M
+-    AHA-3940
+-    AHA-3940U
+-    AHA-3940W
+-    AHA-3940UW
+-    AHA-3940AUW
+-    AHA-3940U2W
+-    AHA-3950U2B
+-    AHA-3950U2D
+-    AHA-3960D
+-    AHA-39160M
+-    AHA-3985
+-    AHA-3985U
+-    AHA-3985W
+-    AHA-3985UW
++    AHA-274xT
++    AHA-274xW
++    AHA-284x
++    AHA-284xW
++    All PCI based cards using any of the chipsets listed under motherboard
++    chipsets.  In general, this means *all* of the Adaptec SCSI controllers
++    except the ones specifically excluded later on in this document.
+ 
+     Motherboard Chipsets
+     ----------------------------
+-    AIC-777x   
++    AIC-777x
+     AIC-785x
+     AIC-786x
+     AIC-787x
+@@ -71,15 +38,14 @@
+         SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
+     U - Ultra SCSI, transfer rates up to 40MB/s.
+     U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
++    U3- Ultra 3 SCSI, transfer rates up to 160MB/s.
+     D - Differential SCSI.
+     T - Twin Channel SCSI. Up to 14 SCSI devices.
+ 
+     AHA-274x - EISA SCSI controller
+     AHA-284x - VLB SCSI controller
+     AHA-29xx - PCI SCSI controller
+-    AHA-394x - PCI controllers with two separate SCSI controllers on-board.
+-    AHA-398x - PCI RAID controllers with three separate SCSI controllers
+-               on-board.
++    AHA-39xx - PCI controllers with multiple separate SCSI channels on-board.
+ 
+   Not Supported Devices
+   ------------------------------
+@@ -93,7 +59,7 @@
+ 
+     Motherboard Chipsets
+     ----------------------------
+-    AIC-7810
++    AIC-781x
+ 
+     Bus Types
+     ----------------------------
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h
+--- linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx.h	Wed Dec 31 19:00:00 1969
++++ linux/drivers/scsi/aic7xxx/aic7xxx.h	Tue Feb  6 03:49:36 2001
+@@ -0,0 +1,114 @@
++/*+M*************************************************************************
++ * Adaptec AIC7xxx device driver for Linux.
++ *
++ * Copyright (c) 1994 John Aycock
++ *   The University of Calgary Department of Computer Science.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING.  If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ * 
++ * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
++ *-M*************************************************************************/
++#ifndef _aic7xxx_h
++#define _aic7xxx_h
++
++#define AIC7XXX_H_VERSION  "3.2.4"
++
++#ifndef LINUX_VERSION_CODE
++#include <linux/version.h>
++#endif
++
++#ifndef KERNEL_VERSION
++#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
++#endif
++
++#if defined(__i386__)
++#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
++#else
++#  define AIC7XXX_BIOSPARAM NULL
++#endif
++
++/*
++ * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
++ * to do with card config are filled in after the card is detected.
++ */
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
++#define AIC7XXX	{						\
++	next: NULL,						\
++	module: NULL,						\
++	proc_dir: NULL,						\
++	proc_info: aic7xxx_proc_info,				\
++	name: NULL,						\
++	detect: aic7xxx_detect,					\
++	release: aic7xxx_release,				\
++	info: aic7xxx_info,					\
++	command: NULL,						\
++	queuecommand: aic7xxx_queue,				\
++	eh_strategy_handler: NULL,				\
++	eh_abort_handler: NULL,					\
++	eh_device_reset_handler: NULL,				\
++	eh_bus_reset_handler: NULL,				\
++	eh_host_reset_handler: NULL,				\
++	abort: aic7xxx_abort,					\
++	reset: aic7xxx_reset,					\
++	slave_attach: NULL,					\
++	bios_param: AIC7XXX_BIOSPARAM,				\
++	can_queue: 255,		/* max simultaneous cmds      */\
++	this_id: -1,		/* scsi id of host adapter    */\
++	sg_tablesize: 0,	/* max scatter-gather cmds    */\
++	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
++	present: 0,		/* number of 7xxx's present   */\
++	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
++	use_clustering: ENABLE_CLUSTERING,			\
++	use_new_eh_code: 0					\
++}
++#else
++#define AIC7XXX	{						\
++	next: NULL,						\
++	usage_count: NULL,					\
++	proc_dir: NULL, 					\
++	proc_info: aic7xxx_proc_info,				\
++	name: NULL,						\
++	detect: aic7xxx_detect,					\
++	release: aic7xxx_release,				\
++	info: aic7xxx_info,					\
++	command: NULL,						\
++	queuecommand: aic7xxx_queue,				\
++	abort: aic7xxx_abort,					\
++	reset: aic7xxx_reset,					\
++	slave_attach: NULL,					\
++	bios_param: AIC7XXX_BIOSPARAM,				\
++	can_queue: 255,		/* max simultaneous cmds      */\
++	this_id: -1,		/* scsi id of host adapter    */\
++	sg_tablesize: 0,	/* max scatter-gather cmds    */\
++	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
++	present: 0,		/* number of 7xxx's present   */\
++	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
++	use_clustering: ENABLE_CLUSTERING			\
++}
++#endif
++
++extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
++extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
++extern int aic7xxx_detect(Scsi_Host_Template *);
++extern int aic7xxx_command(Scsi_Cmnd *);
++extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
++extern int aic7xxx_abort(Scsi_Cmnd *);
++extern int aic7xxx_release(struct Scsi_Host *);
++
++extern const char *aic7xxx_info(struct Scsi_Host *);
++
++extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
++
++#endif /* _aic7xxx_h */
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
+--- linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx.reg	Wed May  3 20:16:44 2000
++++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Tue Feb  6 03:49:36 2001
+@@ -703,7 +703,12 @@
+ 						 * it that it can fill the
+ 						 * message buffer.
+ 						 */
+-	mask	TRACEPOINT	0xb0|SEQINT
++	mask	SEQ_SG_FIXUP	0xb0|SEQINT	/* need help with fixing up
++						 * the sg array pointer after
++						 * a phasemis with no valid
++						 * sg elements in the shadow
++						 * pipeline.
++						 */
+ 	mask	TRACEPOINT2	0xc0|SEQINT
+ 	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
+ 						 * Target changed phase on us
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
+--- linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx.seq	Mon Sep  4 13:39:20 2000
++++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Tue Feb  6 03:49:36 2001
+@@ -291,7 +291,11 @@
+ 
+ 	mov	A, LASTPHASE;
+ 
+-	test	A, ~P_DATAIN	jz p_data;
++	if ((p->features & AHC_ULTRA2) != 0) {
++		test	A, ~P_DATAIN	jz u2_p_data;
++	} else {
++		test	A, ~P_DATAIN	jz p_data;
++	}
+ 	cmp	A,P_COMMAND	je p_command;
+ 	cmp	A,P_MESGOUT	je p_mesgout;
+ 	cmp	A,P_STATUS	je p_status;
+@@ -332,133 +336,73 @@
+ 	/* clear target specific flags */
+ 	clr	SEQ_FLAGS ret;
+ 
++ 	if ((p->features & AHC_ULTRA2) != 0) {
++
++
++
++u2_data_phase_reinit:
+ /*
+  * If we re-enter the data phase after going through another phase, the
+  * STCNT may have been cleared, so restore it from the residual field.
++ * On Ultra2, we have to put it into the HCNT field because we have to
++ * drop the data down into the shadow layer via the preload ability.
+  */
+-data_phase_reinit:
+-	if ((p->features & AHC_ULTRA2) != 0) {
+ 		bmov	HADDR, SHADDR, 4;
+ 		bmov    HCNT, SCB_RESID_DCNT, 3;
+-	}
+-	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+-		bmov    STCNT, SCB_RESID_DCNT, 3;
+-	}
+-	if ((p->features & AHC_CMD_CHAN) == 0) {
+-		mvi	DINDEX, STCNT;
+-		mvi	SCB_RESID_DCNT	call bcopy_3;
+-	}
+-	jmp	data_phase_loop;
+-
+-p_data:
+-	if ((p->features & AHC_ULTRA2) != 0) {
++		jmp	u2_data_phase_loop;
++u2_p_data:
+ 		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
+-	} else {
+-		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+-	}
+-	test	LASTPHASE, IOI jnz . + 2;
+-	or	DMAPARAMS, DIRECTION;
+-	call	assert;			/*
++		test	LASTPHASE, IOI jnz . + 2;
++		or	DMAPARAMS, DIRECTION;
++		call	assert;		/*
+ 					 * Ensure entering a data
+ 					 * phase is okay - seen identify, etc.
+ 					 */
+-	if ((p->features & AHC_CMD_CHAN) != 0) {
+ 		mvi	CCSGADDR, CCSGADDR_MAX;
+-	}
+-	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+-
+-	/* We have seen a data phase */
+-	or	SEQ_FLAGS, DPHASE;
+-
+-	/*
+-	 * Initialize the DMA address and counter from the SCB.
+-	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
+-	 * modify the values in the SCB itself until we see a
+-	 * save data pointers message.
+-	 */
+-	if ((p->features & AHC_CMD_CHAN) != 0) {
++		test	SEQ_FLAGS, DPHASE	jnz u2_data_phase_reinit;
++		or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
++		/*
++		 * Initialize the DMA address and counter from the SCB.
++		 * Also set SG_COUNT and SG_NEXT in memory since we cannot
++		 * modify the values in the SCB itself until we see a
++		 * save data pointers message.
++		 */
+ 		bmov	HADDR, SCB_DATAPTR, 7;
+-		bmov    STCNT, HCNT, 3;
+ 		bmov    SG_COUNT, SCB_SGCOUNT, 5;
+-	} else {
+-		mvi	DINDEX, HADDR;
+-		mvi	SCB_DATAPTR	call bcopy_7;
+-		call	set_stcnt_from_hcnt;
+-		mvi	DINDEX, SG_COUNT;
+-		mvi	SCB_SGCOUNT	call bcopy_5;
+-	}
+-
+-data_phase_loop:
+-/* Guard against overruns */
+-	test	SG_COUNT, 0xff jnz data_phase_inbounds;
++u2_data_phase_loop:
++		/* Guard against overruns */
++		test	SG_COUNT, 0xff jnz u2_data_phase_inbounds;
+ /*
+  * Turn on 'Bit Bucket' mode, set the transfer count to
+  * 16meg and let the target run until it changes phase.
+  * When the transfer completes, notify the host that we
+  * had an overrun.
+  */
+-	or	SXFRCTL1,BITBUCKET;
+-	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
+-	if ((p->features & AHC_CMD_CHAN) != 0) {
+-		if ((p->features & AHC_ULTRA2) != 0) {
+-			bmov	HCNT, ALLONES, 3;
+-		}
+-		bmov	STCNT, ALLONES, 3;
+-	} else {
+-		mvi	STCNT[0], 0xFF;
+-		mvi	STCNT[1], 0xFF;
+-		mvi	STCNT[2], 0xFF;
+-	}
+-data_phase_inbounds:
++		or	SXFRCTL1,BITBUCKET;
++		and	DMAPARAMS, DIRECTION;
++		bmov	HCNT, ALLONES, 3;
++u2_data_phase_inbounds:
+ /* If we are the last SG block, tell the hardware. */
+-	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+-	if ((p->features & AHC_ULTRA2) == 0) {
+-		and	DMAPARAMS, ~WIDEODD;
+-	} else {
+-		mvi	SG_CACHEPTR, LAST_SEG;
+-	}
+-data_phase_wideodd:
+-	if ((p->features & AHC_ULTRA2) != 0) {
+-		mov	SINDEX, ALLONES;
+-		mov	DFCNTRL, DMAPARAMS;
+-		test	SSTAT0, SDONE jnz .;
+-data_phase_dma_loop:
+-		test	SSTAT0, SDONE jnz data_phase_dma_done;
+-		test	SSTAT1,PHASEMIS	jz data_phase_dma_loop;	/* ie. underrun */
+-data_phase_dma_phasemis:
+-		test	SSTAT0,SDONE	jnz data_phase_dma_done;
+-		clr	SINDEX;			/* Remember the phasemiss */
+-	} else {
+-		mov	DMAPARAMS  call dma;
+-	}
+-
+-data_phase_dma_done:
+-/* Go tell the host about any overruns */
+-	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+-
+-/* Exit if we had an underrun.  dma clears SINDEX in this case. */
+-	test	SINDEX,0xff	jz data_phase_finish;
+-
++		shl	A, 2, SG_COUNT;
++		cmp	SG_COUNT,0x01 jne u2_data_phase_lastseg;
++		or	A, LAST_SEG;
++u2_data_phase_lastseg:
++		mov	SG_CACHEPTR, A;
++		mov	DFCNTRL, DMAPARAMS; /* start the operation */
++		test	SXFRCTL1, BITBUCKET jnz u2_data_phase_overrun;
++u2_preload_wait:
++		test	SSTAT1, PHASEMIS jnz u2_phasemis;
++		test	DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
+ /*
+- * Advance the scatter-gather pointers if needed 
++ * Advance the scatter-gather pointers 
+  */
+-sg_advance:
+-	dec	SG_COUNT;	/* one less segment to go */
++u2_sg_advance:
++		cmp	SG_COUNT, 0x01	je u2_data_phase_finish;
+ 
+-	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
+-/*
+- * Load a struct scatter and set up the data address and length.
+- * If the working value of the SG count is nonzero, then
+- * we need to load a new set of values.
+- *
+- * This, like all DMA's, assumes little-endian host data storage.
+- */
+-sg_load:
+-	if ((p->features & AHC_CMD_CHAN) != 0) {
+ 		/*
+ 		 * Do we have any prefetch left???
+ 		 */
+-		cmp	CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
++		cmp	CCSGADDR, CCSGADDR_MAX jne u2_prefetch_avail;
+ 
+ 		/*
+ 		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
+@@ -474,48 +418,263 @@
+ 		and	CCSGCTL, ~CCSGEN;
+ 		test	CCSGCTL, CCSGEN jnz .;
+ 		mvi	CCSGCTL, CCSGRESET;
+-prefetched_segs_avail:
+-		bmov 	HADDR, CCSGRAM, 8;
+-		if ((p->features & AHC_ULTRA2) == 0) {
+-			bmov    STCNT, HCNT, 3;
++u2_prefetch_avail:
++		/* Test for a phasemis before we drop the stuff into the
++		 * host regs.  We might have actually missed the phasemis
++		 * while doing the dma of the sg segs.
++		 */
++		test	SSTAT1, PHASEMIS jnz u2_phasemis;
++		dec	SG_COUNT;	      /* one less segment to go */
++		bmov 	HADDR, CCSGRAM, 8;    /* drop the address in place */
++		clr	A;		      /* Advance the SG pointer by */
++		add	SG_NEXT[0],SG_SIZEOF; /* adding SG_SIZEOF to addr0 */
++		adc	SG_NEXT[1],A;         /* and adding any carry to */
++		jmp	u2_data_phase_loop;   /* addr1 */
++
++
++/*
++ * We've loaded all of our segments into the preload layer.  Now, we simply
++ * have to wait for it to finish or for us to get a phasemis.  And, since
++ * we'll get a phasemis if we do finish, all we really need to do is wait
++ * for a phasemis then check if we did actually complete all the segments.
++ */
++u2_data_phase_finish:
++		test	SSTAT1, PHASEMIS jnz u2_phasemis;
++		test	SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
++		clr	SG_COUNT;
++		test	SSTAT1, REQINIT	jz .;
++		test	SSTAT1, PHASEMIS jz u2_data_phase_loop;
++u2_phasemis:
++		call	ultra2_dmafinish;
++		test	SG_CACHEPTR, LAST_SEG_DONE jnz u2_phasemis_end;
++		test	SSTAT2, SHVALID jnz u2_fixup_residual;
++		mvi	INTSTAT, SEQ_SG_FIXUP;
++		jmp	u2_phasemis_end;
++u2_fixup_residual:
++		shr	ARG_1, 2, SG_CACHEPTR;
++u2_phasemis_loop:
++		and	A, 0x3f, SG_COUNT;
++		cmp	ARG_1, A je u2_phasemis_end;
++/*
++ * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
++ */
++ 		clr	A;
++		add	SG_NEXT[0], -SG_SIZEOF;
++		adc	SG_NEXT[1], 0xff;
++		inc	SG_COUNT;
++		jmp	u2_phasemis_loop;
++u2_phasemis_end:
++		bmov	SCB_RESID_DCNT, STCNT, 3;
++		mov	SCB_RESID_SGCNT, SG_COUNT;
++		or	SXFRCTL0, CLRSTCNT|CLRCHN;
++		jmp	ITloop;
++
++
++
++/*
++ * Actually turn off the DMA hardware, save our current position into the
++ * proper residual variables, wait for the next REQ signal, then jump to
++ * the ITloop.  Jumping to the ITloop ensures that if we happen to get
++ * brought into the data phase again (or are still in it after our last
++ * segment) that we will properly signal an overrun to the kernel.
++ */
++ultra2_dmafinish:
++		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
++		and	DFCNTRL, ~SCSIEN;
++		test	DFCNTRL, SCSIEN jnz .;
++		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
++			or	DFCNTRL, FIFOFLUSH;
+ 		}
+-	} else {
+-		mvi	DINDEX, HADDR;
+-		mvi	SG_NEXT	call bcopy_4;
++ultra2_dmafifoflush:
++		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
++			/*
++			 * hardware bug alert!  This needless set of jumps
++			 * works around a glitch in the silicon.  When the
++			 * PCI DMA fifo goes empty, but there is still SCSI
++			 * data to be flushed into the PCI DMA fifo (and from
++			 * there on into main memory), the FIFOEMP bit will
++			 * come on between the time when the PCI DMA buffer
++			 * went empty and the next bit of data is copied from
++			 * the SCSI fifo into the PCI fifo.  It should only
++			 * come on when both FIFOs (meaning the entire FIFO
++			 * chain) are emtpy.  Since it can take up to 4 cycles
++			 * for new data to be copied from the SCSI fifo into
++			 * the PCI fifo, testing for FIFOEMP status for 4
++			 * extra times gives the needed time for any
++			 * remaining SCSI fifo data to be put in the PCI fifo
++			 * before we declare it *truly* empty.
++			 */
++			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
++			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
++			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
++			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
++		}
++		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
++		test	DFSTATUS, MREQPEND	jnz .;
++ultra2_dmahalt:
++		and     DFCNTRL, ~(HDMAEN|SCSIEN);
++		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
++		ret;
+ 
+-		mvi	HCNT[0],SG_SIZEOF;
+-		clr	HCNT[1];
+-		clr	HCNT[2];
++u2_data_phase_overrun:
++/*
++ * Wait for the target to quit transferring data on the SCSI bus
++ */
++ 		test	SSTAT1, PHASEMIS jz .;
++		call	ultra2_dmafinish;
++/*
++ * Turn off BITBUCKET mode and notify the host
++ */
++		and	SXFRCTL1, ~BITBUCKET;
++		mvi	INTSTAT,DATA_OVERRUN;
++		jmp	ITloop;
++
++
++
++	} else {  /* NOT Ultra2 */
+ 
+-		or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+ 
+-		call	dma_finish;
+ 
++data_phase_reinit:
++/*
++ * If we re-enter the data phase after going through another phase, the
++ * STCNT may have been cleared, so restore it from the residual field.
++ */
++		if ((p->features & AHC_CMD_CHAN) != 0) {
++			bmov    STCNT, SCB_RESID_DCNT, 3;
++		} else {
++			mvi	DINDEX, STCNT;
++			mvi	SCB_RESID_DCNT	call bcopy_3;
++		}
++		jmp	data_phase_loop;
++p_data:
++		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
++		test	LASTPHASE, IOI jnz . + 2;
++		or	DMAPARAMS, DIRECTION;
++		call	assert;		/*
++					 * Ensure entering a data
++					 * phase is okay - seen identify, etc.
++					 */
++		if ((p->features & AHC_CMD_CHAN) != 0) {
++			mvi	CCSGADDR, CCSGADDR_MAX;
++		}
++		test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
++		or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
+ 		/*
+-		 * Copy data from FIFO into SCB data pointer and data count.
+-		 * This assumes that the SG segments are of the form:
+-		 * struct ahc_dma_seg {
+-		 *	u_int32_t	addr;	four bytes, little-endian order
+-		 *	u_int32_t	len;	four bytes, little endian order
+-		 * };
++		 * Initialize the DMA address and counter from the SCB.
++		 * Also set SG_COUNT and SG_NEXT in memory since we cannot
++		 * modify the values in the SCB itself until we see a
++		 * save data pointers message.
+ 		 */
+-		mvi	HADDR	call dfdat_in_7;
+-		call	set_stcnt_from_hcnt;
+-	}
++		if ((p->features & AHC_CMD_CHAN) != 0) {
++			bmov	HADDR, SCB_DATAPTR, 7;
++			bmov    STCNT, HCNT, 3;
++			bmov    SG_COUNT, SCB_SGCOUNT, 5;
++		} else {
++			mvi	DINDEX, HADDR;
++			mvi	SCB_DATAPTR	call bcopy_7;
++			call	set_stcnt_from_hcnt;
++			mvi	DINDEX, SG_COUNT;
++			mvi	SCB_SGCOUNT	call bcopy_5;
++		}
++data_phase_loop:
++		/* Guard against overruns */
++		test	SG_COUNT, 0xff jnz data_phase_inbounds;
++/*
++ * Turn on 'Bit Bucket' mode, set the transfer count to
++ * 16meg and let the target run until it changes phase.
++ * When the transfer completes, notify the host that we
++ * had an overrun.
++ */
++		or	SXFRCTL1,BITBUCKET;
++		and	DMAPARAMS, ~(HDMAEN|SDMAEN);
++		if ((p->features & AHC_CMD_CHAN) != 0) {
++			bmov	STCNT, ALLONES, 3;
++		} else {
++			mvi	STCNT[0], 0xFF;
++			mvi	STCNT[1], 0xFF;
++			mvi	STCNT[2], 0xFF;
++		}
+ 
+-/* Advance the SG pointer */
+-	clr	A;			/* add sizeof(struct scatter) */
+-	add	SG_NEXT[0],SG_SIZEOF;
+-	adc	SG_NEXT[1],A;
++data_phase_inbounds:
++/* If we are the last SG block, tell the hardware. */
++		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
++		and	DMAPARAMS, ~WIDEODD;
++data_phase_wideodd:
++		mov	DMAPARAMS  call dma;
++data_phase_dma_done:
++/* Go tell the host about any overruns */
++		test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
++
++/* Exit if we had an underrun.  dma clears SINDEX in this case. */
++		test	SINDEX,0xff	jz data_phase_finish;
++/*
++ * Advance the scatter-gather pointers if needed 
++ */
++sg_advance:
++		cmp	SG_COUNT, 0x01	je data_phase_finish; /* Are we done? */
++		dec	SG_COUNT;	/* one less segment to go */
++/*
++ * Load a struct scatter and set up the data address and length.
++ * If the working value of the SG count is nonzero, then
++ * we need to load a new set of values.
++ *
++ * This, like all DMA's, assumes little-endian host data storage.
++ */
++sg_load:
++		if ((p->features & AHC_CMD_CHAN) != 0) {
++			/*
++			 * Do we have any prefetch left???
++			 */
++			cmp	CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
++
++			/*
++			 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
++			 */
++			add	A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
++			mvi	A, CCSGADDR_MAX;
++			jc	. + 2;
++			shl	A, 3, SG_COUNT;
++			mov	CCHCNT, A;
++			bmov	CCHADDR, SG_NEXT, 4;
++			mvi	CCSGCTL, CCSGEN|CCSGRESET;
++			test	CCSGCTL, CCSGDONE jz .;
++			and	CCSGCTL, ~CCSGEN;
++			test	CCSGCTL, CCSGEN jnz .;
++			mvi	CCSGCTL, CCSGRESET;
++prefetch_avail:
++			bmov 	HADDR, CCSGRAM, 8;
++			bmov    STCNT, HCNT, 3;
++		} else {
++			mvi	DINDEX, HADDR;
++			mvi	SG_NEXT	call bcopy_4;
+ 
+-	test    SSTAT1, REQINIT jz .;
+-	test	SSTAT1,PHASEMIS	jz data_phase_loop;
++			mvi	HCNT[0],SG_SIZEOF;
++			clr	HCNT[1];
++			clr	HCNT[2];
+ 
+-/* This drops the last SG segment down to the shadow layer for us */
+-	if ((p->features & AHC_ULTRA2) != 0) {
+-		mov	DFCNTRL, DMAPARAMS;
+-		test	SSTAT0, SDONE	jnz .;
+-	}
++			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
++
++			call	dma_finish;
++
++/*
++ * Copy data from FIFO into SCB data pointer and data count.
++ * This assumes that the SG segments are of the form:
++ * struct ahc_dma_seg {
++ *	u_int32_t	addr;	four bytes, little-endian order
++ *	u_int32_t	len;	four bytes, little endian order
++ * };
++ */
++			mvi	HADDR	call dfdat_in_7;
++			call	set_stcnt_from_hcnt;
++		}
++/* Advance the SG pointer */
++		clr	A;		/* add sizeof(struct scatter) */
++		add	SG_NEXT[0],SG_SIZEOF;
++		adc	SG_NEXT[1],A;
++
++		test    SSTAT1, REQINIT jz .;
++		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+ 
+ data_phase_finish:
+ /*
+@@ -523,10 +682,7 @@
+  * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+  * were transferred on the SCSI (as opposed to the host) bus.
+  */
+-	if ((p->features & AHC_ULTRA2) != 0) {
+-		call	ultra2_dmafinish;
+-	}
+-	if ((p->features & AHC_ULTRA2) == 0) {
++		clr	SG_COUNT;
+ 		if ((p->features & AHC_CMD_CHAN) != 0) {
+ 			bmov    SCB_RESID_DCNT, STCNT, 3;
+ 			mov	SCB_RESID_SGCNT, SG_COUNT;
+@@ -536,52 +692,19 @@
+ 			mov	SCB_RESID_DCNT[2],STCNT[2];
+ 			mov	SCB_RESID_SGCNT, SG_COUNT;
+ 		}
+-	}
+ 
+-	jmp	ITloop;
++		jmp	ITloop;
+ 
+ data_phase_overrun:
+-	if ((p->features & AHC_ULTRA2) != 0) {
+-		call	ultra2_dmafinish;
+-	}
+ /*
+  * Turn off BITBUCKET mode and notify the host
+  */
+-	and	SXFRCTL1, ~BITBUCKET;
+-	mvi	INTSTAT,DATA_OVERRUN;
+-	jmp	ITloop;
++		and	SXFRCTL1, ~BITBUCKET;
++		mvi	INTSTAT,DATA_OVERRUN;
++		jmp	ITloop;
++
++
+ 
+-ultra2_dmafinish:
+-	if ((p->features & AHC_ULTRA2) != 0) {
+-		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
+-		and	DFCNTRL, ~SCSIEN;
+-		test	DFCNTRL, SCSIEN jnz .;
+-ultra2_dmafifoflush:
+-		or	DFCNTRL, FIFOFLUSH;
+-		test	DFSTATUS, FIFOEMP jz . - 1;
+-		/*
+-		 * hardware bug alert!  This needless set of jumps is to
+-		 * protect against a FIFOEMP status bit glitch in the
+-		 * silicon.
+-		 */
+-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+-		test	DFSTATUS, MREQPEND	jnz .;
+-ultra2_dmahalt:
+-		test	SCSIOFFSET, 0x7f	jnz ultra2_shutdown;
+-ultra2_await_nreq:
+-		test	SCSISIGI, REQI	jz ultra2_shutdown;
+-		test	SSTAT1, (PHASEMIS|REQINIT)	jz ultra2_await_nreq;
+-ultra2_shutdown:
+-		and     DFCNTRL, ~(HDMAEN|SCSIEN);
+-		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
+-		bmov	SCB_RESID_DCNT, STCNT, 3;
+-		mov	SCB_RESID_SGCNT, SG_COUNT;
+-		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+-		ret;
+ 	}
+ 
+ /*
+@@ -1021,6 +1144,7 @@
+ inb_last:
+ 	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
+ 
++	
+ mesgin_phasemis:
+ /*
+  * We expected to receive another byte, but the target changed phase
+@@ -1080,7 +1204,9 @@
+ 	 * to drain the data fifo until there is space for the input
+ 	 * latch to drain and HDMAEN de-asserts.
+ 	 */
+-	mov	NONE, DFDAT;
++	if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
++		mov	NONE, DFDAT;
++	}
+ 	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+ }
+ return:
+@@ -1306,11 +1432,17 @@
+ 		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
+ 		jmp	dma_scb_finish;
+ dma_scb_tohost:
+-		if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
++		if ((p->features & AHC_ULTRA2) == 0) {
+ 			mvi	CCSCBCTL, CCSCBRESET;
+ 			bmov	CCSCBRAM, SCB_CONTROL, 32;
+ 			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+ 			test	CCSCBCTL, CCSCBDONE jz .;
++		} else if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
++                        mvi     CCSCBCTL, CCARREN|CCSCBRESET;
++			cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
++                        mvi     CCHCNT, 32;
++			mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
++			cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+ 		} else {
+ 			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+ 			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+@@ -1342,17 +1474,81 @@
+ 		mov	DFDAT,SINDIR;
+ 		cmp	SINDEX, A jne copy_scb_tofifo_loop;
+ 		or	DFCNTRL, HDMAEN|FIFOFLUSH;
++		jmp	dma_finish;
+ dma_scb_fromhost:
+-		call	dma_finish;
+-		/* If we were putting the SCB, we are done */
+-		test	DMAPARAMS, DIRECTION	jz	return;
+-		mvi	SCB_CONTROL  call dfdat_in_7;
+-		call	dfdat_in_7_continued;
+-		call	dfdat_in_7_continued;
+-		jmp	dfdat_in_7_continued;
++		mvi	DINDEX, SCB_CONTROL;
++		if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
++			/*
++			 * Set the A to -24.  It it hits 0, then we let
++			 * our code fall through to dfdat_in_8 to complete
++			 * the last of the copy.
++			 *
++			 * Also, things happen 8 bytes at a time in this
++			 * case, so we may need to drain the fifo at most
++			 * 3 times to keep things flowing
++			 */
++			mvi	A, -24;
++dma_scb_hang_fifo:
++			/* Wait for the first bit of data to hit the fifo */
++			test	DFSTATUS, FIFOEMP jnz .;
++dma_scb_hang_wait:
++			/* OK, now they've started to transfer into the fifo,
++			 * so wait for them to stop trying to transfer any
++			 * more data.
++			 */
++			test	DFSTATUS, MREQPEND jnz .;
++			/*
++			 * OK, they started, then they stopped, now see if they
++			 * managed to complete the job before stopping.  Try
++			 * it multiple times to give the chip a few cycles to
++			 * set the flag if it did complete.
++			 */
++			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
++			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
++			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
++			/*
++			 * Too bad, the chip didn't complete the DMA, but there
++			 * aren't any more memory requests pending, so that
++			 * means it stopped part way through and hung.  That's
++			 * our bug, so now we drain what data there is in the
++			 * fifo in order to get things going again.
++			 */
++dma_scb_hang_empty_fifo:
++			call	dfdat_in_8;
++			add	A, 8;
++			add	SINDEX, A, HCNT;
++			/*
++			 * If there are another 8 bytes of data waiting in the
++			 * fifo, then the carry bit will be set as a result
++			 * of the above add command (unless A is non-negative,
++			 * in which case the carry bit won't be set).
++			 */
++			jc	dma_scb_hang_empty_fifo;
++			/*
++			 * We've emptied the fifo now, but we wouldn't have got
++			 * here if the memory transfer hadn't stopped part way
++			 * through, so go back up to the beginning of the
++			 * loop and start over.  When it succeeds in getting
++			 * all the data down, HDONE will be set and we'll
++			 * jump to the code just below here.
++			 */
++			jmp	dma_scb_hang_fifo;
++dma_scb_hang_dma_done:
++			and	DFCNTRL, ~HDMAEN;
++			test	DFCNTRL, HDMAEN jnz .;
++			call	dfdat_in_8;
++			add	A, 8;
++			cmp	A, 8 jne . - 2;
++			ret;
++		} else {
++			call	dma_finish;
++			call	dfdat_in_8;
++			call	dfdat_in_8;
++			call	dfdat_in_8;
++		}
++dfdat_in_8:
++		mov	DINDIR,DFDAT;
+ dfdat_in_7:
+-		mov     DINDEX,SINDEX;
+-dfdat_in_7_continued:
+ 		mov	DINDIR,DFDAT;
+ 		mov	DINDIR,DFDAT;
+ 		mov	DINDIR,DFDAT;
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c
+--- linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx_proc.c	Wed Dec 31 19:00:00 1969
++++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c	Tue Feb  6 03:49:36 2001
+@@ -0,0 +1,414 @@
++/*+M*************************************************************************
++ * Adaptec AIC7xxx device driver proc support for Linux.
++ *
++ * Copyright (c) 1995, 1996 Dean W. Gehnert
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; see the file COPYING.  If not, write to
++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * ----------------------------------------------------------------
++ *  o Modified from the EATA-DMA /proc support.
++ *  o Additional support for device block statistics provided by
++ *    Matthew Jacob.
++ *  o Correction of overflow by Heinz Mauelshagen
++ *  o Adittional corrections by Doug Ledford
++ *
++ *  Dean W. Gehnert, deang@teleport.com, 05/01/96
++ *
++ *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
++ *-M*************************************************************************/
++
++#include <linux/config.h>
++
++#define	BLS	(&aic7xxx_buffer[size])
++#define HDRB \
++"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
++
++#ifdef PROC_DEBUG
++extern int vsprintf(char *, const char *, va_list);
++
++static void
++proc_debug(const char *fmt, ...)
++{
++  va_list ap;
++  char buf[256];
++
++  va_start(ap, fmt);
++  vsprintf(buf, fmt, ap);
++  printk(buf);
++  va_end(ap);
++}
++#else /* PROC_DEBUG */
++#  define proc_debug(fmt, args...)
++#endif /* PROC_DEBUG */
++
++static int aic7xxx_buffer_size = 0;
++static char *aic7xxx_buffer = NULL;
++
++
++/*+F*************************************************************************
++ * Function:
++ *   aic7xxx_set_info
++ *
++ * Description:
++ *   Set parameters for the driver from the /proc filesystem.
++ *-F*************************************************************************/
++int
++aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
++{
++  proc_debug("aic7xxx_set_info(): %s\n", buffer);
++  return (-ENOSYS);  /* Currently this is a no-op */
++}
++
++
++/*+F*************************************************************************
++ * Function:
++ *   aic7xxx_proc_info
++ *
++ * Description:
++ *   Return information to handle /proc support for the driver.
++ *-F*************************************************************************/
++int
++aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
++                    int hostno, int inout)
++{
++  struct Scsi_Host *HBAptr;
++  struct aic7xxx_host *p;
++  int    size = 0;
++  unsigned char i;
++  struct aic7xxx_xferstats *sp;
++  unsigned char target;
++
++  HBAptr = NULL;
++
++  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
++    ;
++
++  if (!p)
++  {
++    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
++    if (size > length)
++    {
++      return (size);
++    }
++    else
++    {
++      return (length);
++    }
++  }
++
++  HBAptr = p->host;
++
++  if (inout == TRUE) /* Has data been written to the file? */ 
++  {
++    return (aic7xxx_set_info(buffer, length, HBAptr));
++  }
++
++  p = (struct aic7xxx_host *) HBAptr->hostdata;
++
++  /*
++   * It takes roughly 1K of space to hold all relevant card info, not
++   * counting any proc stats, so we start out with a 1.5k buffer size and
++   * if proc_stats is defined, then we sweep the stats structure to see
++   * how many drives we will be printing out for and add 384 bytes per
++   * device with active stats.
++   *
++   * Hmmmm...that 1.5k seems to keep growing as items get added so they
++   * can be easily viewed for debugging purposes.  So, we bumped that
++   * 1.5k to 4k so we can quit having to bump it all the time.
++   */
++
++  size = 4096;
++  for (target = 0; target < MAX_TARGETS; target++)
++  {
++    if (p->dev_flags[target] & DEVICE_PRESENT)
++#ifdef AIC7XXX_PROC_STATS
++      size += 512;
++#else
++      size += 256;
++#endif
++  }
++  if (aic7xxx_buffer_size != size)
++  {
++    if (aic7xxx_buffer != NULL) 
++    {
++      kfree(aic7xxx_buffer);
++      aic7xxx_buffer_size = 0;
++    }
++    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
++  }
++  if (aic7xxx_buffer == NULL)
++  {
++    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
++        __LINE__);
++    return size;
++  }
++  aic7xxx_buffer_size = size;
++
++  size = 0;
++  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
++  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
++  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
++  size += sprintf(BLS, "\n");
++  size += sprintf(BLS, "Compile Options:\n");
++#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
++  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
++#else
++  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
++#endif
++#ifdef AIC7XXX_PROC_STATS
++  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
++#else
++  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
++#endif
++  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
++  size += sprintf(BLS, "\n");
++  size += sprintf(BLS, "Adapter Configuration:\n");
++  size += sprintf(BLS, "           SCSI Adapter: %s\n",
++      board_names[p->board_name_index]);
++  if (p->flags & AHC_TWIN)
++    size += sprintf(BLS, "                         Twin Channel Controller ");
++  else
++  {
++    char *channel = "";
++    char *ultra = "";
++    char *wide = "Narrow ";
++    if (p->flags & AHC_MULTI_CHANNEL)
++    {
++      channel = " Channel A";
++      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
++        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
++    }
++    if (p->features & AHC_WIDE)
++      wide = "Wide ";
++    if (p->features & AHC_ULTRA3)
++    {
++      switch(p->chip & AHC_CHIPID_MASK)
++      {
++        case AHC_AIC7892:
++        case AHC_AIC7899:
++          ultra = "Ultra-160/m LVD/SE ";
++          break;
++        default:
++          ultra = "Ultra-3 LVD/SE ";
++          break;
++      }
++    }
++    else if (p->features & AHC_ULTRA2)
++      ultra = "Ultra-2 LVD/SE ";
++    else if (p->features & AHC_ULTRA)
++      ultra = "Ultra ";
++    size += sprintf(BLS, "                           %s%sController%s ",
++      ultra, wide, channel);
++  }
++  switch(p->chip & ~AHC_CHIPID_MASK)
++  {
++    case AHC_VL:
++      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
++      break;
++    case AHC_EISA:
++      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
++      break;
++    default:
++      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
++        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
++      break;
++  }
++  if( !(p->maddr) )
++  {
++    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
++  }
++  else
++  {
++    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
++  }
++  if( (p->chip & (AHC_VL | AHC_EISA)) )
++  {
++    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
++  }
++  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
++          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
++         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
++           "SEEPROM not found, using leftover BIOS values.") );
++  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
++          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
++  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
++  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
++            p->activescbs, p->max_activescbs);
++  size += sprintf(BLS, "                         Allocated %d, HW %d, "
++            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
++            p->scb_data->maxscbs);
++  if (p->flags & AHC_EXTERNAL_SRAM)
++    size += sprintf(BLS, "                         Using External SCB SRAM\n");
++  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
++  if (p->chip & AHC_EISA)
++  {
++    size += sprintf(BLS, " %s\n",
++        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
++  }
++  else
++  {
++    size += sprintf(BLS, "\n");
++  }
++  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
++            p->bios_control);
++  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
++            p->adapter_control);
++  size += sprintf(BLS, "   Extended Translation: %sabled\n",
++      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
++  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
++  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
++  {
++    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
++  }
++  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
++  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
++  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
++  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
++                       "instance %d:\n", p->instance);
++  size += sprintf(BLS, "      {");
++  for(i=0; i < (MAX_TARGETS - 1); i++)
++    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
++  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
++  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
++                       "instance %d:\n", p->instance);
++  size += sprintf(BLS, "      {");
++  for(i=0; i < (MAX_TARGETS - 1); i++)
++    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
++  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
++
++  size += sprintf(BLS, "\n");
++  size += sprintf(BLS, "Statistics:\n\n");
++  for (target = 0; target < MAX_TARGETS; target++)
++  {
++    sp = &p->stats[target];
++    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
++    {
++      continue;
++    }
++    if (p->features & AHC_TWIN)
++    {
++      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
++          p->host_no, (target >> 3), (target & 0x7), 0);
++    }
++    else
++    {
++      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
++          p->host_no, 0, target, 0);
++    }
++    size += sprintf(BLS, "  Device using %s/%s",
++          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
++          "Wide" : "Narrow",
++          (p->transinfo[target].cur_offset != 0) ?
++          "Sync transfers at " : "Async transfers.\n" );
++    if (p->transinfo[target].cur_offset != 0)
++    {
++      struct aic7xxx_syncrate *sync_rate;
++      unsigned char options = p->transinfo[target].cur_options;
++      int period = p->transinfo[target].cur_period;
++      int rate = (p->transinfo[target].cur_width ==
++                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
++
++      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
++      if (sync_rate != NULL)
++      {
++        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
++                        sync_rate->rate[rate],
++                        p->transinfo[target].cur_offset );
++      }
++      else
++      {
++        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
++                        p->transinfo[target].cur_offset );
++      }
++    }
++    size += sprintf(BLS, "  Transinfo settings: ");
++    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
++                    p->transinfo[target].cur_period,
++                    p->transinfo[target].cur_offset,
++                    p->transinfo[target].cur_width,
++                    p->transinfo[target].cur_options);
++    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
++                    p->transinfo[target].goal_period,
++                    p->transinfo[target].goal_offset,
++                    p->transinfo[target].goal_width,
++                    p->transinfo[target].goal_options);
++    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
++                    p->transinfo[target].user_period,
++                    p->transinfo[target].user_offset,
++                    p->transinfo[target].user_width,
++                    p->transinfo[target].user_options);
++#ifdef AIC7XXX_PROC_STATS
++    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
++        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
++    size += sprintf(BLS, "%s\n", HDRB);
++    size += sprintf(BLS, "   Reads:");
++    for (i = 0; i < NUMBER(sp->r_bins); i++)
++    {
++      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
++    }
++    size += sprintf(BLS, "\n");
++    size += sprintf(BLS, "  Writes:");
++    for (i = 0; i < NUMBER(sp->w_bins); i++)
++    {
++      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
++    }
++    size += sprintf(BLS, "\n");
++#else
++    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
++        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
++#endif /* AIC7XXX_PROC_STATS */
++    size += sprintf(BLS, "\n\n");
++  }
++
++  if (size >= aic7xxx_buffer_size)
++  {
++    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
++  }
++
++  if (offset > size - 1)
++  {
++    kfree(aic7xxx_buffer);
++    aic7xxx_buffer = NULL;
++    aic7xxx_buffer_size = length = 0;
++    *start = NULL;
++  }
++  else
++  {
++    *start = buffer;
++    length = MIN(length, size - offset);
++    memcpy(buffer, &aic7xxx_buffer[offset], length);
++  }
++
++  return (length);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-indent-level: 2
++ * c-brace-imaginary-offset: 0
++ * c-brace-offset: -2
++ * c-argdecl-indent: 2
++ * c-label-offset: -2
++ * c-continued-statement-offset: 2
++ * c-continued-brace-offset: 0
++ * indent-tabs-mode: nil
++ * tab-width: 8
++ * End:
++ */
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h
+--- linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx_reg.h	Wed Dec 31 19:00:00 1969
++++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h	Tue Feb  6 03:49:36 2001
+@@ -0,0 +1,629 @@
++/*
++  * DO NOT EDIT - This file is automatically generated.
++  */
++
++#define	SCSISEQ         		0x00
++#define		TEMODE          	0x80
++#define		ENSELO          	0x40
++#define		ENSELI          	0x20
++#define		ENRSELI         	0x10
++#define		ENAUTOATNO      	0x08
++#define		ENAUTOATNI      	0x04
++#define		ENAUTOATNP      	0x02
++#define		SCSIRSTO        	0x01
++
++#define	SXFRCTL0        		0x01
++#define		DFON            	0x80
++#define		DFPEXP          	0x40
++#define		FAST20          	0x20
++#define		CLRSTCNT        	0x10
++#define		SPIOEN          	0x08
++#define		SCAMEN          	0x04
++#define		CLRCHN          	0x02
++
++#define	SXFRCTL1        		0x02
++#define		BITBUCKET       	0x80
++#define		SWRAPEN         	0x40
++#define		ENSPCHK         	0x20
++#define		STIMESEL        	0x18
++#define		ENSTIMER        	0x04
++#define		ACTNEGEN        	0x02
++#define		STPWEN          	0x01
++
++#define	SCSISIGO        		0x03
++#define		CDO             	0x80
++#define		IOO             	0x40
++#define		MSGO            	0x20
++#define		ATNO            	0x10
++#define		SELO            	0x08
++#define		BSYO            	0x04
++#define		REQO            	0x02
++#define		ACKO            	0x01
++
++#define	SCSISIGI        		0x03
++#define		ATNI            	0x10
++#define		SELI            	0x08
++#define		BSYI            	0x04
++#define		REQI            	0x02
++#define		ACKI            	0x01
++
++#define	SCSIRATE        		0x04
++#define		WIDEXFER        	0x80
++#define		SXFR_ULTRA2     	0x7f
++#define		SXFR            	0x70
++#define		SOFS            	0x0f
++
++#define	SCSIID          		0x05
++#define	SCSIOFFSET      		0x05
++#define		SOFS_ULTRA2     	0x7f
++
++#define	SCSIDATL        		0x06
++
++#define	SCSIDATH        		0x07
++
++#define	STCNT           		0x08
++
++#define	OPTIONMODE      		0x08
++#define		AUTORATEEN      	0x80
++#define		AUTOACKEN       	0x40
++#define		ATNMGMNTEN      	0x20
++#define		BUSFREEREV      	0x10
++#define		EXPPHASEDIS     	0x08
++#define		SCSIDATL_IMGEN  	0x04
++#define		AUTO_MSGOUT_DE  	0x02
++#define		DIS_MSGIN_DUALEDGE	0x01
++
++#define	CLRSINT0        		0x0b
++#define		CLRSELDO        	0x40
++#define		CLRSELDI        	0x20
++#define		CLRSELINGO      	0x10
++#define		CLRSWRAP        	0x08
++#define		CLRSPIORDY      	0x02
++
++#define	SSTAT0          		0x0b
++#define		TARGET          	0x80
++#define		SELDO           	0x40
++#define		SELDI           	0x20
++#define		SELINGO         	0x10
++#define		IOERR           	0x08
++#define		SWRAP           	0x08
++#define		SDONE           	0x04
++#define		SPIORDY         	0x02
++#define		DMADONE         	0x01
++
++#define	CLRSINT1        		0x0c
++#define		CLRSELTIMEO     	0x80
++#define		CLRATNO         	0x40
++#define		CLRSCSIRSTI     	0x20
++#define		CLRBUSFREE      	0x08
++#define		CLRSCSIPERR     	0x04
++#define		CLRPHASECHG     	0x02
++#define		CLRREQINIT      	0x01
++
++#define	SSTAT1          		0x0c
++#define		SELTO           	0x80
++#define		ATNTARG         	0x40
++#define		SCSIRSTI        	0x20
++#define		PHASEMIS        	0x10
++#define		BUSFREE         	0x08
++#define		SCSIPERR        	0x04
++#define		PHASECHG        	0x02
++#define		REQINIT         	0x01
++
++#define	SSTAT2          		0x0d
++#define		OVERRUN         	0x80
++#define		SHVALID         	0x40
++#define		WIDE_RES        	0x20
++#define		SFCNT           	0x1f
++#define		EXP_ACTIVE      	0x10
++#define		CRCVALERR       	0x08
++#define		CRCENDERR       	0x04
++#define		CRCREQERR       	0x02
++#define		DUAL_EDGE_ERROR 	0x01
++
++#define	SSTAT3          		0x0e
++#define		SCSICNT         	0xf0
++#define		OFFCNT          	0x0f
++
++#define	SCSIID_ULTRA2   		0x0f
++#define		OID             	0x0f
++
++#define	SIMODE0         		0x10
++#define		ENSELDO         	0x40
++#define		ENSELDI         	0x20
++#define		ENSELINGO       	0x10
++#define		ENIOERR         	0x08
++#define		ENSWRAP         	0x08
++#define		ENSDONE         	0x04
++#define		ENSPIORDY       	0x02
++#define		ENDMADONE       	0x01
++
++#define	SIMODE1         		0x11
++#define		ENSELTIMO       	0x80
++#define		ENATNTARG       	0x40
++#define		ENSCSIRST       	0x20
++#define		ENPHASEMIS      	0x10
++#define		ENBUSFREE       	0x08
++#define		ENSCSIPERR      	0x04
++#define		ENPHASECHG      	0x02
++#define		ENREQINIT       	0x01
++
++#define	SCSIBUSL        		0x12
++
++#define	SCSIBUSH        		0x13
++
++#define	SHADDR          		0x14
++
++#define	SELTIMER        		0x18
++#define		STAGE6          	0x20
++#define		STAGE5          	0x10
++#define		STAGE4          	0x08
++#define		STAGE3          	0x04
++#define		STAGE2          	0x02
++#define		STAGE1          	0x01
++
++#define	SELID           		0x19
++#define		SELID_MASK      	0xf0
++#define		ONEBIT          	0x08
++
++#define	SPIOCAP         		0x1b
++#define		SOFT1           	0x80
++#define		SOFT0           	0x40
++#define		SOFTCMDEN       	0x20
++#define		HAS_BRDCTL      	0x10
++#define		SEEPROM         	0x08
++#define		EEPROM          	0x04
++#define		ROM             	0x02
++#define		SSPIOCPS        	0x01
++
++#define	BRDCTL          		0x1d
++#define		BRDDAT7         	0x80
++#define		BRDDAT6         	0x40
++#define		BRDDAT5         	0x20
++#define		BRDDAT4         	0x10
++#define		BRDSTB          	0x10
++#define		BRDCS           	0x08
++#define		BRDDAT3         	0x08
++#define		BRDDAT2         	0x04
++#define		BRDRW           	0x04
++#define		BRDRW_ULTRA2    	0x02
++#define		BRDCTL1         	0x02
++#define		BRDSTB_ULTRA2   	0x01
++#define		BRDCTL0         	0x01
++
++#define	SEECTL          		0x1e
++#define		EXTARBACK       	0x80
++#define		EXTARBREQ       	0x40
++#define		SEEMS           	0x20
++#define		SEERDY          	0x10
++#define		SEECS           	0x08
++#define		SEECK           	0x04
++#define		SEEDO           	0x02
++#define		SEEDI           	0x01
++
++#define	SBLKCTL         		0x1f
++#define		DIAGLEDEN       	0x80
++#define		DIAGLEDON       	0x40
++#define		AUTOFLUSHDIS    	0x20
++#define		ENAB40          	0x08
++#define		ENAB20          	0x04
++#define		SELWIDE         	0x02
++#define		XCVR            	0x01
++
++#define	SRAM_BASE       		0x20
++
++#define	TARG_SCSIRATE   		0x20
++
++#define	ULTRA_ENB       		0x30
++
++#define	DISC_DSB        		0x32
++
++#define	MSG_OUT         		0x34
++
++#define	DMAPARAMS       		0x35
++#define		PRELOADEN       	0x80
++#define		WIDEODD         	0x40
++#define		SCSIEN          	0x20
++#define		SDMAENACK       	0x10
++#define		SDMAEN          	0x10
++#define		HDMAEN          	0x08
++#define		HDMAENACK       	0x08
++#define		DIRECTION       	0x04
++#define		FIFOFLUSH       	0x02
++#define		FIFORESET       	0x01
++
++#define	SEQ_FLAGS       		0x36
++#define		IDENTIFY_SEEN   	0x80
++#define		SCBPTR_VALID    	0x20
++#define		DPHASE          	0x10
++#define		AMTARGET        	0x08
++#define		WIDE_BUS        	0x02
++#define		TWIN_BUS        	0x01
++
++#define	SAVED_TCL       		0x37
++
++#define	SG_COUNT        		0x38
++
++#define	SG_NEXT         		0x39
++
++#define	LASTPHASE       		0x3d
++#define		P_MESGIN        	0xe0
++#define		PHASE_MASK      	0xe0
++#define		P_STATUS        	0xc0
++#define		P_MESGOUT       	0xa0
++#define		P_COMMAND       	0x80
++#define		CDI             	0x80
++#define		IOI             	0x40
++#define		P_DATAIN        	0x40
++#define		MSGI            	0x20
++#define		P_BUSFREE       	0x01
++#define		P_DATAOUT       	0x00
++
++#define	WAITING_SCBH    		0x3e
++
++#define	DISCONNECTED_SCBH		0x3f
++
++#define	FREE_SCBH       		0x40
++
++#define	HSCB_ADDR       		0x41
++
++#define	SCBID_ADDR      		0x45
++
++#define	TMODE_CMDADDR   		0x49
++
++#define	KERNEL_QINPOS   		0x4d
++
++#define	QINPOS          		0x4e
++
++#define	QOUTPOS         		0x4f
++
++#define	TMODE_CMDADDR_NEXT		0x50
++
++#define	ARG_1           		0x51
++#define	RETURN_1        		0x51
++#define		SEND_MSG        	0x80
++#define		SEND_SENSE      	0x40
++#define		SEND_REJ        	0x20
++#define		MSGOUT_PHASEMIS 	0x10
++
++#define	ARG_2           		0x52
++#define	RETURN_2        		0x52
++
++#define	LAST_MSG        		0x53
++
++#define	PREFETCH_CNT    		0x54
++
++#define	SCSICONF        		0x5a
++#define		TERM_ENB        	0x80
++#define		RESET_SCSI      	0x40
++#define		HWSCSIID        	0x0f
++#define		HSCSIID         	0x07
++
++#define	HOSTCONF        		0x5d
++
++#define	HA_274_BIOSCTRL 		0x5f
++#define		BIOSMODE        	0x30
++#define		BIOSDISABLED    	0x30
++#define		CHANNEL_B_PRIMARY	0x08
++
++#define	SEQCTL          		0x60
++#define		PERRORDIS       	0x80
++#define		PAUSEDIS        	0x40
++#define		FAILDIS         	0x20
++#define		FASTMODE        	0x10
++#define		BRKADRINTEN     	0x08
++#define		STEP            	0x04
++#define		SEQRESET        	0x02
++#define		LOADRAM         	0x01
++
++#define	SEQRAM          		0x61
++
++#define	SEQADDR0        		0x62
++
++#define	SEQADDR1        		0x63
++#define		SEQADDR1_MASK   	0x01
++
++#define	ACCUM           		0x64
++
++#define	SINDEX          		0x65
++
++#define	DINDEX          		0x66
++
++#define	ALLONES         		0x69
++
++#define	ALLZEROS        		0x6a
++
++#define	NONE            		0x6a
++
++#define	FLAGS           		0x6b
++#define		ZERO            	0x02
++#define		CARRY           	0x01
++
++#define	SINDIR          		0x6c
++
++#define	DINDIR          		0x6d
++
++#define	FUNCTION1       		0x6e
++
++#define	STACK           		0x6f
++
++#define	TARG_OFFSET     		0x70
++
++#define	BCTL            		0x84
++#define		ACE             	0x08
++#define		ENABLE          	0x01
++
++#define	DSCOMMAND0      		0x84
++#define		INTSCBRAMSEL    	0x08
++#define		RAMPS           	0x04
++#define		USCBSIZE32      	0x02
++#define		CIOPARCKEN      	0x01
++
++#define	DSCOMMAND       		0x84
++#define		CACHETHEN       	0x80
++#define		DPARCKEN        	0x40
++#define		MPARCKEN        	0x20
++#define		EXTREQLCK       	0x10
++
++#define	BUSTIME         		0x85
++#define		BOFF            	0xf0
++#define		BON             	0x0f
++
++#define	BUSSPD          		0x86
++#define		DFTHRSH         	0xc0
++#define		STBOFF          	0x38
++#define		STBON           	0x07
++
++#define	DSPCISTATUS     		0x86
++#define		DFTHRSH_100     	0xc0
++
++#define	HCNTRL          		0x87
++#define		POWRDN          	0x40
++#define		SWINT           	0x10
++#define		IRQMS           	0x08
++#define		PAUSE           	0x04
++#define		INTEN           	0x02
++#define		CHIPRST         	0x01
++#define		CHIPRSTACK      	0x01
++
++#define	HADDR           		0x88
++
++#define	HCNT            		0x8c
++
++#define	SCBPTR          		0x90
++
++#define	INTSTAT         		0x91
++#define		SEQINT_MASK     	0xf1
++#define		DATA_OVERRUN    	0xe1
++#define		MSGIN_PHASEMIS  	0xd1
++#define		TRACEPOINT2     	0xc1
++#define		SEQ_SG_FIXUP    	0xb1
++#define		AWAITING_MSG    	0xa1
++#define		RESIDUAL        	0x81
++#define		BAD_STATUS      	0x71
++#define		REJECT_MSG      	0x61
++#define		WIDE_RESIDUE    	0x51
++#define		EXTENDED_MSG    	0x41
++#define		NO_MATCH        	0x31
++#define		NO_IDENT        	0x21
++#define		SEND_REJECT     	0x11
++#define		INT_PEND        	0x0f
++#define		BRKADRINT       	0x08
++#define		SCSIINT         	0x04
++#define		CMDCMPLT        	0x02
++#define		BAD_PHASE       	0x01
++#define		SEQINT          	0x01
++
++#define	CLRINT          		0x92
++#define		CLRPARERR       	0x10
++#define		CLRBRKADRINT    	0x08
++#define		CLRSCSIINT      	0x04
++#define		CLRCMDINT       	0x02
++#define		CLRSEQINT       	0x01
++
++#define	ERROR           		0x92
++#define		CIOPARERR       	0x80
++#define		PCIERRSTAT      	0x40
++#define		MPARERR         	0x20
++#define		DPARERR         	0x10
++#define		SQPARERR        	0x08
++#define		ILLOPCODE       	0x04
++#define		DSCTMOUT        	0x02
++#define		ILLSADDR        	0x02
++#define		ILLHADDR        	0x01
++
++#define	DFCNTRL         		0x93
++
++#define	DFSTATUS        		0x94
++#define		PRELOAD_AVAIL   	0x80
++#define		DWORDEMP        	0x20
++#define		MREQPEND        	0x10
++#define		HDONE           	0x08
++#define		DFTHRESH        	0x04
++#define		FIFOFULL        	0x02
++#define		FIFOEMP         	0x01
++
++#define	DFDAT           		0x99
++
++#define	SCBCNT          		0x9a
++#define		SCBAUTO         	0x80
++#define		SCBCNT_MASK     	0x1f
++
++#define	QINFIFO         		0x9b
++
++#define	QINCNT          		0x9c
++
++#define	SCSIDATL_IMG    		0x9c
++
++#define	QOUTFIFO        		0x9d
++
++#define	CRCCONTROL1     		0x9d
++#define		CRCONSEEN       	0x80
++#define		CRCVALCHKEN     	0x40
++#define		CRCENDCHKEN     	0x20
++#define		CRCREQCHKEN     	0x10
++#define		TARGCRCENDEN    	0x08
++#define		TARGCRCCNTEN    	0x04
++
++#define	SCSIPHASE       		0x9e
++#define		SP_STATUS       	0x20
++#define		SP_COMMAND      	0x10
++#define		SP_MSG_IN       	0x08
++#define		SP_MSG_OUT      	0x04
++#define		SP_DATA_IN      	0x02
++#define		SP_DATA_OUT     	0x01
++
++#define	QOUTCNT         		0x9e
++
++#define	SFUNCT          		0x9f
++#define		ALT_MODE        	0x80
++
++#define	SCB_CONTROL     		0xa0
++#define		MK_MESSAGE      	0x80
++#define		DISCENB         	0x40
++#define		TAG_ENB         	0x20
++#define		DISCONNECTED    	0x04
++#define		SCB_TAG_TYPE    	0x03
++
++#define	SCB_BASE        		0xa0
++
++#define	SCB_TCL         		0xa1
++#define		TID             	0xf0
++#define		SELBUSB         	0x08
++#define		LID             	0x07
++
++#define	SCB_TARGET_STATUS		0xa2
++
++#define	SCB_SGCOUNT     		0xa3
++
++#define	SCB_SGPTR       		0xa4
++
++#define	SCB_RESID_SGCNT 		0xa8
++
++#define	SCB_RESID_DCNT  		0xa9
++
++#define	SCB_DATAPTR     		0xac
++
++#define	SCB_DATACNT     		0xb0
++
++#define	SCB_CMDPTR      		0xb4
++
++#define	SCB_CMDLEN      		0xb8
++
++#define	SCB_TAG         		0xb9
++
++#define	SCB_NEXT        		0xba
++
++#define	SCB_PREV        		0xbb
++
++#define	SCB_BUSYTARGETS 		0xbc
++
++#define	SEECTL_2840     		0xc0
++#define		CS_2840         	0x04
++#define		CK_2840         	0x02
++#define		DO_2840         	0x01
++
++#define	STATUS_2840     		0xc1
++#define		EEPROM_TF       	0x80
++#define		BIOS_SEL        	0x60
++#define		ADSEL           	0x1e
++#define		DI_2840         	0x01
++
++#define	CCHADDR         		0xe0
++
++#define	CCHCNT          		0xe8
++
++#define	CCSGRAM         		0xe9
++
++#define	CCSGADDR        		0xea
++
++#define	CCSGCTL         		0xeb
++#define		CCSGDONE        	0x80
++#define		CCSGEN          	0x08
++#define		FLAG            	0x02
++#define		CCSGRESET       	0x01
++
++#define	CCSCBRAM        		0xec
++
++#define	CCSCBADDR       		0xed
++
++#define	CCSCBCTL        		0xee
++#define		CCSCBDONE       	0x80
++#define		ARRDONE         	0x40
++#define		CCARREN         	0x10
++#define		CCSCBEN         	0x08
++#define		CCSCBDIR        	0x04
++#define		CCSCBRESET      	0x01
++
++#define	CCSCBCNT        		0xef
++
++#define	CCSCBPTR        		0xf1
++
++#define	HNSCB_QOFF      		0xf4
++
++#define	HESCB_QOFF      		0xf5
++
++#define	SNSCB_QOFF      		0xf6
++
++#define	SESCB_QOFF      		0xf7
++
++#define	SDSCB_QOFF      		0xf8
++
++#define	QOFF_CTLSTA     		0xfa
++#define		ESTABLISH_SCB_AVAIL	0x80
++#define		SCB_AVAIL       	0x40
++#define		SNSCB_ROLLOVER  	0x20
++#define		SDSCB_ROLLOVER  	0x10
++#define		SESCB_ROLLOVER  	0x08
++#define		SCB_QSIZE       	0x07
++#define		SCB_QSIZE_256   	0x06
++
++#define	DFF_THRSH       		0xfb
++#define		WR_DFTHRSH      	0x70
++#define		WR_DFTHRSH_MAX  	0x70
++#define		WR_DFTHRSH_90   	0x60
++#define		WR_DFTHRSH_85   	0x50
++#define		WR_DFTHRSH_75   	0x40
++#define		WR_DFTHRSH_63   	0x30
++#define		WR_DFTHRSH_50   	0x20
++#define		WR_DFTHRSH_25   	0x10
++#define		RD_DFTHRSH_MAX  	0x07
++#define		RD_DFTHRSH      	0x07
++#define		RD_DFTHRSH_90   	0x06
++#define		RD_DFTHRSH_85   	0x05
++#define		RD_DFTHRSH_75   	0x04
++#define		RD_DFTHRSH_63   	0x03
++#define		RD_DFTHRSH_50   	0x02
++#define		RD_DFTHRSH_25   	0x01
++#define		WR_DFTHRSH_MIN  	0x00
++#define		RD_DFTHRSH_MIN  	0x00
++
++#define	SG_CACHEPTR     		0xfc
++#define		SG_USER_DATA    	0xfc
++#define		LAST_SEG        	0x02
++#define		LAST_SEG_DONE   	0x01
++
++
++#define	CMD_GROUP2_BYTE_DELTA	0xfa
++#define	MAX_OFFSET_8BIT	0x0f
++#define	BUS_16_BIT	0x01
++#define	QINFIFO_OFFSET	0x02
++#define	CMD_GROUP5_BYTE_DELTA	0x0b
++#define	CMD_GROUP_CODE_SHIFT	0x05
++#define	MAX_OFFSET_ULTRA2	0x7f
++#define	MAX_OFFSET_16BIT	0x08
++#define	BUS_8_BIT	0x00
++#define	QOUTFIFO_OFFSET	0x01
++#define	UNTAGGEDSCB_OFFSET	0x00
++#define	CCSGRAM_MAXSEGS	0x10
++#define	SCB_LIST_NULL	0xff
++#define	SG_SIZEOF	0x08
++#define	CMD_GROUP4_BYTE_DELTA	0x04
++#define	CMD_GROUP0_BYTE_DELTA	0xfc
++#define	HOST_MSG	0xff
++#define	BUS_32_BIT	0x02
++#define	CCSGADDR_MAX	0x80
++
++
++/* Downloaded Constant Definitions */
++#define	TMODE_NUMCMDS	0x00
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx_seq.c linux/drivers/scsi/aic7xxx/aic7xxx_seq.c
+--- linux-2.2.17/drivers/scsi/aic7xxx/aic7xxx_seq.c	Wed Dec 31 19:00:00 1969
++++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.c	Tue Feb  6 03:49:36 2001
+@@ -0,0 +1,830 @@
++/*
++  * DO NOT EDIT - This file is automatically generated.
++  */
++static unsigned char seqprog[] = {
++	0xff, 0x6a, 0x06, 0x08,
++	0x7f, 0x02, 0x04, 0x08,
++	0x12, 0x6a, 0x00, 0x00,
++	0xff, 0x6a, 0xd6, 0x09,
++	0xff, 0x6a, 0xdc, 0x09,
++	0x00, 0x65, 0xcc, 0x58,
++	0xf7, 0x01, 0x02, 0x08,
++	0xff, 0x4e, 0xc8, 0x08,
++	0xbf, 0x60, 0xc0, 0x08,
++	0x60, 0x0b, 0x86, 0x68,
++	0x40, 0x00, 0x0c, 0x68,
++	0x08, 0x1f, 0x3e, 0x10,
++	0x60, 0x0b, 0x86, 0x68,
++	0x40, 0x00, 0x0c, 0x68,
++	0x08, 0x1f, 0x3e, 0x10,
++	0xff, 0x3e, 0x48, 0x60,
++	0x40, 0xfa, 0x10, 0x78,
++	0xff, 0xf6, 0xd4, 0x08,
++	0x01, 0x4e, 0x9c, 0x18,
++	0x40, 0x60, 0xc0, 0x00,
++	0x00, 0x4d, 0x10, 0x70,
++	0x01, 0x4e, 0x9c, 0x18,
++	0xbf, 0x60, 0xc0, 0x08,
++	0x00, 0x6a, 0xce, 0x5c,
++	0xff, 0x4e, 0xc8, 0x18,
++	0x02, 0x6a, 0xb8, 0x5b,
++	0xff, 0x52, 0x20, 0x09,
++	0x0d, 0x6a, 0x6a, 0x00,
++	0x00, 0x52, 0x2e, 0x5c,
++	0x03, 0xb0, 0x52, 0x31,
++	0xff, 0xb0, 0x52, 0x09,
++	0xff, 0xb1, 0x54, 0x09,
++	0xff, 0xb2, 0x56, 0x09,
++	0xff, 0xa3, 0x50, 0x09,
++	0xff, 0x3e, 0x74, 0x09,
++	0xff, 0x90, 0x7c, 0x08,
++	0xff, 0x3e, 0x20, 0x09,
++	0x00, 0x65, 0x4e, 0x58,
++	0x00, 0x65, 0x0c, 0x40,
++	0xf7, 0x1f, 0xca, 0x08,
++	0x08, 0xa1, 0xc8, 0x08,
++	0x00, 0x65, 0xca, 0x00,
++	0xff, 0x65, 0x3e, 0x08,
++	0xf0, 0xa1, 0xc8, 0x08,
++	0x0f, 0x0f, 0x1e, 0x08,
++	0x00, 0x0f, 0x1e, 0x00,
++	0xf0, 0xa1, 0xc8, 0x08,
++	0x0f, 0x05, 0x0a, 0x08,
++	0x00, 0x05, 0x0a, 0x00,
++	0xff, 0x6a, 0x0c, 0x08,
++	0x5a, 0x6a, 0x00, 0x04,
++	0x12, 0x65, 0x02, 0x00,
++	0x31, 0x6a, 0xca, 0x00,
++	0x80, 0x37, 0x6e, 0x68,
++	0xff, 0x65, 0xca, 0x18,
++	0xff, 0x37, 0xdc, 0x08,
++	0xff, 0x6e, 0xc8, 0x08,
++	0x00, 0x6c, 0x76, 0x78,
++	0x20, 0x01, 0x02, 0x00,
++	0x4c, 0x37, 0xc8, 0x28,
++	0x08, 0x1f, 0x7e, 0x78,
++	0x08, 0x37, 0x6e, 0x00,
++	0x08, 0x64, 0xc8, 0x00,
++	0x70, 0x64, 0xca, 0x18,
++	0xff, 0x6c, 0x0a, 0x08,
++	0x20, 0x64, 0xca, 0x18,
++	0xff, 0x6c, 0x08, 0x0c,
++	0x40, 0x0b, 0x96, 0x68,
++	0x20, 0x6a, 0x16, 0x00,
++	0xf0, 0x19, 0x6e, 0x08,
++	0x08, 0x6a, 0x18, 0x00,
++	0x08, 0x11, 0x22, 0x00,
++	0x08, 0x6a, 0x66, 0x58,
++	0x08, 0x6a, 0x68, 0x00,
++	0x00, 0x65, 0xaa, 0x40,
++	0x12, 0x6a, 0x00, 0x00,
++	0x40, 0x6a, 0x16, 0x00,
++	0xff, 0x3e, 0x20, 0x09,
++	0xff, 0xba, 0x7c, 0x08,
++	0xff, 0xa1, 0x6e, 0x08,
++	0x08, 0x6a, 0x18, 0x00,
++	0x08, 0x11, 0x22, 0x00,
++	0x08, 0x6a, 0x66, 0x58,
++	0x80, 0x6a, 0x68, 0x00,
++	0x80, 0x36, 0x6c, 0x00,
++	0x00, 0x65, 0x02, 0x5c,
++	0xff, 0x3d, 0xc8, 0x08,
++	0xbf, 0x64, 0xde, 0x78,
++	0xbf, 0x64, 0x88, 0x79,
++	0x80, 0x64, 0x10, 0x72,
++	0xa0, 0x64, 0x40, 0x72,
++	0xc0, 0x64, 0x38, 0x72,
++	0xe0, 0x64, 0x80, 0x72,
++	0x01, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0xaa, 0x40,
++	0xf7, 0x11, 0x22, 0x08,
++	0x00, 0x65, 0xcc, 0x58,
++	0xff, 0x06, 0xd4, 0x08,
++	0xf7, 0x01, 0x02, 0x08,
++	0x09, 0x0c, 0xc6, 0x78,
++	0x08, 0x0c, 0x0c, 0x68,
++	0x01, 0x6a, 0x22, 0x01,
++	0xff, 0x6a, 0x26, 0x09,
++	0x02, 0x6a, 0x08, 0x30,
++	0xff, 0x6a, 0x08, 0x08,
++	0xdf, 0x01, 0x02, 0x08,
++	0x01, 0x6a, 0x7a, 0x00,
++	0xff, 0x6a, 0x6c, 0x0c,
++	0x04, 0x14, 0x10, 0x31,
++	0x03, 0xa9, 0x18, 0x31,
++	0x00, 0x65, 0xf0, 0x40,
++	0xa8, 0x6a, 0x6a, 0x00,
++	0x40, 0x3d, 0xe4, 0x68,
++	0x04, 0x35, 0x6a, 0x00,
++	0x00, 0x65, 0x72, 0x5b,
++	0x80, 0x6a, 0xd4, 0x01,
++	0x10, 0x36, 0xd8, 0x68,
++	0x10, 0x36, 0x6c, 0x00,
++	0x07, 0xac, 0x10, 0x31,
++	0x05, 0xa3, 0x70, 0x30,
++	0xff, 0x38, 0xf8, 0x68,
++	0x80, 0x02, 0x04, 0x00,
++	0x04, 0x35, 0x6a, 0x08,
++	0x03, 0x69, 0x18, 0x31,
++	0x22, 0x38, 0xc8, 0x28,
++	0x01, 0x38, 0xfe, 0x60,
++	0x02, 0x64, 0xc8, 0x00,
++	0xff, 0x64, 0xf8, 0x09,
++	0xff, 0x35, 0x26, 0x09,
++	0x80, 0x02, 0x76, 0x69,
++	0x10, 0x0c, 0x3a, 0x69,
++	0x80, 0x94, 0x04, 0x79,
++	0x01, 0x38, 0x30, 0x71,
++	0x80, 0xea, 0x22, 0x61,
++	0xef, 0x38, 0xc8, 0x18,
++	0x80, 0x6a, 0xc8, 0x00,
++	0x00, 0x65, 0x14, 0x49,
++	0x33, 0x38, 0xc8, 0x28,
++	0xff, 0x64, 0xd0, 0x09,
++	0x04, 0x39, 0xc0, 0x31,
++	0x09, 0x6a, 0xd6, 0x01,
++	0x80, 0xeb, 0x1a, 0x79,
++	0xf7, 0xeb, 0xd6, 0x09,
++	0x08, 0xeb, 0x1e, 0x69,
++	0x01, 0x6a, 0xd6, 0x01,
++	0x10, 0x0c, 0x3a, 0x69,
++	0xff, 0x38, 0x70, 0x18,
++	0x08, 0xe9, 0x10, 0x31,
++	0xff, 0x6a, 0xc8, 0x08,
++	0x08, 0x39, 0x72, 0x18,
++	0x00, 0x3a, 0x74, 0x20,
++	0x00, 0x65, 0xf0, 0x40,
++	0x10, 0x0c, 0x3a, 0x69,
++	0x01, 0xfc, 0x30, 0x79,
++	0xff, 0x6a, 0x70, 0x08,
++	0x01, 0x0c, 0x36, 0x79,
++	0x10, 0x0c, 0xf0, 0x78,
++	0x00, 0x65, 0x5c, 0x59,
++	0x01, 0xfc, 0x54, 0x69,
++	0x40, 0x0d, 0x44, 0x69,
++	0xb1, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0x54, 0x41,
++	0x2e, 0xfc, 0xa2, 0x28,
++	0x3f, 0x38, 0xc8, 0x08,
++	0x00, 0x51, 0x54, 0x71,
++	0xff, 0x6a, 0xc8, 0x08,
++	0xf8, 0x39, 0x72, 0x18,
++	0xff, 0x3a, 0x74, 0x20,
++	0x01, 0x38, 0x70, 0x18,
++	0x00, 0x65, 0x46, 0x41,
++	0x03, 0x08, 0x52, 0x31,
++	0xff, 0x38, 0x50, 0x09,
++	0x12, 0x01, 0x02, 0x00,
++	0x00, 0x65, 0xaa, 0x40,
++	0x04, 0x93, 0x70, 0x69,
++	0xdf, 0x93, 0x26, 0x09,
++	0x20, 0x93, 0x60, 0x69,
++	0x02, 0x93, 0x26, 0x01,
++	0x01, 0x94, 0x64, 0x79,
++	0x01, 0x94, 0x64, 0x79,
++	0x01, 0x94, 0x64, 0x79,
++	0x01, 0x94, 0x64, 0x79,
++	0x01, 0x94, 0x64, 0x79,
++	0x10, 0x94, 0x6e, 0x69,
++	0xd7, 0x93, 0x26, 0x09,
++	0x28, 0x93, 0x72, 0x69,
++	0xff, 0x6a, 0xd4, 0x0c,
++	0x10, 0x0c, 0x76, 0x79,
++	0x00, 0x65, 0x5c, 0x59,
++	0x7f, 0x02, 0x04, 0x08,
++	0xe1, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0xaa, 0x40,
++	0x03, 0xa9, 0x10, 0x30,
++	0x08, 0x6a, 0xcc, 0x00,
++	0xa9, 0x6a, 0x18, 0x5c,
++	0x00, 0x65, 0xa6, 0x41,
++	0x79, 0x6a, 0x6a, 0x00,
++	0x40, 0x3d, 0x8e, 0x69,
++	0x04, 0x35, 0x6a, 0x00,
++	0x00, 0x65, 0x72, 0x5b,
++	0x80, 0x6a, 0xd4, 0x01,
++	0x10, 0x36, 0x80, 0x69,
++	0x10, 0x36, 0x6c, 0x00,
++	0x07, 0xac, 0x10, 0x31,
++	0x03, 0x8c, 0x10, 0x30,
++	0x05, 0xa3, 0x70, 0x30,
++	0x88, 0x6a, 0xcc, 0x00,
++	0xac, 0x6a, 0x10, 0x5c,
++	0x00, 0x65, 0x0a, 0x5c,
++	0x38, 0x6a, 0xcc, 0x00,
++	0xa3, 0x6a, 0x14, 0x5c,
++	0xff, 0x38, 0xb4, 0x69,
++	0x80, 0x02, 0x04, 0x00,
++	0xe7, 0x35, 0x6a, 0x08,
++	0x03, 0x69, 0x10, 0x30,
++	0xff, 0x6a, 0x10, 0x00,
++	0xff, 0x6a, 0x12, 0x00,
++	0xff, 0x6a, 0x14, 0x00,
++	0x01, 0x38, 0xb8, 0x61,
++	0xbf, 0x35, 0x6a, 0x08,
++	0x00, 0x35, 0x52, 0x5b,
++	0x80, 0x02, 0x0a, 0x6a,
++	0xff, 0x65, 0xfa, 0x79,
++	0x01, 0x38, 0xfa, 0x71,
++	0xff, 0x38, 0x70, 0x18,
++	0x80, 0xea, 0xda, 0x61,
++	0xef, 0x38, 0xc8, 0x18,
++	0x80, 0x6a, 0xc8, 0x00,
++	0x00, 0x65, 0xcc, 0x49,
++	0x33, 0x38, 0xc8, 0x28,
++	0xff, 0x64, 0xd0, 0x09,
++	0x04, 0x39, 0xc0, 0x31,
++	0x09, 0x6a, 0xd6, 0x01,
++	0x80, 0xeb, 0xd2, 0x79,
++	0xf7, 0xeb, 0xd6, 0x09,
++	0x08, 0xeb, 0xd6, 0x69,
++	0x01, 0x6a, 0xd6, 0x01,
++	0x08, 0xe9, 0x10, 0x31,
++	0x03, 0x8c, 0x10, 0x30,
++	0x88, 0x6a, 0xcc, 0x00,
++	0x39, 0x6a, 0x16, 0x5c,
++	0x08, 0x6a, 0x18, 0x01,
++	0xff, 0x6a, 0x1a, 0x09,
++	0xff, 0x6a, 0x1c, 0x09,
++	0x0d, 0x93, 0x26, 0x01,
++	0x00, 0x65, 0xc0, 0x5c,
++	0x88, 0x6a, 0xb2, 0x5c,
++	0x00, 0x65, 0x0a, 0x5c,
++	0xff, 0x6a, 0xc8, 0x08,
++	0x08, 0x39, 0x72, 0x18,
++	0x00, 0x3a, 0x74, 0x20,
++	0x01, 0x0c, 0xf6, 0x79,
++	0x10, 0x0c, 0xa6, 0x79,
++	0xff, 0x6a, 0x70, 0x08,
++	0x03, 0x08, 0x52, 0x31,
++	0xff, 0x38, 0x50, 0x09,
++	0xff, 0x08, 0x52, 0x09,
++	0xff, 0x09, 0x54, 0x09,
++	0xff, 0x0a, 0x56, 0x09,
++	0xff, 0x38, 0x50, 0x09,
++	0x00, 0x65, 0xaa, 0x40,
++	0x7f, 0x02, 0x04, 0x08,
++	0xe1, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0xaa, 0x40,
++	0x00, 0x65, 0x72, 0x5b,
++	0x05, 0xb4, 0x10, 0x31,
++	0x02, 0x6a, 0x1a, 0x31,
++	0x03, 0x8c, 0x10, 0x30,
++	0x88, 0x6a, 0xcc, 0x00,
++	0xb4, 0x6a, 0x14, 0x5c,
++	0xff, 0x6a, 0x1a, 0x09,
++	0xff, 0x6a, 0x1c, 0x09,
++	0x00, 0x65, 0x0a, 0x5c,
++	0x3d, 0x6a, 0x52, 0x5b,
++	0xac, 0x6a, 0x26, 0x01,
++	0x04, 0x0b, 0x26, 0x6a,
++	0x04, 0x0b, 0x2c, 0x6a,
++	0x10, 0x0c, 0x28, 0x7a,
++	0x02, 0x03, 0x30, 0x7a,
++	0x11, 0x0c, 0x2c, 0x7a,
++	0xd7, 0x93, 0x26, 0x09,
++	0x28, 0x93, 0x32, 0x6a,
++	0x12, 0x01, 0x02, 0x00,
++	0x00, 0x65, 0xaa, 0x40,
++	0x00, 0x65, 0x72, 0x5b,
++	0xff, 0x06, 0x44, 0x09,
++	0x00, 0x65, 0xaa, 0x40,
++	0x10, 0x3d, 0x06, 0x00,
++	0xff, 0x34, 0xca, 0x08,
++	0x80, 0x65, 0x64, 0x62,
++	0x0f, 0xa1, 0xca, 0x08,
++	0x07, 0xa1, 0xca, 0x08,
++	0x40, 0xa0, 0xc8, 0x08,
++	0x00, 0x65, 0xca, 0x00,
++	0x80, 0x65, 0xca, 0x00,
++	0x80, 0xa0, 0x54, 0x7a,
++	0xff, 0x65, 0x0c, 0x08,
++	0x00, 0x65, 0x66, 0x42,
++	0x20, 0xa0, 0x6c, 0x7a,
++	0xff, 0x65, 0x0c, 0x08,
++	0x00, 0x65, 0x02, 0x5c,
++	0xa0, 0x3d, 0x74, 0x62,
++	0x23, 0xa0, 0x0c, 0x08,
++	0x00, 0x65, 0x02, 0x5c,
++	0xa0, 0x3d, 0x74, 0x62,
++	0x00, 0xb9, 0x6c, 0x42,
++	0xff, 0x65, 0x6c, 0x62,
++	0xa1, 0x6a, 0x22, 0x01,
++	0xff, 0x6a, 0xd4, 0x08,
++	0x10, 0x51, 0x74, 0x72,
++	0x40, 0x6a, 0x18, 0x00,
++	0xff, 0x65, 0x0c, 0x08,
++	0x00, 0x65, 0x02, 0x5c,
++	0xa0, 0x3d, 0x3e, 0x72,
++	0x40, 0x6a, 0x18, 0x00,
++	0xff, 0x34, 0xa6, 0x08,
++	0x80, 0x34, 0x7c, 0x62,
++	0x7f, 0xa0, 0x40, 0x09,
++	0x08, 0x6a, 0x68, 0x00,
++	0x00, 0x65, 0xaa, 0x40,
++	0x64, 0x6a, 0x48, 0x5b,
++	0x80, 0x64, 0xf2, 0x6a,
++	0x04, 0x64, 0xd4, 0x72,
++	0x02, 0x64, 0xda, 0x72,
++	0x00, 0x6a, 0x9c, 0x72,
++	0x03, 0x64, 0xee, 0x72,
++	0x01, 0x64, 0xd0, 0x72,
++	0x07, 0x64, 0x30, 0x73,
++	0x08, 0x64, 0x98, 0x72,
++	0x23, 0x64, 0x34, 0x73,
++	0x11, 0x6a, 0x22, 0x01,
++	0x07, 0x6a, 0x3a, 0x5b,
++	0xff, 0x06, 0xd4, 0x08,
++	0x00, 0x65, 0xaa, 0x40,
++	0xff, 0xa8, 0xa0, 0x6a,
++	0xff, 0xa2, 0xb8, 0x7a,
++	0x01, 0x6a, 0x6a, 0x00,
++	0x00, 0xb9, 0x2e, 0x5c,
++	0xff, 0xa2, 0xb8, 0x7a,
++	0x71, 0x6a, 0x22, 0x01,
++	0xff, 0x6a, 0xd4, 0x08,
++	0x40, 0x51, 0xb8, 0x62,
++	0x0d, 0x6a, 0x6a, 0x00,
++	0x00, 0xb9, 0x2e, 0x5c,
++	0xff, 0x3e, 0x74, 0x09,
++	0xff, 0x90, 0x7c, 0x08,
++	0x00, 0x65, 0x4e, 0x58,
++	0x00, 0x65, 0xbe, 0x40,
++	0x20, 0xa0, 0xc0, 0x6a,
++	0xff, 0x37, 0xc8, 0x08,
++	0x00, 0x6a, 0xd8, 0x5b,
++	0xff, 0x6a, 0xee, 0x5b,
++	0xff, 0xf8, 0xc8, 0x08,
++	0xff, 0x4f, 0xc8, 0x08,
++	0x01, 0x6a, 0xd8, 0x5b,
++	0x00, 0xb9, 0xee, 0x5b,
++	0x01, 0x4f, 0x9e, 0x18,
++	0x02, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0xc8, 0x5c,
++	0x00, 0x65, 0xbe, 0x40,
++	0x41, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0xaa, 0x40,
++	0x04, 0xa0, 0x40, 0x01,
++	0x00, 0x65, 0xe0, 0x5c,
++	0x00, 0x65, 0xbe, 0x40,
++	0x10, 0x36, 0x98, 0x7a,
++	0x05, 0x38, 0x46, 0x31,
++	0x04, 0x14, 0x58, 0x31,
++	0x03, 0xa9, 0x60, 0x31,
++	0xa3, 0x6a, 0xcc, 0x00,
++	0x38, 0x6a, 0x14, 0x5c,
++	0xac, 0x6a, 0xcc, 0x00,
++	0x14, 0x6a, 0x16, 0x5c,
++	0xa9, 0x6a, 0x18, 0x5c,
++	0x00, 0x65, 0x98, 0x42,
++	0xef, 0x36, 0x6c, 0x08,
++	0x00, 0x65, 0x98, 0x42,
++	0x0f, 0x64, 0xc8, 0x08,
++	0x07, 0x64, 0xc8, 0x08,
++	0x00, 0x37, 0x6e, 0x00,
++	0xff, 0x6a, 0xa4, 0x00,
++	0x00, 0x65, 0xa8, 0x5b,
++	0xff, 0x51, 0x04, 0x73,
++	0x20, 0x36, 0x0e, 0x7b,
++	0x00, 0x90, 0x96, 0x5b,
++	0x00, 0x65, 0x10, 0x43,
++	0xff, 0x06, 0xd4, 0x08,
++	0x00, 0x65, 0x02, 0x5c,
++	0xe0, 0x3d, 0x2a, 0x63,
++	0x20, 0x12, 0x2a, 0x63,
++	0x51, 0x6a, 0x3e, 0x5b,
++	0x00, 0x65, 0x90, 0x5b,
++	0xff, 0x37, 0xc8, 0x08,
++	0x00, 0xa1, 0x22, 0x63,
++	0x04, 0xa0, 0x22, 0x7b,
++	0xfb, 0xa0, 0x40, 0x09,
++	0x80, 0x36, 0x6c, 0x00,
++	0x80, 0xa0, 0x98, 0x7a,
++	0x7f, 0xa0, 0x40, 0x09,
++	0xff, 0x6a, 0x3a, 0x5b,
++	0x00, 0x65, 0x98, 0x42,
++	0x04, 0xa0, 0x28, 0x7b,
++	0x00, 0x65, 0xe0, 0x5c,
++	0x00, 0x65, 0x2a, 0x43,
++	0x00, 0x65, 0xc8, 0x5c,
++	0x31, 0x6a, 0x22, 0x01,
++	0x0c, 0x6a, 0x3a, 0x5b,
++	0x00, 0x65, 0x98, 0x42,
++	0x61, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0x98, 0x42,
++	0x51, 0x6a, 0x3e, 0x5b,
++	0x51, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0x98, 0x42,
++	0x10, 0x3d, 0x06, 0x00,
++	0xff, 0x65, 0x68, 0x0c,
++	0xff, 0x06, 0xd4, 0x08,
++	0x01, 0x0c, 0x40, 0x7b,
++	0x04, 0x0c, 0x42, 0x6b,
++	0xe0, 0x03, 0x7a, 0x08,
++	0xe0, 0x3d, 0x4e, 0x63,
++	0xff, 0x65, 0xcc, 0x08,
++	0xff, 0x12, 0xda, 0x0c,
++	0xff, 0x06, 0xd4, 0x0c,
++	0xd1, 0x6a, 0x22, 0x01,
++	0x00, 0x65, 0xaa, 0x40,
++	0xff, 0x65, 0x26, 0x09,
++	0x01, 0x0b, 0x62, 0x6b,
++	0x10, 0x0c, 0x54, 0x7b,
++	0x04, 0x0b, 0x5c, 0x6b,
++	0xff, 0x6a, 0xca, 0x08,
++	0x04, 0x93, 0x60, 0x6b,
++	0x01, 0x94, 0x5e, 0x7b,
++	0x10, 0x94, 0x60, 0x6b,
++	0x80, 0x3d, 0x66, 0x73,
++	0x0f, 0x04, 0x6a, 0x6b,
++	0x02, 0x03, 0x6a, 0x7b,
++	0x11, 0x0c, 0x66, 0x7b,
++	0xc7, 0x93, 0x26, 0x09,
++	0xff, 0x99, 0xd4, 0x08,
++	0x38, 0x93, 0x6c, 0x6b,
++	0xff, 0x6a, 0xd4, 0x0c,
++	0x80, 0x36, 0x70, 0x6b,
++	0x21, 0x6a, 0x22, 0x05,
++	0xff, 0x65, 0x20, 0x09,
++	0xff, 0x51, 0x7e, 0x63,
++	0xff, 0x37, 0xc8, 0x08,
++	0xa1, 0x6a, 0x8a, 0x43,
++	0xff, 0x51, 0xc8, 0x08,
++	0xb9, 0x6a, 0x8a, 0x43,
++	0xff, 0x90, 0xa4, 0x08,
++	0xff, 0xba, 0x8e, 0x73,
++	0xff, 0xba, 0x20, 0x09,
++	0xff, 0x65, 0xca, 0x18,
++	0x00, 0x6c, 0x82, 0x63,
++	0xff, 0x90, 0xca, 0x0c,
++	0xff, 0x6a, 0xca, 0x04,
++	0x20, 0x36, 0xa2, 0x7b,
++	0x00, 0x90, 0x76, 0x5b,
++	0xff, 0x65, 0xa2, 0x73,
++	0xff, 0x52, 0xa0, 0x73,
++	0xff, 0xba, 0xcc, 0x08,
++	0xff, 0x52, 0x20, 0x09,
++	0xff, 0x66, 0x74, 0x09,
++	0xff, 0x65, 0x20, 0x0d,
++	0xff, 0xba, 0x7e, 0x0c,
++	0x00, 0x6a, 0xce, 0x5c,
++	0x0d, 0x6a, 0x6a, 0x00,
++	0x00, 0x51, 0x2e, 0x44,
++	0xff, 0x3f, 0xfc, 0x73,
++	0xff, 0x6a, 0xa2, 0x00,
++	0x00, 0x3f, 0x76, 0x5b,
++	0xff, 0x65, 0xfc, 0x73,
++	0x20, 0x36, 0x6c, 0x00,
++	0x20, 0xa0, 0xb6, 0x6b,
++	0xff, 0xb9, 0xa2, 0x0c,
++	0xff, 0x6a, 0xa2, 0x04,
++	0xff, 0x65, 0xa4, 0x08,
++	0xe0, 0x6a, 0xcc, 0x00,
++	0x45, 0x6a, 0x22, 0x5c,
++	0x01, 0x6a, 0xd0, 0x01,
++	0x09, 0x6a, 0xd6, 0x01,
++	0x80, 0xeb, 0xc2, 0x7b,
++	0x01, 0x6a, 0xd6, 0x01,
++	0x01, 0xe9, 0xa4, 0x34,
++	0x88, 0x6a, 0xcc, 0x00,
++	0x45, 0x6a, 0x22, 0x5c,
++	0x01, 0x6a, 0x18, 0x01,
++	0xff, 0x6a, 0x1a, 0x09,
++	0xff, 0x6a, 0x1c, 0x09,
++	0x0d, 0x6a, 0x26, 0x01,
++	0x00, 0x65, 0xc0, 0x5c,
++	0xff, 0x99, 0xa4, 0x0c,
++	0xff, 0x65, 0xa4, 0x08,
++	0xe0, 0x6a, 0xcc, 0x00,
++	0x45, 0x6a, 0x22, 0x5c,
++	0x01, 0x6a, 0xd0, 0x01,
++	0x01, 0x6a, 0xdc, 0x05,
++	0x88, 0x6a, 0xcc, 0x00,
++	0x45, 0x6a, 0x22, 0x5c,
++	0x01, 0x6a, 0x18, 0x01,
++	0xff, 0x6a, 0x1a, 0x09,
++	0xff, 0x6a, 0x1c, 0x09,
++	0x01, 0x6a, 0x26, 0x05,
++	0x01, 0x65, 0xd8, 0x31,
++	0x09, 0xee, 0xdc, 0x01,
++	0x80, 0xee, 0xf2, 0x7b,
++	0xff, 0x6a, 0xdc, 0x0d,
++	0xff, 0x65, 0x32, 0x09,
++	0x0a, 0x93, 0x26, 0x01,
++	0x00, 0x65, 0xc0, 0x44,
++	0xff, 0x37, 0xc8, 0x08,
++	0x00, 0x6a, 0xb8, 0x5b,
++	0xff, 0x52, 0xa2, 0x0c,
++	0x01, 0x0c, 0x02, 0x7c,
++	0x04, 0x0c, 0x02, 0x6c,
++	0xe0, 0x03, 0x06, 0x08,
++	0xe0, 0x03, 0x7a, 0x0c,
++	0xff, 0x8c, 0x10, 0x08,
++	0xff, 0x8d, 0x12, 0x08,
++	0xff, 0x8e, 0x14, 0x0c,
++	0xff, 0x6c, 0xda, 0x08,
++	0xff, 0x6c, 0xda, 0x08,
++	0xff, 0x6c, 0xda, 0x08,
++	0xff, 0x6c, 0xda, 0x08,
++	0xff, 0x6c, 0xda, 0x08,
++	0xff, 0x6c, 0xda, 0x08,
++	0xff, 0x6c, 0xda, 0x0c,
++	0x3d, 0x64, 0xa4, 0x28,
++	0x55, 0x64, 0xc8, 0x28,
++	0x00, 0x6c, 0xda, 0x18,
++	0xff, 0x52, 0xc8, 0x08,
++	0x00, 0x6c, 0xda, 0x20,
++	0xff, 0x6a, 0xc8, 0x08,
++	0x00, 0x6c, 0xda, 0x20,
++	0x00, 0x6c, 0xda, 0x24,
++	0xff, 0x65, 0xc8, 0x08,
++	0xe0, 0x6a, 0xcc, 0x00,
++	0x41, 0x6a, 0x1e, 0x5c,
++	0xff, 0x90, 0xe2, 0x09,
++	0x20, 0x6a, 0xd0, 0x01,
++	0x04, 0x35, 0x40, 0x7c,
++	0x1d, 0x6a, 0xdc, 0x01,
++	0xdc, 0xee, 0x3c, 0x64,
++	0x00, 0x65, 0x56, 0x44,
++	0x01, 0x6a, 0xdc, 0x01,
++	0x20, 0xa0, 0xd8, 0x31,
++	0x09, 0xee, 0xdc, 0x01,
++	0x80, 0xee, 0x46, 0x7c,
++	0x11, 0x6a, 0xdc, 0x01,
++	0x50, 0xee, 0x4a, 0x64,
++	0x20, 0x6a, 0xd0, 0x01,
++	0x09, 0x6a, 0xdc, 0x01,
++	0x88, 0xee, 0x50, 0x64,
++	0x19, 0x6a, 0xdc, 0x01,
++	0xd8, 0xee, 0x54, 0x64,
++	0xff, 0x6a, 0xdc, 0x09,
++	0x18, 0xee, 0x58, 0x6c,
++	0xff, 0x6a, 0xd4, 0x0c,
++	0x88, 0x6a, 0xcc, 0x00,
++	0x41, 0x6a, 0x1e, 0x5c,
++	0x20, 0x6a, 0x18, 0x01,
++	0xff, 0x6a, 0x1a, 0x09,
++	0xff, 0x6a, 0x1c, 0x09,
++	0xff, 0x35, 0x26, 0x09,
++	0x04, 0x35, 0x84, 0x6c,
++	0xa0, 0x6a, 0xca, 0x00,
++	0x20, 0x65, 0xc8, 0x18,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0xff, 0x6c, 0x32, 0x09,
++	0x00, 0x65, 0x6e, 0x64,
++	0x0a, 0x93, 0x26, 0x01,
++	0x00, 0x65, 0xc0, 0x44,
++	0xa0, 0x6a, 0xcc, 0x00,
++	0xe8, 0x6a, 0xc8, 0x00,
++	0x01, 0x94, 0x88, 0x6c,
++	0x10, 0x94, 0x8a, 0x6c,
++	0x08, 0x94, 0x9c, 0x6c,
++	0x08, 0x94, 0x9c, 0x6c,
++	0x08, 0x94, 0x9c, 0x6c,
++	0x00, 0x65, 0xb0, 0x5c,
++	0x08, 0x64, 0xc8, 0x18,
++	0x00, 0x8c, 0xca, 0x18,
++	0x00, 0x65, 0x92, 0x4c,
++	0x00, 0x65, 0x88, 0x44,
++	0xf7, 0x93, 0x26, 0x09,
++	0x08, 0x93, 0x9e, 0x6c,
++	0x00, 0x65, 0xb0, 0x5c,
++	0x08, 0x64, 0xc8, 0x18,
++	0x08, 0x64, 0xa0, 0x64,
++	0xff, 0x6a, 0xd4, 0x0c,
++	0x00, 0x65, 0xc0, 0x5c,
++	0x00, 0x65, 0xb0, 0x5c,
++	0x00, 0x65, 0xb0, 0x5c,
++	0x00, 0x65, 0xb0, 0x5c,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x08,
++	0xff, 0x99, 0xda, 0x0c,
++	0x08, 0x94, 0xc0, 0x7c,
++	0xf7, 0x93, 0x26, 0x09,
++	0x08, 0x93, 0xc4, 0x6c,
++	0xff, 0x6a, 0xd4, 0x0c,
++	0xff, 0x40, 0x74, 0x09,
++	0xff, 0x90, 0x80, 0x08,
++	0xff, 0x6a, 0x72, 0x05,
++	0xff, 0x40, 0xdc, 0x64,
++	0xff, 0x3f, 0xd4, 0x64,
++	0xff, 0x6a, 0xca, 0x04,
++	0xff, 0x3f, 0x20, 0x09,
++	0x01, 0x6a, 0x6a, 0x00,
++	0x00, 0xb9, 0x2e, 0x5c,
++	0xff, 0xba, 0x7e, 0x0c,
++	0xff, 0x40, 0x20, 0x09,
++	0xff, 0xba, 0x80, 0x0c,
++	0xff, 0x3f, 0x74, 0x09,
++	0xff, 0x90, 0x7e, 0x0c,
++};
++
++static int aic7xxx_patch14_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch14_func(struct aic7xxx_host *p)
++{
++	return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
++}
++
++static int aic7xxx_patch13_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch13_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_CMD_CHAN) == 0);
++}
++
++static int aic7xxx_patch12_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch12_func(struct aic7xxx_host *p)
++{
++	return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
++}
++
++static int aic7xxx_patch11_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch11_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_WIDE) != 0);
++}
++
++static int aic7xxx_patch10_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch10_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_ULTRA2) == 0);
++}
++
++static int aic7xxx_patch9_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch9_func(struct aic7xxx_host *p)
++{
++	return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
++}
++
++static int aic7xxx_patch8_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch8_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_ULTRA) != 0);
++}
++
++static int aic7xxx_patch7_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch7_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_ULTRA2) != 0);
++}
++
++static int aic7xxx_patch6_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch6_func(struct aic7xxx_host *p)
++{
++	return ((p->flags & AHC_PAGESCBS) == 0);
++}
++
++static int aic7xxx_patch5_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch5_func(struct aic7xxx_host *p)
++{
++	return ((p->flags & AHC_PAGESCBS) != 0);
++}
++
++static int aic7xxx_patch4_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch4_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_QUEUE_REGS) != 0);
++}
++
++static int aic7xxx_patch3_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch3_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_TWIN) != 0);
++}
++
++static int aic7xxx_patch2_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch2_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_QUEUE_REGS) == 0);
++}
++
++static int aic7xxx_patch1_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch1_func(struct aic7xxx_host *p)
++{
++	return ((p->features & AHC_CMD_CHAN) != 0);
++}
++
++static int aic7xxx_patch0_func(struct aic7xxx_host *p);
++
++static int
++aic7xxx_patch0_func(struct aic7xxx_host *p)
++{
++	return (0);
++}
++
++struct sequencer_patch {
++	int		(*patch_func)(struct aic7xxx_host *);
++	unsigned int	begin	   :10,
++			skip_instr :10,
++			skip_patch :12;
++} sequencer_patches[] = {
++	{ aic7xxx_patch1_func, 3, 2, 1 },
++	{ aic7xxx_patch2_func, 7, 1, 1 },
++	{ aic7xxx_patch2_func, 8, 1, 1 },
++	{ aic7xxx_patch3_func, 11, 4, 1 },
++	{ aic7xxx_patch4_func, 16, 3, 2 },
++	{ aic7xxx_patch0_func, 19, 4, 1 },
++	{ aic7xxx_patch5_func, 23, 1, 1 },
++	{ aic7xxx_patch6_func, 26, 1, 1 },
++	{ aic7xxx_patch1_func, 29, 1, 2 },
++	{ aic7xxx_patch0_func, 30, 3, 1 },
++	{ aic7xxx_patch3_func, 39, 4, 1 },
++	{ aic7xxx_patch7_func, 43, 3, 2 },
++	{ aic7xxx_patch0_func, 46, 3, 1 },
++	{ aic7xxx_patch8_func, 52, 7, 1 },
++	{ aic7xxx_patch3_func, 60, 3, 1 },
++	{ aic7xxx_patch7_func, 63, 2, 1 },
++	{ aic7xxx_patch7_func, 87, 1, 2 },
++	{ aic7xxx_patch0_func, 88, 1, 1 },
++	{ aic7xxx_patch7_func, 103, 1, 2 },
++	{ aic7xxx_patch0_func, 104, 2, 1 },
++	{ aic7xxx_patch7_func, 108, 84, 15 },
++	{ aic7xxx_patch9_func, 177, 1, 1 },
++	{ aic7xxx_patch9_func, 178, 4, 1 },
++	{ aic7xxx_patch0_func, 192, 72, 12 },
++	{ aic7xxx_patch1_func, 192, 1, 2 },
++	{ aic7xxx_patch0_func, 193, 2, 1 },
++	{ aic7xxx_patch1_func, 200, 1, 1 },
++	{ aic7xxx_patch1_func, 203, 3, 2 },
++	{ aic7xxx_patch0_func, 206, 5, 1 },
++	{ aic7xxx_patch1_func, 214, 1, 2 },
++	{ aic7xxx_patch0_func, 215, 3, 1 },
++	{ aic7xxx_patch1_func, 225, 14, 2 },
++	{ aic7xxx_patch0_func, 239, 9, 1 },
++	{ aic7xxx_patch1_func, 254, 2, 2 },
++	{ aic7xxx_patch0_func, 256, 4, 1 },
++	{ aic7xxx_patch1_func, 265, 3, 3 },
++	{ aic7xxx_patch10_func, 267, 1, 1 },
++	{ aic7xxx_patch0_func, 268, 5, 1 },
++	{ aic7xxx_patch10_func, 273, 1, 2 },
++	{ aic7xxx_patch0_func, 274, 9, 1 },
++	{ aic7xxx_patch11_func, 290, 1, 2 },
++	{ aic7xxx_patch0_func, 291, 1, 1 },
++	{ aic7xxx_patch4_func, 352, 1, 2 },
++	{ aic7xxx_patch0_func, 353, 1, 1 },
++	{ aic7xxx_patch2_func, 356, 1, 1 },
++	{ aic7xxx_patch1_func, 366, 3, 2 },
++	{ aic7xxx_patch0_func, 369, 5, 1 },
++	{ aic7xxx_patch11_func, 377, 1, 2 },
++	{ aic7xxx_patch0_func, 378, 1, 1 },
++	{ aic7xxx_patch5_func, 383, 1, 1 },
++	{ aic7xxx_patch10_func, 425, 15, 2 },
++	{ aic7xxx_patch12_func, 438, 1, 1 },
++	{ aic7xxx_patch1_func, 477, 7, 2 },
++	{ aic7xxx_patch0_func, 484, 8, 1 },
++	{ aic7xxx_patch1_func, 493, 4, 2 },
++	{ aic7xxx_patch0_func, 497, 6, 1 },
++	{ aic7xxx_patch1_func, 503, 4, 2 },
++	{ aic7xxx_patch0_func, 507, 3, 1 },
++	{ aic7xxx_patch13_func, 517, 10, 1 },
++	{ aic7xxx_patch1_func, 536, 22, 8 },
++	{ aic7xxx_patch10_func, 544, 4, 4 },
++	{ aic7xxx_patch0_func, 548, 7, 3 },
++	{ aic7xxx_patch14_func, 548, 5, 2 },
++	{ aic7xxx_patch0_func, 553, 2, 1 },
++	{ aic7xxx_patch0_func, 558, 50, 3 },
++	{ aic7xxx_patch12_func, 579, 17, 2 },
++	{ aic7xxx_patch0_func, 596, 4, 1 },
++	{ aic7xxx_patch13_func, 608, 4, 1 },
++	{ aic7xxx_patch5_func, 612, 2, 1 },
++	{ aic7xxx_patch5_func, 615, 9, 1 },
++
++};
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
+--- linux-2.2.17/drivers/scsi/aic7xxx.c	Mon Sep  4 13:39:21 2000
++++ linux/drivers/scsi/aic7xxx.c	Tue Feb  6 03:49:37 2001
+@@ -246,11 +246,11 @@
+ #include "sd.h"
+ #include "scsi.h"
+ #include "hosts.h"
+-#include "aic7xxx.h"
++#include "aic7xxx/aic7xxx.h"
+ 
+ #include "aic7xxx/sequencer.h"
+ #include "aic7xxx/scsi_message.h"
+-#include "aic7xxx_reg.h"
++#include "aic7xxx/aic7xxx_reg.h"
+ #include <scsi/scsicam.h>
+ 
+ #include <linux/stat.h>
+@@ -270,7 +270,7 @@
+     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ };
+ 
+-#define AIC7XXX_C_VERSION  "5.1.31"
++#define AIC7XXX_C_VERSION  "5.1.32"
+ 
+ #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
+ #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
+@@ -790,6 +790,7 @@
+ 
+ typedef enum {
+         SCB_FREE                = 0x0000,
++        SCB_DTR_SCB             = 0x0001,
+         SCB_WAITINGQ            = 0x0002,
+         SCB_ACTIVE              = 0x0004,
+         SCB_SENSE               = 0x0008,
+@@ -896,6 +897,17 @@
+   AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
+ } ahc_feature;
+ 
++typedef enum {
++  AHC_BUG_NONE            = 0x0000,
++  AHC_BUG_TMODE_WIDEODD   = 0x0001,
++  AHC_BUG_AUTOFLUSH       = 0x0002,
++  AHC_BUG_CACHETHEN       = 0x0004,
++  AHC_BUG_CACHETHEN_DIS   = 0x0008,
++  AHC_BUG_PCI_2_1_RETRY   = 0x0010,
++  AHC_BUG_PCI_MWI         = 0x0020,
++  AHC_BUG_SCBCHAN_UPLOAD  = 0x0040,
++} ahc_bugs;
++
+ struct aic7xxx_scb {
+         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
+         Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
+@@ -1004,7 +1016,6 @@
+   unsigned long            isr_count;        /* Interrupt count */
+   unsigned long            spurious_int;
+   scb_data_type           *scb_data;
+-  volatile unsigned short  needdv;
+   volatile unsigned short  needppr;
+   volatile unsigned short  needsdtr;
+   volatile unsigned short  needwdtr;
+@@ -1032,10 +1043,9 @@
+ #define  BUS_DEVICE_RESET_PENDING       0x02
+ #define  DEVICE_RESET_DELAY             0x04
+ #define  DEVICE_PRINT_DTR               0x08
+-#define  DEVICE_PARITY_ERROR            0x10
+-#define  DEVICE_WAS_BUSY                0x20
+-#define  DEVICE_SCSI_3                  0x40
+-#define  DEVICE_SCANNED                 0x80
++#define  DEVICE_WAS_BUSY                0x10
++#define  DEVICE_SCSI_3                  0x20
++#define  DEVICE_DTR_SCANNED             0x40
+   volatile unsigned char   dev_flags[MAX_TARGETS];
+   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
+   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
+@@ -1051,10 +1061,6 @@
+ #endif
+ 
+ 
+-  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
+-
+-  unsigned int             dev_checksum[MAX_TARGETS];
+-  
+   unsigned char            dev_last_queue_full[MAX_TARGETS];
+   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+   unsigned char            dev_max_queue_depth[MAX_TARGETS];
+@@ -1111,6 +1117,7 @@
+   int                      host_no;          /* SCSI host number */
+   unsigned long            mbase;            /* I/O memory address */
+   ahc_chip                 chip;             /* chip type */
++  ahc_bugs                 bugs;             /* hardware bugs this chip has */
+ 
+   /*
+    * Statistics Kept:
+@@ -1712,7 +1719,7 @@
+  * prototype, our code has to be ordered that way, it's a left-over from
+  * the original driver days.....I should fix it some time DL).
+  */
+-#include "aic7xxx_seq.c"
++#include "aic7xxx/aic7xxx_seq.c"
+ 
+ /*+F*************************************************************************
+  * Function:
+@@ -2876,138 +2883,98 @@
+   {
+     p->flags &= ~AHC_ABORT_PENDING;
+   }
+-  if (scb->flags & SCB_RESET)
++  if (scb->flags & (SCB_RESET|SCB_ABORT))
+   {
+-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
++    cmd->result |= (DID_RESET << 16);
+   }
+-  else if (scb->flags & SCB_ABORT)
+-  {
+-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+-  }
+-  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
++
++  if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
+   {
+     if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
+     {
+-      char *buffer;
+-      
++    
+       p->dev_flags[tindex] |= DEVICE_PRESENT;
+-      if(cmd->use_sg)
+-      {
+-        struct scatterlist *sg;
+-
+-        sg = (struct scatterlist *)cmd->request_buffer;
+-        buffer = (char *)sg[0].address;
+-      }
+-      else
+-      {
+-        buffer = (char *)cmd->request_buffer;
+-      }
+ #define WIDE_INQUIRY_BITS 0x60
+ #define SYNC_INQUIRY_BITS 0x10
+ #define SCSI_VERSION_BITS 0x07
+ #define SCSI_DT_BIT       0x04
+-      if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+-           (p->features & AHC_WIDE) )
+-      {
+-        p->needwdtr |= (1<<tindex);
+-        p->needwdtr_copy |= (1<<tindex);
+-        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+-      }
+-      else
+-      {
+-        p->needwdtr &= ~(1<<tindex);
+-        p->needwdtr_copy &= ~(1<<tindex);
+-        pause_sequencer(p);
+-        aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+-                          MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+-                                                   AHC_TRANS_GOAL |
+-                                                   AHC_TRANS_CUR) );
+-        unpause_sequencer(p, FALSE);
+-      }
+-      if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+-            p->transinfo[tindex].user_offset )
+-      {
+-        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+-        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+-        if (p->features & AHC_ULTRA2)
+-          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+-        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+-          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
++      if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
++        char *buffer;
++
++        if(cmd->use_sg)
++        {
++          struct scatterlist *sg;
++
++          sg = (struct scatterlist *)cmd->request_buffer;
++          buffer = (char *)sg[0].address;
++        }
++        else
++        {
++          buffer = (char *)cmd->request_buffer;
++        }
++
++
++        if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
++             (p->features & AHC_WIDE) )
++        {
++          p->needwdtr |= (1<<tindex);
++          p->needwdtr_copy |= (1<<tindex);
++          p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
++        }
+         else
+-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+-        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
+-               (buffer[56] & SCSI_DT_BIT) ||
+-	       (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+-               (p->transinfo[tindex].user_period <= 9) &&
+-               (p->transinfo[tindex].user_options) )
+         {
+-          p->needppr |= (1<<tindex);
+-          p->needppr_copy |= (1<<tindex);
+-          p->needsdtr &= ~(1<<tindex);
+-          p->needsdtr_copy &= ~(1<<tindex);
+           p->needwdtr &= ~(1<<tindex);
+           p->needwdtr_copy &= ~(1<<tindex);
+-          p->dev_flags[tindex] |= DEVICE_SCSI_3;
++          pause_sequencer(p);
++          aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
++                            MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
++                                                     AHC_TRANS_GOAL |
++                                                     AHC_TRANS_CUR) );
++          unpause_sequencer(p, FALSE);
+         }
+-        else
++        if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
++              p->transinfo[tindex].user_offset )
+         {
+-          p->needsdtr |= (1<<tindex);
+-          p->needsdtr_copy |= (1<<tindex);
+-          p->transinfo[tindex].goal_period = 
+-            MAX(10, p->transinfo[tindex].goal_period);
+-          p->transinfo[tindex].goal_options = 0;
++          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
++          p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
++          if (p->features & AHC_ULTRA2)
++            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
++          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
++            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
++          else
++            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
++          if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
++                 (buffer[56] & SCSI_DT_BIT) ||
++                 (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
++                 (p->transinfo[tindex].user_period <= 9) &&
++                 (p->transinfo[tindex].user_options) )
++          {
++            p->needppr |= (1<<tindex);
++            p->needppr_copy |= (1<<tindex);
++            p->needsdtr &= ~(1<<tindex);
++            p->needsdtr_copy &= ~(1<<tindex);
++            p->needwdtr &= ~(1<<tindex);
++            p->needwdtr_copy &= ~(1<<tindex);
++            p->dev_flags[tindex] |= DEVICE_SCSI_3;
++          }
++          else
++          {
++            p->needsdtr |= (1<<tindex);
++            p->needsdtr_copy |= (1<<tindex);
++            p->transinfo[tindex].goal_period = 
++              MAX(10, p->transinfo[tindex].goal_period);
++            p->transinfo[tindex].goal_options = 0;
++          }
+         }
+-      }
+-      else
+-      {
+-        p->needsdtr &= ~(1<<tindex);
+-        p->needsdtr_copy &= ~(1<<tindex);
+-        p->transinfo[tindex].goal_period = 255;
+-        p->transinfo[tindex].goal_offset = 0;
+-        p->transinfo[tindex].goal_options = 0;
+-      }
+-      /*
+-       * This is needed to work around a sequencer bug for now.  Regardless
+-       * of the controller in use, if we have a Quantum drive, we need to
+-       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
+-       * of the sequencer, this code will get yanked.
+-       */
+-      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
+-         p->transinfo[tindex].goal_options )
+-      {
+-        p->transinfo[tindex].goal_period = 
+-          MAX(p->transinfo[tindex].goal_period, 10);
+-        p->transinfo[tindex].goal_options = 0;
+-        p->needppr &= ~(1<<tindex);
+-        p->needppr_copy &= ~(1<<tindex);
+-        p->needsdtr |= (1<<tindex);
+-        p->needsdtr_copy |= (1<<tindex);
+-        p->needwdtr |= (1<<tindex);
+-        p->needwdtr_copy |= (1<<tindex);
+-      }
+-      /*
+-       * Get the INQUIRY checksum.  We use this on Ultra 160/m
+-       * and older devices both.  It allows us to drop speed on any bus type
+-       * while at the same time giving us the needed domain validation for
+-       * Ultra 160/m
+-       *
+-       * Note: We only get the checksum and set the SCANNED bit if this is
+-       * one of our dtr commands.  If we don't do this, then we end up
+-       * getting bad checksum results on the mid-level SCSI code's INQUIRY
+-       * commands.
+-       */
+-      if(p->dev_dtr_cmnd[tindex] == cmd) {
+-        unsigned int checksum = 0;
+-        int *ibuffer;
+-        int i=0;
+-
+-        ibuffer = (int *)buffer;
+-        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
++        else
+         {
+-          checksum += ibuffer[i];
++          p->needsdtr &= ~(1<<tindex);
++          p->needsdtr_copy &= ~(1<<tindex);
++          p->transinfo[tindex].goal_period = 255;
++          p->transinfo[tindex].goal_offset = 0;
++          p->transinfo[tindex].goal_options = 0;
+         }
+-        p->dev_checksum[tindex] = checksum;
+-        p->dev_flags[tindex] |= DEVICE_SCANNED;
++        p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
+         p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
+       }
+ #undef WIDE_INQUIRY_BITS
+@@ -3016,7 +2983,8 @@
+ #undef SCSI_DT_BIT
+     }
+   }
+-  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
++
++  if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+   {
+     unsigned short mask;
+     int message_error = FALSE;
+@@ -3036,7 +3004,6 @@
+ 
+     if (scb->flags & SCB_MSGOUT_WDTR)
+     {
+-      p->dtr_pending &= ~mask;
+       if (message_error)
+       {
+         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+@@ -3055,7 +3022,6 @@
+     }
+     if (scb->flags & SCB_MSGOUT_SDTR)
+     {
+-      p->dtr_pending &= ~mask;
+       if (message_error)
+       {
+         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+@@ -3075,7 +3041,6 @@
+     }
+     if (scb->flags & SCB_MSGOUT_PPR)
+     {
+-      p->dtr_pending &= ~mask;
+       if(message_error)
+       {
+         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+@@ -3100,6 +3065,7 @@
+       }
+     }
+   }
++
+   queue_depth = p->dev_temp_queue_depth[tindex];
+   if (queue_depth >= p->dev_active_cmds[tindex])
+   {
+@@ -3133,9 +3099,18 @@
+       }
+     }
+   }
+-  if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
++  if (!(scb->tag_action))
++  {
++    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
++                              /* unbusy */ TRUE);
++    if (p->tagenable & (1<<tindex))
++    {
++      p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
++    }
++  }
++  if(scb->flags & SCB_DTR_SCB)
+   {
+-    p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
++    p->dtr_pending &= ~(1 << tindex);
+   }
+   p->dev_active_cmds[tindex]--;
+   p->activescbs--;
+@@ -3244,6 +3219,14 @@
+         printk(INFO_LEAD "Aborting scb %d\n",
+              p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+       found++;
++      /*
++       * Clear any residual information since the normal aic7xxx_done() path
++       * doesn't touch the residuals.
++       */
++      scb->hscb->residual_SG_segment_count = 0;
++      scb->hscb->residual_data_count[0] = 0;
++      scb->hscb->residual_data_count[1] = 0;
++      scb->hscb->residual_data_count[2] = 0;
+       aic7xxx_done(p, scb);
+     }
+   }
+@@ -3456,8 +3439,22 @@
+   active_scb = aic_inb(p, SCBPTR);
+ 
+   if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
++  {
+     printk(INFO_LEAD "Reset device, active_scb %d\n",
+          p->host_no, channel, target, lun, active_scb);
++    printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
++           "0x%x\n",
++         p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
++         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
++         aic_inb(p, LASTPHASE));
++    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
++         p->host_no, channel, target, lun,
++         (p->features & AHC_ULTRA2) ?  aic_inb(p, SG_CACHEPTR) : 0,
++         aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
++    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
++         p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
++         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
++  }
+   /*
+    * Deal with the busy target and linked next issues.
+    */
+@@ -3501,11 +3498,11 @@
+       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+         printk(INFO_LEAD "Cleaning up status information "
+           "and delayed_scbs.\n", p->host_no, channel, i, lun);
+-      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
++      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+       if ( tag == SCB_LIST_NULL )
+       {
+         p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
+-        p->dev_expires[i] = jiffies + (4 * HZ);
++        p->dev_expires[i] = jiffies + (1 * HZ);
+         p->dev_timer_active |= (0x01 << i);
+         p->dev_last_queue_full_count[i] = 0;
+         p->dev_last_queue_full[i] = 0;
+@@ -3550,7 +3547,7 @@
+           prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+         }
+       }
+-      if ( j > (p->scb_data->maxscbs + 1) )
++      if ( j > (p->scb_data->numscbs + 1) )
+       {
+         if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+           printk(WARN_LEAD "Yikes!! There's a loop in the "
+@@ -3611,7 +3608,7 @@
+         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+       }
+     }
+-    if ( j > (p->scb_data->maxscbs + 1) )
++    if ( j > (p->scb_data->numscbs + 1) )
+     {
+       if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
+         printk(WARN_LEAD "Yikes!! There's a loop in the "
+@@ -4375,11 +4372,25 @@
+     if (actual < cmd->underflow)
+     {
+       if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
++      {
+         printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+           "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+           (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
+           hscb->residual_SG_segment_count);
++        printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
++          hscb->target_status);
++      }
++      /*
++       * In 2.4, only send back the residual information, don't flag this
++       * as an error.  Before 2.4 we had to flag this as an error because
++       * the mid layer didn't check residual data counts to see if the
++       * command needs retried.
++       */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
++      cmd->resid = scb->sg_length - actual;
++#else
+       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
++#endif
+       aic7xxx_status(cmd) = hscb->target_status;
+     }
+   }
+@@ -4698,7 +4709,6 @@
+            */
+           p->needwdtr &= ~target_mask;
+           p->needwdtr_copy &= ~target_mask;
+-          p->dtr_pending &= ~target_mask;
+           scb->flags &= ~SCB_MSGOUT_BITS;
+           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+             (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
+@@ -4718,8 +4728,7 @@
+           */
+           p->needsdtr &= ~target_mask;
+           p->needsdtr_copy &= ~target_mask;
+-          p->dtr_pending &= ~target_mask;
+-          scb->flags &= ~SCB_MSGOUT_SDTR;
++          scb->flags &= ~SCB_MSGOUT_BITS;
+           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+             (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+@@ -4852,6 +4861,8 @@
+                 aic7xxx_error(cmd) = DID_OK;
+                 break;
+               }  /* first time sense, no errors */
++              printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
++                     "an error.\n", p->host_no, CTL_OF_SCB(scb));
+               aic7xxx_error(cmd) = DID_ERROR;
+               scb->flags &= ~SCB_SENSE;
+               break;
+@@ -5214,12 +5225,21 @@
+           printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+             (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+             scb->sg_length, scb->sg_count);
+-          for (i = 0; i < scb->sg_count; i++)
++          printk(KERN_WARNING "  Raw SCSI Command: 0x");
++          for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
++          {
++            printk("%02x ", scb->cmd->cmnd[i]);
++          }
++          printk("\n");
++          if(aic7xxx_verbose > 0xffff)
+           {
+-            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
++            for (i = 0; i < scb->sg_count; i++)
++            {
++              printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                  i, 
+                  le32_to_cpu(scb->sg_list[i].address),
+                  le32_to_cpu(scb->sg_list[i].length) );
++            }
+           }
+           aic7xxx_error(scb->cmd) = DID_ERROR;
+         }
+@@ -5234,7 +5254,7 @@
+         unsigned char resid_sgcnt, index;
+         unsigned char scb_index = aic_inb(p, SCB_TAG);
+         unsigned int cur_addr, resid_dcnt;
+-        unsigned int native_addr, native_length;
++        unsigned int native_addr, native_length, sg_addr;
+         int i;
+ 
+         if(scb_index > p->scb_data->numscbs)
+@@ -5254,6 +5274,9 @@
+                  scb->flags, (unsigned int)scb->cmd);
+           break;
+         }
++        if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
++          printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
++                 "pointer.\n", p->host_no, CTL_OF_SCB(scb));
+ 
+         /*
+          * We have a valid scb to use on this WIDE_RESIDUE message, so
+@@ -5266,132 +5289,87 @@
+          */
+         cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
+           (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
++        sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
++          (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24);
+         resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
+         resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
+           (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
+           (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
+-        index = scb->sg_count - (resid_sgcnt + 1);
++        index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
+         native_addr = le32_to_cpu(scb->sg_list[index].address);
+         native_length = le32_to_cpu(scb->sg_list[index].length);
+         /*
+-         * Make sure this is a valid sg_seg for the given pointer
++         * If resid_dcnt == native_length, then we just loaded this SG
++         * segment and we need to back it up one...
+          */
+-        if(cur_addr < native_addr ||
+-           cur_addr > (native_addr + native_length + 1))
+-        {
+-          printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
+-                 p->host_no, CTL_OF_SCB(scb), cur_addr);
+-          if(index > 0)
+-            printk(WARN_LEAD "  sg_address[-1]:0x%x sg_length[-1]:%d\n",
+-                   p->host_no, CTL_OF_SCB(scb),
+-                   le32_to_cpu(scb->sg_list[index - 1].address),
+-                   le32_to_cpu(scb->sg_list[index - 1].length));
+-          printk(WARN_LEAD "  sg_address:0x%x sg_length:%d\n",
+-                 p->host_no, CTL_OF_SCB(scb),
+-                 native_addr, native_length);
+-          if(resid_sgcnt > 1)
+-            printk(WARN_LEAD "  sg_address[1]:0x%x sg_length[1]:%d\n",
+-                   p->host_no, CTL_OF_SCB(scb),
+-                   le32_to_cpu(scb->sg_list[index + 1].address),
+-                   le32_to_cpu(scb->sg_list[index + 1].length));
+-          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
+-                 p->host_no, CTL_OF_SCB(scb),
+-                 cur_addr, resid_dcnt);
+-          break;
+-        }
+-
+-        if( (resid_sgcnt == 0) &&
+-            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
++        if(resid_dcnt == native_length)
+         {
+-          /*
+-           * We are at the end of the transfer and this is about a byte
+-           * we ignored already (because the sequencer knew this was
+-           * the last segment and set the adapter to ignore any wide
+-           * residue bytes that might come through, which is only done
+-           * on the last scatter gather segment of transfers).
+-           */
+-          break;
+-        }
+-        else if(cur_addr == native_addr)
+-        {
+-          /*
+-           * If our current address matches the sg_seg->address then we
+-           * have to back up the sg array to the previous segment and set
+-           * it up to have only one byte of transfer left to go.
+-           */
+           if(index == 0)
+           {
+-            printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
+-                   "transferred.\n", p->host_no, CTL_OF_SCB(scb));
++            /*
++             * Oops, this isn't right, we can't back up to before the
++             * beginning.  This must be a bogus message, ignore it.
++             */
+             break;
+           }
+-          resid_sgcnt++;
+-          index--;
+-          cur_addr = le32_to_cpu(scb->sg_list[index].address) + 
+-            le32_to_cpu(scb->sg_list[index].length) - 1;
+-          native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
+-            | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
+-          native_addr -= SG_SIZEOF;
+-          aic_outb(p, resid_sgcnt, SG_COUNT);
+-          aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+-          aic_outb(p, native_addr & 0xff, SG_NEXT);
+-          aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
+-          aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
+-          aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
+-          aic_outb(p, 1, SCB_RESID_DCNT); 
+-          aic_outb(p, 0, SCB_RESID_DCNT + 1); 
+-          aic_outb(p, 0, SCB_RESID_DCNT + 2); 
+-          aic_outb(p, 1, HCNT); 
+-          aic_outb(p, 0, HCNT + 1); 
+-          aic_outb(p, 0, HCNT + 2); 
+-          aic_outb(p, cur_addr & 0xff, HADDR);
+-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
++          resid_dcnt = 1;
++          resid_sgcnt += 1;
++          native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
++          native_length = le32_to_cpu(scb->sg_list[index - 1].length);
++          cur_addr = native_addr + (native_length - 1);
++          sg_addr -= sizeof(struct hw_scatterlist);
+         }
+         else
+         {
+           /*
+-           * Back the data pointer up by one and add one to the remaining
+-           * byte count.  Then store that in the HCNT and HADDR registers.
++           * resid_dcnt != native_length, so we are in the middle of a SG
++           * element.  Back it up one byte and leave the rest alone.
+            */
+-          cur_addr--;
+-          resid_dcnt++;
+-          aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); 
+-          aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); 
+-          aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); 
+-          aic_outb(p, resid_dcnt & 0xff, HCNT); 
+-          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); 
+-          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); 
+-          aic_outb(p, cur_addr & 0xff, HADDR);
+-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
++          resid_dcnt += 1;
++          cur_addr -= 1;
+         }
++        
++        /*
++         * Output the new addresses and counts to the right places on the
++         * card.
++         */
++        aic_outb(p, resid_sgcnt, SG_COUNT);
++        aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
++        aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
++        aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
++        aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
++        aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
++        aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
++        aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
++        aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
++
+         /*
+-         * The sequencer actually wants to find the new address and byte
+-         * count in the SHCNT and SHADDR register sets.  These registers
+-         * are a shadow of the regular HCNT and HADDR registers.  On the
+-         * Ultra2 controllers, these registers are read only and the way
+-         * we have to set their values is to put the values we want into
+-         * the HCNT and HADDR registers and then output PRELOADEN into
+-         * the DFCNTRL register which causes the card to latch the current
+-         * values in the HADDR and HCNT registers and drop it through to
+-         * the shadow registers.  On older cards we copy them directly
+-         * across by hand.
++         * The sequencer actually wants to find the new address
++         * in the SHADDR register set.  On the Ultra2 and later controllers
++         * this register set is readonly.  In order to get the right number
++         * into the register, you actually have to enter it in HADDR and then
++         * use the PRELOADEN bit of DFCNTRL to drop it through from the
++         * HADDR register to the SHADDR register.  On non-Ultra2 controllers,
++         * we simply write it direct.
+          */
+         if(p->features & AHC_ULTRA2)
+         {
+-          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+-          i=0;
++          /*
++           * We might as well be accurate and drop both the resid_dcnt and
++           * cur_addr into HCNT and HADDR and have both of them drop
++           * through to the shadow layer together.
++           */
++          aic_outb(p, resid_dcnt & 0xff, HCNT);
++          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
++          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
++          aic_outb(p, cur_addr & 0xff, HADDR);
++          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
++          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
++          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
++          aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
+           udelay(1);
+-          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
+-          {
+-            udelay(1);
+-          }
+           aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
+           i=0;
+-          udelay(1);
+           while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
+           {
+             udelay(1);
+@@ -5399,9 +5377,6 @@
+         }
+         else
+         {
+-          aic_outb(p, resid_dcnt & 0xff, STCNT); 
+-          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
+-          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
+           aic_outb(p, cur_addr & 0xff, SHADDR);
+           aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+           aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+@@ -5410,15 +5385,82 @@
+       }
+       break;
+ 
+-        
+-#if AIC7XXX_NOT_YET 
+-    case TRACEPOINT:
++    case SEQ_SG_FIXUP:
++    {
++      unsigned char scb_index, tmp;
++      int sg_addr, sg_length;
++
++      scb_index = aic_inb(p, SCB_TAG);
++
++      if(scb_index > p->scb_data->numscbs)
+       {
+-        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
+-               channel, target, lun);
++        printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
++          p->host_no, -1, -1, -1);
++        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
++           "0x%x\n", p->host_no, -1, -1, -1,
++           aic_inb(p, SCSISIGI),
++           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
++           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
++        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
++           p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
++           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
++           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
++        /*
++         * XXX: Add error handling here
++         */
++        break;
+       }
+-      break;
++      scb = p->scb_data->scb_array[scb_index];
++      if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
++      {
++        printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
++               "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
++               scb->flags, (unsigned int)scb->cmd);
++        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
++           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
++           aic_inb(p, SCSISIGI),
++           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
++           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
++        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
++           p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
++           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
++           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
++        break;
++      }
++      if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
++        printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
++               CTL_OF_SCB(scb));
++      /*
++       * Advance the SG pointer to the next element in the list
++       */
++      tmp = aic_inb(p, SG_NEXT);
++      tmp += SG_SIZEOF;
++      aic_outb(p, tmp, SG_NEXT);
++      if( tmp < SG_SIZEOF )
++        aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
++      tmp = aic_inb(p, SG_COUNT) - 1;
++      aic_outb(p, tmp, SG_COUNT);
++      sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
++      sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
++      /*
++       * Now stuff the element we just advanced past down onto the
++       * card so it can be stored in the residual area.
++       */
++      aic_outb(p, sg_addr & 0xff, HADDR);
++      aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
++      aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
++      aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
++      aic_outb(p, sg_length & 0xff, HCNT);
++      aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
++      aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
++      aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
++      aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
++      while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
++      while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
++    }
++    break;
+ 
++#if AIC7XXX_NOT_YET 
+     case TRACEPOINT2:
+       {
+         printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+@@ -5463,6 +5505,10 @@
+   unsigned char target_scsirate, tindex;
+   unsigned short target_mask;
+   unsigned char target, channel, lun;
++  unsigned char bus_width, new_bus_width;
++  unsigned char trans_options, new_trans_options;
++  unsigned int period, new_period, offset, new_offset, maxsync;
++  struct aic7xxx_syncrate *syncrate;
+ 
+   target = scb->cmd->target;
+   channel = scb->cmd->channel;
+@@ -5486,6 +5532,35 @@
+   }
+ 
+   /*
++   * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
++   * using the SDTR messages.  We need the PPR messages to enable the
++   * higher speeds that include things like Dual Edge clocking.
++   */
++  if (p->features & AHC_ULTRA2)
++  {
++    if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
++         !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
++    {
++      if (p->features & AHC_ULTRA3)
++        maxsync = AHC_SYNCRATE_ULTRA3;
++      else
++        maxsync = AHC_SYNCRATE_ULTRA2;
++    }
++    else
++    {
++      maxsync = AHC_SYNCRATE_ULTRA;
++    }
++  }
++  else if (p->features & AHC_ULTRA)
++  {
++    maxsync = AHC_SYNCRATE_ULTRA;
++  }
++  else
++  {
++    maxsync = AHC_SYNCRATE_FAST;
++  }
++
++  /*
+    * Just accept the length byte outright and perform
+    * more checking once we know the message type.
+    */
+@@ -5496,9 +5571,6 @@
+     {
+       case MSG_EXT_SDTR:
+       {
+-        unsigned int period, offset;
+-        unsigned char maxsync, saved_offset, options;
+-        struct aic7xxx_syncrate *syncrate;
+         
+         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+         {
+@@ -5511,35 +5583,18 @@
+           break;
+         }
+ 
+-        period = p->msg_buf[3];
+-        saved_offset = offset = p->msg_buf[4];
+-        options = 0;
++        period = new_period = p->msg_buf[3];
++        offset = new_offset = p->msg_buf[4];
++        trans_options = new_trans_options = 0;
++        bus_width = new_bus_width = target_scsirate & WIDEXFER;
+ 
+         /*
+-         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+-         * using the SDTR messages.  We need the PPR messages to enable the
+-         * higher speeds that include things like Dual Edge clocking.
++         * If our current max syncrate is in the Ultra3 range, bump it back
++         * down to Ultra2 since we can't negotiate DT transfers using SDTR
+          */
+-        if (p->features & AHC_ULTRA2)
+-        {
+-          if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+-               !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+-          {
+-            maxsync = AHC_SYNCRATE_ULTRA2;
+-          }
+-          else
+-          {
+-            maxsync = AHC_SYNCRATE_ULTRA;
+-          }
+-        }
+-        else if (p->features & AHC_ULTRA)
+-        {
+-          maxsync = AHC_SYNCRATE_ULTRA;
+-        }
+-        else
+-        {
+-          maxsync = AHC_SYNCRATE_FAST;
+-        }
++        if(maxsync == AHC_SYNCRATE_ULTRA3)
++          maxsync = AHC_SYNCRATE_ULTRA2;
++
+         /*
+          * We might have a device that is starting negotiation with us
+          * before we can start up negotiation with it....be prepared to
+@@ -5549,88 +5604,116 @@
+         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
+         {
+-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
+-              !(p->needsdtr_copy & target_mask) &&
+-               (p->transinfo[tindex].user_offset) )
++          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
+           {
+             /*
+-             * Not only is the device starting this up, but it also hasn't
+-             * been scanned yet, so this would likely be our TUR or our
+-             * INQUIRY command at scan time, so we need to use the
+-             * settings from the SEEPROM if they existed.  Of course, even
+-             * if we didn't find a SEEPROM, we stuffed default values into
+-             * the user settings anyway, so use those in all cases.
++             * We shouldn't get here unless this is a narrow drive, wide
++             * devices should trigger this same section of code in the WDTR
++             * handler first instead.
+              */
+-            p->transinfo[tindex].goal_period =
+-              p->transinfo[tindex].user_period;
+-            if(p->features & AHC_ULTRA2)
+-            {
+-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+-            }
+-            else if (p->transinfo[tindex].cur_width)
++            p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
++            p->transinfo[tindex].goal_options = 0;
++            if(p->transinfo[tindex].user_offset)
+             {
+-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
++              p->needsdtr_copy |= target_mask;
++              p->transinfo[tindex].goal_period =
++                MAX(10,p->transinfo[tindex].user_period);
++              if(p->features & AHC_ULTRA2)
++              {
++                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
++              }
++              else
++              {
++                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
++              }
+             }
+             else
+             {
+-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
++              p->needsdtr_copy &= ~target_mask;
++              p->transinfo[tindex].goal_period = 255;
++              p->transinfo[tindex].goal_offset = 0;
+             }
+-            p->needsdtr_copy |= target_mask;
++            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
++          }
++          else if ((p->needsdtr_copy & target_mask) == 0)
++          {
++            /*
++             * This is a preemptive message from the target, we've already
++             * scanned this target and set our options for it, and we
++             * don't need a WDTR with this target (for whatever reason),
++             * so reject this incoming WDTR
++             */
++            reject = TRUE;
++            break;
+           }
++
++          /* The device is sending this message first and we have to reply */
++          reply = TRUE;
++          
+           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+           {
+             printk(INFO_LEAD "Received pre-emptive SDTR message from "
+                    "target.\n", p->host_no, CTL_OF_SCB(scb));
+           }
+-          if ( !p->transinfo[tindex].goal_offset )
+-            period = 255;
+-          if ( p->transinfo[tindex].goal_period > period )
+-            period = p->transinfo[tindex].goal_period;
++          /*
++           * Validate the values the device passed to us against our SEEPROM
++           * settings.  We don't have to do this if we aren't replying since
++           * the device isn't allowed to send values greater than the ones
++           * we first sent to it.
++           */
++          new_period = MAX(period, p->transinfo[tindex].goal_period);
++          new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
+         }
+-  
+-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
+-        aic7xxx_validate_offset(p, syncrate, &offset,
+-                                target_scsirate & WIDEXFER);
+-        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+-                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++ 
++        /*
++         * Use our new_period, new_offset, bus_width, and card options
++         * to determine the actual syncrate settings
++         */
++        syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
++                                         &trans_options);
++        aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
+ 
+         /*
+-         * Did we drop to async?  Or are we sending a reply?  If we are,
+-         * then we have to make sure that the reply value reflects the proper
+-         * settings so we need to set the goal values according to what
+-         * we need to send.
++         * Did we drop to async?  If so, send a reply regardless of whether
++         * or not we initiated this negotiation.
+          */
+-        if ( (offset != saved_offset) ||
+-             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
++        if ((new_offset == 0) && (new_offset != offset))
+         {
+-          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
+-                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
++          p->needsdtr_copy &= ~target_mask;
++          reply = TRUE;
+         }
+         
+         /*
+-         * Did we start this, if not, or if we went to low and had to
++         * Did we start this, if not, or if we went too low and had to
+          * go async, then send an SDTR back to the target
+          */
+-        p->needsdtr &= ~target_mask;
+-        p->dtr_pending &= ~target_mask;
+-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
+-             (offset != saved_offset) )
++        if(reply)
+         {
+-          reply = TRUE;
+-          p->dtr_pending |= target_mask;
++          /* when sending a reply, make sure that the goal settings are
++           * updated along with current and active since the code that
++           * will actually build the message for the sequencer uses the
++           * goal settings as its guidelines.
++           */
++          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
++                               new_offset, trans_options,
++                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+           scb->flags &= ~SCB_MSGOUT_BITS;
+           scb->flags |= SCB_MSGOUT_SDTR;
+           aic_outb(p, HOST_MSG, MSG_OUT);
+           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+         }
++        else
++        {
++          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
++                               new_offset, trans_options,
++                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++          p->needsdtr &= ~target_mask;
++        }
+         done = TRUE;
+         break;
+       }
+       case MSG_EXT_WDTR:
+       {
+-        unsigned char bus_width;
+           
+         if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+         {
+@@ -5643,7 +5726,8 @@
+           break;
+         }
+ 
+-        bus_width = p->msg_buf[3];
++        bus_width = new_bus_width = p->msg_buf[3];
++
+         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
+         {
+@@ -5662,7 +5746,7 @@
+             } /* We fall through on purpose */
+             case MSG_EXT_WDTR_BUS_8_BIT:
+             {
+-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
++              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+               p->needwdtr_copy &= ~target_mask;
+               break;
+             }
+@@ -5671,29 +5755,40 @@
+               break;
+             }
+           }
+-          p->dtr_pending &= ~target_mask;
+           p->needwdtr &= ~target_mask;
++          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
++                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+         }
+         else
+         {
+-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
++          if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
+           {
+             /* 
+              * Well, we now know the WDTR and SYNC caps of this device since
+              * it contacted us first, mark it as such and copy the user stuff
+              * over to the goal stuff.
+              */
+-            p->transinfo[tindex].goal_period =
+-              p->transinfo[tindex].user_period;
++            if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
++            {
++              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
++              p->needwdtr_copy |= target_mask;
++            }
++            
++            /*
++             * Devices that support DT transfers don't start WDTR requests
++             */
++            p->transinfo[tindex].goal_options = 0;
++
+             if(p->transinfo[tindex].user_offset)
+             {
++              p->needsdtr_copy |= target_mask;
++              p->transinfo[tindex].goal_period =
++                MAX(10,p->transinfo[tindex].user_period);
+               if(p->features & AHC_ULTRA2)
+               {
+                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+               }
+-              else if( p->transinfo[tindex].user_width &&
+-                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+-                       p->features & AHC_WIDE )
++              else if( p->transinfo[tindex].goal_width )
+               {
+                 p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+               }
+@@ -5701,48 +5796,76 @@
+               {
+                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+               }
++            } else {
++              p->needsdtr_copy &= ~target_mask;
++              p->transinfo[tindex].goal_period = 255;
++              p->transinfo[tindex].goal_offset = 0;
+             }
+-            p->transinfo[tindex].goal_width =
+-              p->transinfo[tindex].user_width;
+-            p->needwdtr_copy |= target_mask;
+-            p->needsdtr_copy |= target_mask;
++            
++            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+           }
+-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
++          else if ((p->needwdtr_copy & target_mask) == 0)
+           {
+-            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+-                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+-          }
++            /*
++             * This is a preemptive message from the target, we've already
++             * scanned this target and set our options for it, and we
++             * don't need a WDTR with this target (for whatever reason),
++             * so reject this incoming WDTR
++             */
++            reject = TRUE;
++            break;
++          }
++
++          /* The device is sending this message first and we have to reply */
++          reply = TRUE;
++
++          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
++          {
++            printk(INFO_LEAD "Received pre-emptive WDTR message from "
++                   "target.\n", p->host_no, CTL_OF_SCB(scb));
++          }
+           switch(bus_width)
+           {
+-            default:
++            case MSG_EXT_WDTR_BUS_16_BIT:
+             {
+               if ( (p->features & AHC_WIDE) &&
+                    (p->transinfo[tindex].goal_width ==
+                     MSG_EXT_WDTR_BUS_16_BIT) )
+               {
+-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
++                new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                 break;
+               }
+             } /* Fall through if we aren't a wide card */
++            default:
+             case MSG_EXT_WDTR_BUS_8_BIT:
+             {
+               p->needwdtr_copy &= ~target_mask;
+-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+-              aic7xxx_set_width(p, target, channel, lun, bus_width,
+-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
++              new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+               break;
+             }
+           }
+-          reply = TRUE;
+           scb->flags &= ~SCB_MSGOUT_BITS;
+           scb->flags |= SCB_MSGOUT_WDTR;
+           p->needwdtr &= ~target_mask;
+-          p->dtr_pending |= target_mask;
++          if((p->dtr_pending & target_mask) == 0)
++          {
++            /* there is no other command with SCB_DTR_SCB already set that will
++             * trigger the release of the dtr_pending bit.  Both set the bit
++             * and set scb->flags |= SCB_DTR_SCB
++             */
++            p->dtr_pending |= target_mask;
++            scb->flags |= SCB_DTR_SCB;
++          }
+           aic_outb(p, HOST_MSG, MSG_OUT);
+           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
++          /* when sending a reply, make sure that the goal settings are
++           * updated along with current and active since the code that
++           * will actually build the message for the sequencer uses the
++           * goal settings as its guidelines.
++           */
++          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
++                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+         }
+-        aic7xxx_set_width(p, target, channel, lun, bus_width,
+-                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+         
+         /*
+          * By virtue of the SCSI spec, a WDTR message negates any existing
+@@ -5759,10 +5882,6 @@
+       }
+       case MSG_EXT_PPR:
+       {
+-        unsigned char bus_width, trans_options, new_trans_options;
+-        unsigned int period, offset;
+-        unsigned char maxsync, saved_offset;
+-        struct aic7xxx_syncrate *syncrate;
+         
+         if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
+         {
+@@ -5775,9 +5894,9 @@
+           break;
+         }
+ 
+-        period = p->msg_buf[3];
+-        offset = saved_offset = p->msg_buf[5];
+-        bus_width = p->msg_buf[6];
++        period = new_period = p->msg_buf[3];
++        offset = new_offset = p->msg_buf[5];
++        bus_width = new_bus_width = p->msg_buf[6];
+         trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+ 
+         if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+@@ -5787,22 +5906,6 @@
+                  trans_options);
+         }
+ 
+-        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+-            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+-        {
+-          if(p->features & AHC_ULTRA3)
+-          {
+-            maxsync = AHC_SYNCRATE_ULTRA3;
+-          }
+-          else
+-          {
+-            maxsync = AHC_SYNCRATE_ULTRA2;
+-          }
+-        }
+-        else
+-        {
+-          maxsync = AHC_SYNCRATE_ULTRA;
+-        }
+         /*
+          * We might have a device that is starting negotiation with us
+          * before we can start up negotiation with it....be prepared to
+@@ -5811,13 +5914,22 @@
+          */
+         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
+-        {
+-          reply = TRUE;
+-          scb->flags &= ~SCB_MSGOUT_BITS;
+-          scb->flags |= SCB_MSGOUT_PPR;
+-	  p->dev_flags[tindex] |= DEVICE_SCSI_3;
+-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+-          {
++        { 
++          /* Have we scanned the device yet? */
++          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
++          {
++            /* The device is electing to use PPR messages, so we will too until
++             * we know better */
++            p->needppr |= target_mask;
++            p->needppr_copy |= target_mask;
++            p->needsdtr &= ~target_mask;
++            p->needsdtr_copy &= ~target_mask;
++            p->needwdtr &= ~target_mask;
++            p->needwdtr_copy &= ~target_mask;
++          
++            /* We know the device is SCSI-3 compliant due to PPR */
++            p->dev_flags[tindex] |= DEVICE_SCSI_3;
++          
+             /*
+              * Not only is the device starting this up, but it also hasn't
+              * been scanned yet, so this would likely be our TUR or our
+@@ -5826,15 +5938,19 @@
+              * if we didn't find a SEEPROM, we stuffed default values into
+              * the user settings anyway, so use those in all cases.
+              */
+-            p->transinfo[tindex].goal_period =
+-              p->transinfo[tindex].user_period;
++            p->transinfo[tindex].goal_width =
++              p->transinfo[tindex].user_width;
+             if(p->transinfo[tindex].user_offset)
+             {
++              p->transinfo[tindex].goal_period =
++                p->transinfo[tindex].user_period;
++              p->transinfo[tindex].goal_options =
++                p->transinfo[tindex].user_options;
+               if(p->features & AHC_ULTRA2)
+               {
+                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+               }
+-              else if( p->transinfo[tindex].user_width &&
++              else if( p->transinfo[tindex].goal_width &&
+                        (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                        p->features & AHC_WIDE )
+               {
+@@ -5845,117 +5961,142 @@
+                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+               }
+             }
+-            p->transinfo[tindex].goal_width =
+-              p->transinfo[tindex].user_width;
+-            p->transinfo[tindex].goal_options =
+-              p->transinfo[tindex].user_options;
++            else
++            {
++              p->transinfo[tindex].goal_period = 255;
++              p->transinfo[tindex].goal_offset = 0;
++              p->transinfo[tindex].goal_options = 0;
++            }
++            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
++          }
++          else if ((p->needppr_copy & target_mask) == 0)
++          {
++            /*
++             * This is a preemptive message from the target, we've already
++             * scanned this target and set our options for it, and we
++             * don't need a PPR with this target (for whatever reason),
++             * so reject this incoming PPR
++             */
++            reject = TRUE;
++            break;
+           }
++
++          /* The device is sending this message first and we have to reply */
++          reply = TRUE;
++          
+           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+           {
+             printk(INFO_LEAD "Received pre-emptive PPR message from "
+                    "target.\n", p->host_no, CTL_OF_SCB(scb));
+           }
+-          if ( !p->transinfo[tindex].goal_offset )
+-            period = 255;
+-          if ( p->transinfo[tindex].goal_period > period )
+-            period = p->transinfo[tindex].goal_period;
+-          if ( p->transinfo[tindex].goal_options == 0 )
+-            new_trans_options = 0;
+-          switch(bus_width)
++
++        }
++
++        switch(bus_width)
++        {
++          case MSG_EXT_WDTR_BUS_16_BIT:
+           {
+-            default:
+-            {
+-              if ( (p->features & AHC_WIDE) &&
+-                   (p->transinfo[tindex].goal_width ==
+-                    MSG_EXT_WDTR_BUS_16_BIT) )
+-              {
+-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+-                break;
+-              }
+-            } /* Fall through if we aren't a wide card */
+-            case MSG_EXT_WDTR_BUS_8_BIT:
++            if ( (p->transinfo[tindex].goal_width ==
++                  MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE)
+             {
+-              p->needwdtr_copy &= ~target_mask;
+-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+-              aic7xxx_set_width(p, target, channel, lun, bus_width,
+-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+               break;
+             }
+           }
+-          if ( (p->transinfo[tindex].goal_period > 9) ||
+-               (p->transinfo[tindex].goal_options == 0) )
++          default:
+           {
+-            scb->flags &= ~SCB_MSGOUT_BITS;
+-            reject = TRUE;
+-            reply = FALSE;
+-            p->needppr &= ~(1 << tindex);
+-            p->needppr_copy &= ~(1 << tindex);
+-            if ( p->transinfo[tindex].goal_offset )
+-            {
+-              p->needsdtr |= (1 << tindex);
+-              p->needsdtr_copy |= (1 << tindex);
+-            }
+-            if ( p->transinfo[tindex].goal_width )
+-            {
+-              p->needwdtr |= (1 << tindex);
+-              p->needwdtr_copy |= (1 << tindex);
++            if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
++                 ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
++                  (aic7xxx_verbose > 0xffff)) )
++            {
++              reply = TRUE;
++              printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
++                p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+             }
++          } /* We fall through on purpose */
++          case MSG_EXT_WDTR_BUS_8_BIT:
++          {
++            /*
++             * According to the spec, if we aren't wide, we also can't be
++             * Dual Edge so clear the options byte
++             */
++            new_trans_options = 0;
++            new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
++            break;
+           }
+         }
++
++        if(reply)
++        {
++          /* when sending a reply, make sure that the goal settings are
++           * updated along with current and active since the code that
++           * will actually build the message for the sequencer uses the
++           * goal settings as its guidelines.
++           */
++          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
++                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
++                                           &new_trans_options);
++          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
++          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
++                               new_offset, new_trans_options,
++                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++        }
+         else
+         {
+-          switch(bus_width)
++          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
++                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
++                                           &new_trans_options);
++          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
++          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
++                               new_offset, new_trans_options,
++                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++        }
++
++        /*
++         * As it turns out, if we don't *have* to have PPR messages, then
++         * configure ourselves not to use them since that makes some
++         * external drive chassis work (those chassis can't parse PPR
++         * messages and they mangle the SCSI bus until you send a WDTR
++         * and SDTR that they can understand).
++         */
++        if(new_trans_options == 0)
++        {
++          p->needppr &= ~target_mask;
++          p->needppr_copy &= ~target_mask;
++          if(new_offset)
+           {
+-            default:
+-            {
+-              reject = TRUE;
+-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+-                    (aic7xxx_verbose > 0xffff)) )
+-              {
+-                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+-                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+-              }
+-            } /* We fall through on purpose */
+-            case MSG_EXT_WDTR_BUS_8_BIT:
+-            {
+-              /*
+-               * According to the spec, if we aren't wide, we also can't be
+-               * Dual Edge so clear the options byte
+-               */
+-              new_trans_options = 0;
+-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+-              break;
+-            }
+-            case MSG_EXT_WDTR_BUS_16_BIT:
+-            {
+-              break;
+-            }
++            p->needsdtr |= target_mask;
++            p->needsdtr_copy |= target_mask;
++          }
++          if (new_bus_width)
++          {
++            p->needwdtr |= target_mask;
++            p->needwdtr_copy |= target_mask;
+           }
+         }
+ 
+-        if ( !reject )
++        if((new_offset == 0) && (offset != 0))
+         {
+-          aic7xxx_set_width(p, target, channel, lun, bus_width,
+-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+-                                           &new_trans_options);
+-          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
+-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+-                               offset, new_trans_options,
+-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
++          /*
++           * Oops, the syncrate went to low for this card and we fell off
++           * to async (should never happen with a device that uses PPR
++           * messages, but have to be complete)
++           */
++          reply = TRUE;
+         }
+ 
+-        p->dtr_pending &= ~target_mask;
+-        p->needppr &= ~target_mask;
+         if(reply)
+         {
+-          p->dtr_pending |= target_mask;
+           scb->flags &= ~SCB_MSGOUT_BITS;
+           scb->flags |= SCB_MSGOUT_PPR;
+           aic_outb(p, HOST_MSG, MSG_OUT);
+           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+         }
++        else
++        {
++          p->needppr &= ~target_mask;
++        }
+         done = TRUE;
+         break;
+       }
+@@ -6193,16 +6334,14 @@
+         printerror = 0;
+       }
+     }
+-    if ( (scb != NULL) &&
+-         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
++    if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) 
+     {
+       /*
+-       * This might be a SCSI-3 device that is dropping the bus due to
+-       * errors and signalling that we should reduce the transfer speed.
+-       * All we have to do is complete this command (since it's a negotiation
+-       * command already) and the checksum routine should flag an error and
+-       * reduce the speed setting and renegotiate.  We call the reset routing
+-       * just to clean out the hardware from this scb.
++       * Hmmm...error during a negotiation command.  Either we have a
++       * borken bus, or the device doesn't like our negotiation message.
++       * Since we check the INQUIRY data of a device before sending it
++       * negotiation messages, assume the bus is borken for whatever
++       * reason.  Complete the command.
+        */
+       printerror = 0;
+       aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+@@ -6334,19 +6473,6 @@
+         cmd->result = 0;
+         scb = NULL;
+       }
+-      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+-      {
+-        /*
+-         * Turn off the needsdtr, needwdtr, and needppr bits since this device
+-         * doesn't seem to exist.
+-         */
+-        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+-        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+-        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+-        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+-        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+-        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+-      }
+     }
+     /*
+      * Keep the sequencer from trying to restart any selections
+@@ -6469,7 +6595,6 @@
+       }
+     }
+     else if( (lastphase == P_MESGOUT) &&
+-             (cmd == p->dev_dtr_cmnd[tindex]) &&
+              (scb->flags & SCB_MSGOUT_PPR) )
+     {
+       /*
+@@ -6488,7 +6613,6 @@
+       aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
+                            0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+       p->transinfo[tindex].goal_options = 0;
+-      p->dtr_pending &= ~(1 << tindex);
+       scb->flags &= ~SCB_MSGOUT_BITS;
+       if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+       {
+@@ -6511,87 +6635,6 @@
+       }
+       scb = NULL;
+     }
+-    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+-    {
+-      struct aic7xxx_syncrate *syncrate;
+-      unsigned int period = p->transinfo[tindex].cur_period;
+-      unsigned char options = p->transinfo[tindex].cur_options;
+-      /*
+-       * oops, we had a failure, lower the transfer rate and try again.  It's
+-       * worth noting here that it might be wise to also check for typical
+-       * wide setting on narrow cable type problems and try disabling wide
+-       * instead of slowing down if those exist.  That's hard to do with simple
+-       * checksums though.
+-       */
+-      printk(WARN_LEAD "Parity error during %s phase.\n",
+-             p->host_no, CTL_OF_SCB(scb), phase);
+-      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+-      {
+-        syncrate++;
+-        if( (syncrate->rate[0] != NULL) &&
+-            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+-        {
+-          p->transinfo[tindex].goal_period = syncrate->period;
+-          if( p->transinfo[tindex].goal_period > 9 )
+-          {
+-            p->transinfo[tindex].goal_options = 0;
+-            p->needppr &= ~(1<<tindex);
+-            p->needsdtr |= (1<<tindex);
+-            p->needppr_copy &= ~(1<<tindex);
+-            p->needsdtr_copy |= (1<<tindex);
+-            if (p->transinfo[tindex].goal_width)
+-            {
+-              p->needwdtr |= (1<<tindex);
+-              p->needwdtr_copy |= (1<<tindex);
+-            }
+-          }
+-        }
+-        else if (p->transinfo[tindex].goal_width)
+-        {
+-          p->transinfo[tindex].goal_width = 0;
+-          p->needwdtr &= ~(1<<tindex);
+-          p->needwdtr_copy &= ~(1<<tindex);
+-          p->transinfo[tindex].goal_offset =
+-            p->transinfo[tindex].user_offset;
+-          p->transinfo[tindex].goal_period =
+-            p->transinfo[tindex].user_period;
+-          p->transinfo[tindex].goal_options =
+-            p->transinfo[tindex].user_options;
+-          if( p->transinfo[tindex].goal_period <= 9 )
+-          {
+-            p->needppr |= (1<<tindex);
+-            p->needsdtr &= ~(1<<tindex);
+-            p->needppr_copy |= (1<<tindex);
+-            p->needsdtr_copy &= ~(1<<tindex);
+-          }
+-          else
+-          {
+-            p->needppr &= ~(1<<tindex);
+-            p->needsdtr |= (1<<tindex);
+-            p->needppr_copy &= ~(1<<tindex);
+-            p->needsdtr_copy |= (1<<tindex);
+-          }
+-        }
+-        else
+-        {
+-          p->transinfo[tindex].goal_offset = 0;
+-          p->transinfo[tindex].goal_period = 255;
+-          p->transinfo[tindex].goal_options = 0;
+-          p->transinfo[tindex].goal_width = 0;
+-          p->needppr &= ~(1<<tindex);
+-          p->needsdtr &= ~(1<<tindex);
+-          p->needwdtr &= ~(1<<tindex);
+-          p->needppr_copy &= ~(1<<tindex);
+-          p->needsdtr_copy &= ~(1<<tindex);
+-          p->needwdtr_copy &= ~(1<<tindex);
+-        }
+-      }
+-      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
+-    }
+-    else
+-    {
+-      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
+-    }
+ 
+     /*
+      * We've set the hardware to assert ATN if we get a parity
+@@ -6860,34 +6903,11 @@
+     else if (scb->flags & SCB_SENSE)
+     {
+       char *buffer = &scb->cmd->sense_buffer[0];
+-      if (scb->cmd == p->dev_dtr_cmnd[tindex])
+-      {
+-        struct aic7xxx_scb *old_scb;
+-        /*
+-         * We have valid sense data, send it back immediately.
+-         */
+-        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
+-        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
+-        old_scb->hscb->target_status = scb->hscb->target_status;
+-        old_scb->cmd->result = scb->hscb->target_status;
+-        old_scb->cmd->result |= (DID_ERROR << 16);
+-        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
+-        scbq_remove(&p->waiting_scbs, old_scb);
+-        scbq_remove(&p->delayed_scbs[tindex], old_scb);
+-        scb->cmd->next = NULL;
+-	aic7xxx_done(p, scb);
+-        aic7xxx_done(p, old_scb);
+-	continue;
+-      } 
+-      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
++
++      if (buffer[12] == 0x47 || buffer[12] == 0x54)
+       {
+         /*
+-         * SCSI errors, run domain validation and re-run negotiation
+-         */
+-        p->needdv |= (1<<tindex);
+-        /*
+-         * Signal that we need to re-negotiate things, this also gets us our
+-         * INQUIRY command to re-checksum off of.
++         * Signal that we need to re-negotiate things.
+          */
+         p->needppr |= (p->needppr_copy & (1<<tindex));
+         p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+@@ -6900,7 +6920,18 @@
+       case BUSY:
+         scb->hscb->target_status = 0;
+         scb->cmd->result = 0;
++        scb->hscb->residual_SG_segment_count = 0;
++        scb->hscb->residual_data_count[0] = 0;
++        scb->hscb->residual_data_count[1] = 0;
++        scb->hscb->residual_data_count[2] = 0;
+         aic7xxx_error(scb->cmd) = DID_OK;
++        aic7xxx_status(scb->cmd) = 0;
++        /*
++         * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
++         * this command on a timer and allowing us to retry it.  Here, we
++         * just 0 out a few values so that they don't carry through to when
++         * the command finally does complete.
++         */
+         break;
+       default:
+         cmd = scb->cmd;
+@@ -7065,33 +7096,27 @@
+   if(!p)
+     return;
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+-  if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
+-  {
+-    return;
+-  }
+   spin_lock_irqsave(&io_request_lock, cpu_flags);
++  p->flags |= AHC_IN_ISR;
+   do
+   {
+     aic7xxx_isr(irq, dev_id, regs);
+   } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
+   aic7xxx_done_cmds_complete(p);
+   aic7xxx_run_waiting_queues(p);
+-  clear_bit(AHC_IN_ISR_BIT, &p->flags);
++  p->flags &= ~AHC_IN_ISR;
+   spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+ #else
+-  if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
+-  {
+-    return;
+-  }
+   DRIVER_LOCK
++  p->flags |= AHC_IN_ISR;
+   do
+   {
+     aic7xxx_isr(irq, dev_id, regs);
+   } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
++  p->flags &= ~AHC_IN_ISR;
+   DRIVER_UNLOCK
+   aic7xxx_done_cmds_complete(p);
+   aic7xxx_run_waiting_queues(p);
+-  clear_bit(AHC_IN_ISR_BIT, (int *)&p->flags);
+ #endif
+ }
+ 
+@@ -9012,22 +9037,6 @@
+     kfree(p->scb_data);
+   }
+ 
+-  /*
+-   * Free any alloced Scsi_Cmnd structures that might be around for
+-   * negotiation purposes....
+-   */
+-  for (i = 0; i < MAX_TARGETS; i++)
+-  {
+-    if(p->dev_dtr_cmnd[i])
+-    {
+-      if(p->dev_dtr_cmnd[i]->request_buffer)
+-      {
+-        kfree(p->dev_dtr_cmnd[i]->request_buffer);
+-      }
+-      kfree(p->dev_dtr_cmnd[i]);
+-    }
+-  }
+-
+ }
+ 
+ /*+F*************************************************************************
+@@ -9413,7 +9422,7 @@
+   }
+   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+-  p->needppr = p->needppr_copy = p->needdv = 0;
++  p->needppr = p->needppr_copy = 0;
+   p->needwdtr = p->needwdtr_copy;
+   p->needsdtr = p->needsdtr_copy;
+   p->dtr_pending = 0;
+@@ -9471,53 +9480,165 @@
+ 
+ /*+F*************************************************************************
+  * Function:
+- *   aic7xxx_detect
++ *   aic7xxx_configure_bugs
+  *
+  * Description:
+- *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+- *
+- * XXX - This should really be called aic7xxx_probe().  A sequence of
+- *       probe(), attach()/detach(), and init() makes more sense than
+- *       one do-it-all function.  This may be useful when (and if) the
+- *       mid-level SCSI code is overhauled.
++ *   Take the card passed in and set the appropriate bug flags based upon
++ *   the card model.  Also make any changes needed to device registers or
++ *   PCI registers while we are here.
+  *-F*************************************************************************/
+-int
+-aic7xxx_detect(Scsi_Host_Template *template)
++static void
++aic7xxx_configure_bugs(struct aic7xxx_host *p)
+ {
+-  struct aic7xxx_host *temp_p = NULL;
+-  struct aic7xxx_host *current_p = NULL;
+-  struct aic7xxx_host *list_p = NULL;
+-  int found = 0;
+-#if defined(__i386__) || defined(__alpha__)
+-  ahc_flag_type flags = 0;
+-  int type;
+-#endif
+-  unsigned char sxfrctl1;
+-#if defined(__i386__) || defined(__alpha__)
+-  unsigned char hcntrl, hostconf;
+-  unsigned int slot, base;
+-#endif
+-
+-#ifdef MODULE
+-  /*
+-   * If we are called as a module, the aic7xxx pointer may not be null
+-   * and it would point to our bootup string, just like on the lilo
+-   * command line.  IF not NULL, then process this config string with
+-   * aic7xxx_setup
+-   */
+-  if(aic7xxx)
+-    aic7xxx_setup(aic7xxx, NULL);
+-  if(dummy_buffer[0] != 'P')
+-    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
+-      "/scsi/README.aic7xxx\n"
+-      "aic7xxx: to see the proper way to specify options to the aic7xxx "
+-      "module\n"
+-      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
+-      "aic7xxx: insmod or else it might trash certain memory areas.\n");
++  unsigned char pci_rev;
++  unsigned short tmp_word;
++ 
++  if((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
++  {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
++      pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
++            PCI_REVISION_ID, &pci_rev);
++#else
++      pci_read_config_byte(p->pdev, PCI_REVISION_ID, &pci_rev);
+ #endif
++  }
+ 
+-  template->proc_dir = &proc_scsi_aic7xxx;
+-  template->sg_tablesize = AIC7XXX_MAX_SG;
++  switch(p->chip & AHC_CHIPID_MASK)
++  {
++    case AHC_AIC7860:
++      if(pci_rev >= 1)
++      {
++        p->bugs |= AHC_BUG_PCI_2_1_RETRY;
++      }
++      /* fall through */
++    case AHC_AIC7850:
++    case AHC_AIC7870:
++      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
++      break;
++    case AHC_AIC7880:
++      p->bugs |= AHC_BUG_TMODE_WIDEODD;
++      if(pci_rev >= 1)
++      {
++        p->bugs |= AHC_BUG_PCI_2_1_RETRY;
++      }
++      else
++      {
++        p->bugs |= AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
++      }
++      break;
++    case AHC_AIC7890:
++      if(pci_rev == 0)
++      {
++        p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
++      }
++      break;
++    case AHC_AIC7892:
++      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
++      break;
++    case AHC_AIC7895:
++      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
++                 AHC_BUG_CACHETHEN;
++      if(pci_rev <= 3)
++      {
++        p->bugs |= AHC_BUG_PCI_MWI;
++      }
++      break;
++    case AHC_AIC7896:
++      p->bugs |= AHC_BUG_CACHETHEN_DIS;
++      break;
++    case AHC_AIC7899:
++      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
++      break;
++    default:
++      /* Nothing to do */
++      break;
++  }
++
++  /*
++   * Now handle the bugs that require PCI register or card register tweaks
++   */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
++  pcibios_read_config_word(p->pci_bus, p->pci_device_fn,
++            PCI_COMMAND, &tmp_word);
++#else
++  pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
++#endif
++  if(p->bugs & AHC_BUG_PCI_MWI)
++  {
++    tmp_word &= ~PCI_COMMAND_INVALIDATE;
++  }
++  else
++  {
++    tmp_word |= PCI_COMMAND_INVALIDATE;
++  }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
++  pcibios_write_config_word(p->pci_bus, p->pci_device_fn,
++            PCI_COMMAND, tmp_word);
++#else
++  pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
++#endif
++
++  if(p->bugs & AHC_BUG_CACHETHEN)
++  {
++    aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
++  }
++  else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
++  {
++    aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
++  }
++
++  return;
++}
++
++/*+F*************************************************************************
++ * Function:
++ *   aic7xxx_detect
++ *
++ * Description:
++ *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
++ *
++ * XXX - This should really be called aic7xxx_probe().  A sequence of
++ *       probe(), attach()/detach(), and init() makes more sense than
++ *       one do-it-all function.  This may be useful when (and if) the
++ *       mid-level SCSI code is overhauled.
++ *-F*************************************************************************/
++int
++aic7xxx_detect(Scsi_Host_Template *template)
++{
++  struct aic7xxx_host *temp_p = NULL;
++  struct aic7xxx_host *current_p = NULL;
++  struct aic7xxx_host *list_p = NULL;
++  int found = 0;
++#if defined(__i386__) || defined(__alpha__)
++  ahc_flag_type flags = 0;
++  int type;
++#endif
++  unsigned char sxfrctl1;
++#if defined(__i386__) || defined(__alpha__)
++  unsigned char hcntrl, hostconf;
++  unsigned int slot, base;
++#endif
++
++#ifdef MODULE
++  /*
++   * If we are called as a module, the aic7xxx pointer may not be null
++   * and it would point to our bootup string, just like on the lilo
++   * command line.  IF not NULL, then process this config string with
++   * aic7xxx_setup
++   */
++  if(aic7xxx)
++    aic7xxx_setup(aic7xxx, NULL);
++  if(dummy_buffer[0] != 'P')
++    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
++      "/scsi/README.aic7xxx\n"
++      "aic7xxx: to see the proper way to specify options to the aic7xxx "
++      "module\n"
++      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
++      "aic7xxx: insmod or else it might trash certain memory areas.\n");
++#endif
++
++  template->proc_dir = &proc_scsi_aic7xxx;
++  template->sg_tablesize = AIC7XXX_MAX_SG;
+ 
+ 
+ #ifdef CONFIG_PCI
+@@ -10290,6 +10411,14 @@
+             aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
+           }
+ 
++          /*
++           * Call our function to fixup any bugs that exist on this chipset.
++           * This may muck with PCI settings and other device settings, so
++           * make sure it's after all the other PCI and device register
++           * tweaks so it can back out bad settings on specific broken cards.
++           */
++          aic7xxx_configure_bugs(temp_p);
++
+           if ( list_p == NULL )
+           {
+             list_p = current_p = temp_p;
+@@ -10533,6 +10662,11 @@
+     }
+ 
+     /*
++     * All the 7770 based chipsets have this bug
++     */
++    temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
++
++    /*
+      * Set the FIFO threshold and the bus off time.
+      */
+     hostconf = aic_inb(temp_p, HOSTCONF);
+@@ -10751,297 +10885,6 @@
+   return (found);
+ }
+ 
+-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
+-                                           Scsi_Cmnd *old_cmd, int tindex);
+-
+-/*+F*************************************************************************
+- * Function:
+- *   aic7xxx_allocate_negotiation_command
+- *
+- * Description:
+- *   allocate the actual command struct and fill in the gaps...
+- *-F*************************************************************************/
+-static Scsi_Cmnd *
+-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
+-                                     Scsi_Cmnd *old_cmd, int tindex)
+-{
+-  Scsi_Cmnd *cmd;
+-  char *buffer;
+-
+-  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+-  {
+-    return(NULL);
+-  }
+-  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
+-  {
+-    kfree(p->dev_dtr_cmnd[tindex]);
+-    p->dev_dtr_cmnd[tindex] = NULL;
+-    return(NULL);
+-  }
+-  cmd = p->dev_dtr_cmnd[tindex];
+-  memset(cmd, 0, sizeof(Scsi_Cmnd));
+-  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+-  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+-  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+-  cmd->lun = 0;
+-  cmd->request_bufflen = 255;
+-  cmd->request_buffer = buffer;
+-  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+-  cmd->bufflen = 0;
+-  cmd->buffer = NULL;
+-  cmd->underflow = 0;
+-  cmd->cmd_len = 6;
+-  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
+-  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
+-  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
+-  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
+-  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
+-  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
+-  return(cmd);
+-}
+-
+-/*+F*************************************************************************
+- * Function:
+- *   aic7xxx_negotiation_complete
+- *
+- * Description:
+- *   Handle completion events for our Negotiation commands.  Clear out the
+- *   struct and get it ready for its next use.
+- *-F*************************************************************************/
+-static void
+-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
+-{
+-  unsigned int checksum;
+-  int i;
+-  int *ibuffer;
+-  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
+-  int tindex = TARGET_INDEX(cmd);
+-  struct aic7xxx_syncrate *syncrate;
+-
+-  /*
+-   * perform our minimalistic domain validation
+-   */
+-  if(p->dev_flags[tindex] & DEVICE_SCANNED)
+-  {
+-    ibuffer = (int *)cmd->request_buffer;
+-    checksum = 0;
+-    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
+-    {
+-      checksum += ibuffer[i];
+-    }
+-    if( (checksum != p->dev_checksum[tindex]) &&
+-        (p->transinfo[tindex].cur_offset != 0) )
+-    {
+-      unsigned int period = p->transinfo[tindex].cur_period;
+-      unsigned char options = p->transinfo[tindex].cur_options;
+-
+-      if (p->needdv & (1<<tindex))
+-      {
+-        /*
+-         * oops, we had a failure, lower the transfer rate and try again.  It's
+-         * worth noting here that it might be wise to also check for typical
+-         * wide setting on narrow cable type problems and try disabling wide
+-         * instead of slowing down if those exist.  That's hard to do with simple
+-         * checksums though.
+-         */
+-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
+-        {
+-          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
+-                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
+-        }
+-        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+-        {
+-          syncrate++;
+-          if( (syncrate->rate[0] != NULL) &&
+-              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+-          {
+-            p->transinfo[tindex].goal_period = syncrate->period;
+-            if( p->transinfo[tindex].goal_period > 9 )
+-            {
+-              p->transinfo[tindex].goal_options = 0;
+-              p->needppr &= ~(1<<tindex);
+-              p->needsdtr |= (1<<tindex);
+-              p->needppr_copy &= ~(1<<tindex);
+-              p->needsdtr_copy |= (1<<tindex);
+-              if (p->transinfo[tindex].goal_width)
+-              {
+-                p->needwdtr |= (1<<tindex);
+-                p->needwdtr_copy |= (1<<tindex);
+-              }
+-            }
+-          }
+-          else if (p->transinfo[tindex].goal_width)
+-          {
+-            p->transinfo[tindex].goal_width = 0;
+-            p->needwdtr &= ~(1<<tindex);
+-            p->needwdtr_copy &= ~(1<<tindex);
+-            p->transinfo[tindex].goal_offset =
+-              p->transinfo[tindex].user_offset;
+-            p->transinfo[tindex].goal_period =
+-              p->transinfo[tindex].user_period;
+-            p->transinfo[tindex].goal_options =
+-              p->transinfo[tindex].user_options;
+-            if( p->transinfo[tindex].goal_period <= 9 )
+-            {
+-              p->needppr |= (1<<tindex);
+-              p->needsdtr &= ~(1<<tindex);
+-              p->needppr_copy |= (1<<tindex);
+-              p->needsdtr_copy &= ~(1<<tindex);
+-            }
+-            else
+-            {
+-              p->needppr &= ~(1<<tindex);
+-              p->needsdtr |= (1<<tindex);
+-              p->needppr_copy &= ~(1<<tindex);
+-              p->needsdtr_copy |= (1<<tindex);
+-            }
+-          }
+-          else
+-          {
+-            p->transinfo[tindex].goal_offset = 0;
+-            p->transinfo[tindex].goal_period = 255;
+-            p->transinfo[tindex].goal_options = 0;
+-            p->transinfo[tindex].goal_width = 0;
+-            p->needppr &= ~(1<<tindex);
+-            p->needsdtr &= ~(1<<tindex);
+-            p->needwdtr &= ~(1<<tindex);
+-            p->needppr_copy &= ~(1<<tindex);
+-            p->needsdtr_copy &= ~(1<<tindex);
+-            p->needwdtr_copy &= ~(1<<tindex);
+-          }
+-        }
+-        p->needdv &= ~(1<<tindex);
+-      }
+-      else
+-      {
+-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
+-        {
+-          printk(INFO_LEAD "Performing Domain validation.\n",
+-                 p->host_no, CTL_OF_CMD(cmd));
+-        }
+-        /*
+-         * Update the checksum in case the INQUIRY data has changed, maybe
+-         * in relation to a change in the mode pages, or whatever.
+-         */
+-        p->dev_checksum[tindex] = checksum;
+-        /*
+-         * Signal that we are trying out the domain validation
+-         */
+-        p->needdv |= (1<<tindex);
+-        /*
+-         * Signal that we need to re-negotiate things, this also gets us our
+-         * INQUIRY command to re-checksum off of.
+-         */
+-        p->needppr |= (p->needppr_copy & (1<<tindex));
+-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+-      }
+-    } 
+-    else
+-    {
+-      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+-          (p->needdv & (1<<tindex)) )
+-      {
+-        printk(INFO_LEAD "Successfully completed Domain validation.\n",
+-               p->host_no, CTL_OF_CMD(cmd));
+-      }
+-      /*
+-       * We successfully did our checksum, so don't leave the needdv flag set
+-       * in case we might have set it last time through.
+-       */
+-      p->needdv &= ~(1<<tindex);
+-    }
+-  }
+-
+-  p->dtr_pending &= ~(0x01 << tindex);
+-  /*
+-   * This looks recursive in the extreme, but if this was a WDTR negotiation
+-   * and we didn't follow up with SDTR yet, then this will get it started.
+-   * For all other cases, this should work out to be a no-op, unless we are
+-   * doing domain validation and happen to need a new negotiation command.
+-   *
+-   * In case we don't want this to go any further, the cmdcmplt interrupt
+-   * handler will NULL out the cmd->next entry so that the real SCSI command
+-   * can be sent back to the mid layer code with SENSE data intact.  We'll
+-   * finish things up when the cmd gets sent back down to us, so no worries.
+-   */
+-  if(cmd->next)
+-  {
+-    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+-  }
+-  return;
+-}
+-
+-/*+F*************************************************************************
+- * Function:
+- *   aic7xxx_build_negotiation_command
+- *
+- * Description:
+- *   Build a Scsi_Cmnd structure to perform negotiation with or else send
+- *   a pre-built command specifically for this purpose.
+- *-F*************************************************************************/
+-static void
+-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
+-  int tindex)
+-{
+-
+-  if ( !(p->dtr_pending & (1<<tindex)) &&
+-       ( (p->needppr & (1<<tindex)) ||
+-         (p->needwdtr & (1<<tindex)) ||
+-         (p->needsdtr & (1<<tindex)) ) )
+-  {
+-    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
+-         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
+-    {
+-      return;
+-    }
+-    /*
+-     * Before sending this thing out, we also make the cmd->next pointer
+-     * point to the real command so we can stuff any possible SENSE data
+-     * into the real command instead of this fake command.  This has to be
+-     * done each time the command is built, not just the first time, hence
+-     * it's outside of the above if()...
+-     */
+-    p->dev_dtr_cmnd[tindex]->next = old_cmd;
+-    /*
+-     * Clear the buffer so checksums come out right....
+-     */
+-    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
+-           p->dev_dtr_cmnd[tindex]->request_bufflen);
+-    /*
+-     * Remove any commands for this particular device that might be on the
+-     * waiting_scbs queue or qinfifo so that this command goes out first.
+-     * This is vital for our implementation of domain validation.
+-     */
+-    pause_sequencer(p);
+-    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
+-                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
+-    unpause_sequencer(p, FALSE);
+-    {
+-      struct aic7xxx_scb *scb, *next;
+-
+-      scb = p->waiting_scbs.head;
+-      while(scb != NULL)
+-      {
+-        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
+-                              ALL_LUNS, SCB_LIST_NULL) )
+-        {
+-          next = scb->q_next;
+-          scbq_remove(&p->waiting_scbs, scb);
+-          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+-          scb = next;
+-        }
+-        else
+-        {
+-          scb = scb->q_next;
+-        }
+-      }
+-    }
+-    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
+-                  aic7xxx_negotiation_complete);
+-  }
+-}
+-
+ #ifdef AIC7XXX_VERBOSE_DEBUGGING
+ /*+F*************************************************************************
+  * Function:
+@@ -11090,7 +10933,7 @@
+    */
+   hscb->control = 0;
+   scb->tag_action = 0;
+-  cmd->tag = hscb->tag;
++
+   if (p->discenable & mask)
+   {
+     hscb->control |= DISCENB;
+@@ -11119,34 +10962,29 @@
+       }
+     }
+   }
+-  if ( cmd == p->dev_dtr_cmnd[tindex] )
++  if ( !(p->dtr_pending & mask) &&
++        ( (p->needppr & mask) ||
++          (p->needwdtr & mask) ||
++          (p->needsdtr & mask) ) &&
++        (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
+   {
+     p->dtr_pending |= mask;
+     scb->tag_action = 0;
+-    if (p->dev_flags[tindex] & DEVICE_SCANNED)
++    hscb->control &= DISCENB;
++    hscb->control |= MK_MESSAGE;
++    if(p->needppr & mask)
+     {
+-      hscb->control &= DISCENB;
+-      hscb->control |= MK_MESSAGE;
+-      if(p->needppr & mask)
+-      {
+-        scb->flags |= SCB_MSGOUT_PPR;
+-      }
+-      else if(p->needwdtr & mask)
+-      {
+-        scb->flags |= SCB_MSGOUT_WDTR;
+-      }
+-      else if(p->needsdtr & mask)
+-      {
+-        scb->flags |= SCB_MSGOUT_SDTR;
+-      }
++      scb->flags |= SCB_MSGOUT_PPR;
+     }
+-  }
+-  if ( !(p->dtr_pending & mask) &&
+-        ( (p->needppr & mask) ||
+-          (p->needwdtr & mask) ||
+-          (p->needsdtr & mask) ) )
+-  {
+-    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
++    else if(p->needwdtr & mask)
++    {
++      scb->flags |= SCB_MSGOUT_WDTR;
++    }
++    else if(p->needsdtr & mask)
++    {
++      scb->flags |= SCB_MSGOUT_SDTR;
++    }
++    scb->flags |= SCB_DTR_SCB;
+   }
+   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+@@ -11285,50 +11123,58 @@
+     aic7xxx_allocate_scb(p);
+     DRIVER_UNLOCK
+     scb = scbq_remove_head(&p->scb_data->free_scbs);
+-  }
+-  if (scb == NULL)
+-  {
+-    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+-           CTL_OF_CMD(cmd));
+-    cmd->result = (DID_BUS_BUSY << 16);
++    if(scb == NULL)
++      printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
++             CTL_OF_CMD(cmd));
++  }
++  while (scb == NULL)
++  {
++    /*
++     * Well, all SCBs are currently active on the bus.  So, we spin here
++     * running the interrupt handler until one completes and becomes free.
++     * We can do this safely because we either A) hold the driver lock (in
++     * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
++     * kernels) and so either way, we won't take any other interrupts and
++     * the queue path will block until we release it.  Also, we would worry
++     * about running the completion queues, but obviously there are plenty
++     * of commands outstanding to trigger a later interrupt that will do
++     * that for us, so skip it here.
++     */
+     DRIVER_LOCK
+-    aic7xxx_queue_cmd_complete(p, cmd);
++    aic7xxx_isr(p->irq, p, NULL);
+     DRIVER_UNLOCK
+-    return 0;
++    scb = scbq_remove_head(&p->scb_data->free_scbs);
+   }
+-  else
+-  {
+-    scb->cmd = cmd;
+-    aic7xxx_position(cmd) = scb->hscb->tag;
++  scb->cmd = cmd;
++  aic7xxx_position(cmd) = scb->hscb->tag;
+ 
+-    /*
+-     * Construct the SCB beforehand, so the sequencer is
+-     * paused a minimal amount of time.
+-     */
+-    aic7xxx_buildscb(p, cmd, scb);
++  /*
++   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
++   * is set up properly, and the parity error flag is reset, then send
++   * the SCB to the sequencer and watch the fun begin.
++   */
++  cmd->scsi_done = fn;
++  cmd->result = DID_OK;
++  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
++  aic7xxx_error(cmd) = DID_OK;
++  aic7xxx_status(cmd) = 0;
++  cmd->host_scribble = NULL;
+ 
+-    /*
+-     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+-     * is set up properly, and the parity error flag is reset, then send
+-     * the SCB to the sequencer and watch the fun begin.
+-     */
+-    cmd->scsi_done = fn;
+-    cmd->result = DID_OK;
+-    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+-    aic7xxx_error(cmd) = DID_OK;
+-    aic7xxx_status(cmd) = 0;
+-    cmd->host_scribble = NULL;
++  /*
++   * Construct the SCB beforehand, so the sequencer is
++   * paused a minimal amount of time.
++   */
++  aic7xxx_buildscb(p, cmd, scb);
+ 
+-    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
++  scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+ 
+-    DRIVER_LOCK
+-    scbq_insert_tail(&p->waiting_scbs, scb);
+-    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+-    {
+-      aic7xxx_run_waiting_queues(p);
+-    }
+-    DRIVER_UNLOCK
++  DRIVER_LOCK
++  scbq_insert_tail(&p->waiting_scbs, scb);
++  if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
++  {
++    aic7xxx_run_waiting_queues(p);
+   }
++  DRIVER_UNLOCK
+   return (0);
+ }
+ 
+@@ -11394,6 +11240,12 @@
+          aic_inb(p, SCSISIGI),
+          aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+          aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
++    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
++         CTL_OF_SCB(scb),
++         (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
++         aic_inb(p, SSTAT2),
++         aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
++         aic_inb(p, STCNT));
+   }
+ 
+   channel = cmd->channel;
+@@ -11687,7 +11539,6 @@
+ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+   unsigned long cpu_flags = 0;
+ #endif
+-  Scsi_Cmnd *cmd_next, *cmd_prev;
+ 
+   p = (struct aic7xxx_host *) cmd->host->hostdata;
+   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+@@ -11718,13 +11569,11 @@
+   {
+     aic7xxx_isr(p->irq, p, (void *)NULL);
+     pause_sequencer(p);
+-    aic7xxx_done_cmds_complete(p);
+   }
++  aic7xxx_done_cmds_complete(p);
+ 
+-  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+-                      /*  Totally bogus cmd since it points beyond our  */
+-  {                   /*  valid SCB range or doesn't even match it's own*/
+-                      /*  timeout serial number.                        */
++  if (scb == NULL)
++  {
+     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+       printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
+         "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
+@@ -11743,28 +11592,6 @@
+                         /*  finish successfully, or to indicate that we     */
+                         /*  don't have this cmd any more and the mid level  */
+                         /*  code needs to find it.                          */
+-    cmd_next = p->completeq.head;
+-    cmd_prev = NULL;
+-    while (cmd_next != NULL) 
+-    {
+-      if (cmd_next == cmd) 
+-      {
+-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+-          printk(INFO_LEAD "Abort called for command "
+-          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+-        if ( cmd_prev == NULL )
+-          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+-        else
+-          cmd_prev->host_scribble = cmd_next->host_scribble;
+-        cmd_next->scsi_done(cmd_next);
+-        unpause_sequencer(p, FALSE);
+-        DRIVER_UNLOCK
+-        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+-                                         * completion */
+-      }                                  
+-      cmd_prev = cmd_next;
+-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+-    }
+     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
+       printk(INFO_LEAD "Abort called for already completed"
+         " command.\n", p->host_no, CTL_OF_CMD(cmd));
+@@ -11822,8 +11649,20 @@
+   found = 0;
+   p->flags |= AHC_IN_ABORT;
+   if (aic7xxx_verbose & VERBOSE_ABORT)
+-    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
+-         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
++  {
++    printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
++           "0x%x\n",
++         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
++         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
++         aic_inb(p, LASTPHASE));
++    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
++         p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
++         aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
++         aic_inb(p, SCSISIGI));
++    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
++         p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
++         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
++  }
+ 
+ /*
+  *   First, let's check to see if the currently running command is our target
+@@ -11851,6 +11690,16 @@
+         if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+           printk(INFO_LEAD "SCB is currently active.  "
+                 "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
++        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
++           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
++           aic_inb(p, SCSISIGI),
++           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
++           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
++        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
++           p->host_no, CTL_OF_SCB(scb),
++           (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
++           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
++           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+         unpause_sequencer(p, FALSE);
+         p->flags &= ~AHC_IN_ABORT;
+         scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+@@ -11866,35 +11715,7 @@
+   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
+   {
+     int tindex = TARGET_INDEX(cmd);
+-    unsigned short mask;
+-
+-    mask = (1 << tindex);
+ 
+-    if (p->dtr_pending & mask)
+-    {
+-      if (p->dev_dtr_cmnd[tindex]->next != cmd)
+-        found = 1;
+-      else
+-        found = 0;
+-    }
+-    else
+-    {
+-      found = 1;
+-    }
+-    if (found == 0)
+-    {
+-      /*
+-       * OK..this means the command we are currently getting an abort
+-       * for has an outstanding negotiation command in front of it.
+-       * We don't really have a way to tie back into the negotiation
+-       * commands, so we just send this back as pending, then it
+-       * will get reset in 2 seconds.
+-       */
+-      unpause_sequencer(p, TRUE);
+-      scb->flags |= SCB_ABORT;
+-      DRIVER_UNLOCK
+-      return(SCSI_ABORT_PENDING);
+-    }
+     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+       printk(INFO_LEAD "SCB found on waiting list and "
+           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+@@ -12051,10 +11872,8 @@
+ #define DEVICE_RESET 0x01
+ #define BUS_RESET    0x02
+ #define HOST_RESET   0x04
+-#define FAIL         0x08
+-#define RESET_DELAY  0x10
++#define RESET_DELAY  0x08
+   int        action;
+-  Scsi_Cmnd *cmd_prev, *cmd_next;
+ 
+ 
+   if ( cmd == NULL )
+@@ -12082,86 +11901,32 @@
+   DRIVER_LOCK
+ 
+   pause_sequencer(p);
+-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+-  {
+-    aic7xxx_isr(p->irq, p, (void *)NULL );
+-    pause_sequencer(p);
+-    aic7xxx_done_cmds_complete(p);
+-  }
+ 
+-  if (scb == NULL)
++  if(flags & SCSI_RESET_SYNCHRONOUS)
+   {
+     if (aic7xxx_verbose & VERBOSE_RESET_MID)
+-      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+-           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+-    {
+-      action = HOST_RESET;
+-    }
+-    else
+-    {
+-      action = BUS_RESET;
+-    }
++      printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
++           "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
++           cmd->result);
++    scb = NULL;
++    action = HOST_RESET;
+   }
+-  else if (scb->cmd != cmd) 
++  else if ((scb == NULL) || (scb->cmd != cmd))
+   {
+     if (aic7xxx_verbose & VERBOSE_RESET_MID)
+-    printk(INFO_LEAD "Reset called with recycled SCB "
+-        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+-    cmd_prev = NULL;
+-    cmd_next = p->completeq.head;
+-    while ( cmd_next != NULL )
+-    {
+-      if (cmd_next == cmd)
+-      {
+-        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+-          printk(INFO_LEAD "Reset, found cmd on completeq"
+-          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+-        unpause_sequencer(p, FALSE);
+-        DRIVER_UNLOCK
+-        return(SCSI_RESET_NOT_RUNNING);
+-      }
+-      cmd_prev = cmd_next;
+-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+-    }
+-    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
+-    {
+-      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+-        printk(INFO_LEAD "Reset, cmd not found,"
+-          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+-      unpause_sequencer(p, FALSE);
+-      DRIVER_UNLOCK
+-      return(SCSI_RESET_NOT_RUNNING);
+-    }
+-    else
+-    {
+-      if (aic7xxx_verbose & VERBOSE_RESET_MID)
+-        printk(INFO_LEAD "Reset called, no scb, "
+-          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
+-      scb = NULL;
+-      action = HOST_RESET;
+-    }
++      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
++           "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
++    aic7xxx_done_cmds_complete(p);
++    aic7xxx_run_waiting_queues(p);
++    unpause_sequencer(p, FALSE);
++    DRIVER_UNLOCK
++    return(SCSI_RESET_NOT_RUNNING);
+   }
+   else
+   {
+     if (aic7xxx_verbose & VERBOSE_RESET_MID)
+       printk(INFO_LEAD "Reset called, scb %d, flags "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+-    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
+-    {
+-      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
+-        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
+-          CTL_OF_SCB(scb));
+-      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
+-        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
+-          CTL_OF_SCB(scb));
+-      aic7xxx_handle_command_completion_intr(p);
+-      aic7xxx_done_cmds_complete(p);
+-      aic7xxx_run_waiting_queues(p);
+-      unpause_sequencer(p, FALSE);
+-      DRIVER_UNLOCK
+-      return(SCSI_RESET_SUCCESS);
+-    }
+     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
+     {
+       action = HOST_RESET;
+@@ -12175,6 +11940,26 @@
+       action = DEVICE_RESET;
+     }
+   }
++
++  while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
++  {
++    aic7xxx_isr(p->irq, p, (void *)NULL );
++    pause_sequencer(p);
++  }
++  aic7xxx_done_cmds_complete(p);
++
++  if(scb && (scb->cmd == NULL))
++  {
++    /*
++     * We just completed the command when we ran the isr stuff, so we no
++     * longer have it.
++     */
++    aic7xxx_run_waiting_queues(p);
++    unpause_sequencer(p, FALSE);
++    DRIVER_UNLOCK
++    return(SCSI_RESET_SUCCESS);
++  }
++    
+   if ( (action & DEVICE_RESET) && 
+         (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
+   {
+@@ -12234,14 +12019,13 @@
+   switch (action)
+   {
+     case RESET_DELAY:
++      aic7xxx_run_waiting_queues(p);
+       unpause_sequencer(p, FALSE);
+       DRIVER_UNLOCK
+-      return(SCSI_RESET_PENDING);
+-      break;
+-    case FAIL:
+-      unpause_sequencer(p, FALSE);
+-      DRIVER_UNLOCK
+-      return(SCSI_RESET_ERROR);
++      if(scb == NULL)
++        return(SCSI_RESET_PUNT);
++      else
++        return(SCSI_RESET_PENDING);
+       break;
+     case DEVICE_RESET:
+       p->flags |= AHC_IN_RESET;
+@@ -12259,7 +12043,7 @@
+     case HOST_RESET:
+     default:
+       p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
+-      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
++      p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
+       p->dev_timer_active |= (0x01 << p->scsi_id);
+       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+             time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
+@@ -12288,21 +12072,14 @@
+         p->msg_index = 0;
+         p->msg_len = 0;
+       }
+-      aic7xxx_run_done_queue(p, TRUE);
+-      /*
+-       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
+-       * in need of being re-started, so send it on through to aic7xxx_queue
+-       * and let it set until the delay is over.  This keeps it from dying
+-       * entirely and avoids getting a bogus dead command back through the
+-       * mid-level code due to too many retries.
+-       */
+-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+-      if ( flags & SCSI_RESET_SYNCHRONOUS )
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
++      if(flags & SCSI_RESET_SYNCHRONOUS)
+       {
+-        cmd->result = DID_BUS_BUSY << 16;
++        cmd->result = DID_RESET << 16;
+         cmd->done(cmd);
+       }
+ #endif
++      aic7xxx_run_done_queue(p, TRUE);
+       p->flags &= ~AHC_IN_RESET;
+       /*
+        * We can't rely on run_waiting_queues to unpause the sequencer for
+@@ -12313,7 +12090,10 @@
+       aic7xxx_run_waiting_queues(p);
+       unpause_sequencer(p, FALSE);
+       DRIVER_UNLOCK
+-      return(result);
++      if(scb == NULL)
++        return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
++      else
++        return(result);
+       break;
+   }
+ }
+@@ -12623,7 +12403,7 @@
+ }
+ 
+ 
+-#include "aic7xxx_proc.c"
++#include "aic7xxx/aic7xxx_proc.c"
+ 
+ #ifdef MODULE
+ /* Eventually this will go into an include file, but this will be later */
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h
+--- linux-2.2.17/drivers/scsi/aic7xxx.h	Tue May 11 13:36:28 1999
++++ linux/drivers/scsi/aic7xxx.h	Wed Dec 31 19:00:00 1969
+@@ -1,114 +0,0 @@
+-/*+M*************************************************************************
+- * Adaptec AIC7xxx device driver for Linux.
+- *
+- * Copyright (c) 1994 John Aycock
+- *   The University of Calgary Department of Computer Science.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2, or (at your option)
+- * any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; see the file COPYING.  If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- * 
+- * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
+- *-M*************************************************************************/
+-#ifndef _aic7xxx_h
+-#define _aic7xxx_h
+-
+-#define AIC7XXX_H_VERSION  "3.2.4"
+-
+-#ifndef LINUX_VERSION_CODE
+-#include <linux/version.h>
+-#endif
+-
+-#ifndef KERNEL_VERSION
+-#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+-#endif
+-
+-#if defined(__i386__)
+-#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+-#else
+-#  define AIC7XXX_BIOSPARAM NULL
+-#endif
+-
+-/*
+- * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
+- * to do with card config are filled in after the card is detected.
+- */
+-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+-#define AIC7XXX	{						\
+-	next: NULL,						\
+-	module: NULL,						\
+-	proc_dir: NULL,						\
+-	proc_info: aic7xxx_proc_info,				\
+-	name: NULL,						\
+-	detect: aic7xxx_detect,					\
+-	release: aic7xxx_release,				\
+-	info: aic7xxx_info,					\
+-	command: NULL,						\
+-	queuecommand: aic7xxx_queue,				\
+-	eh_strategy_handler: NULL,				\
+-	eh_abort_handler: NULL,					\
+-	eh_device_reset_handler: NULL,				\
+-	eh_bus_reset_handler: NULL,				\
+-	eh_host_reset_handler: NULL,				\
+-	abort: aic7xxx_abort,					\
+-	reset: aic7xxx_reset,					\
+-	slave_attach: NULL,					\
+-	bios_param: AIC7XXX_BIOSPARAM,				\
+-	can_queue: 255,		/* max simultaneous cmds      */\
+-	this_id: -1,		/* scsi id of host adapter    */\
+-	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+-	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+-	present: 0,		/* number of 7xxx's present   */\
+-	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+-	use_clustering: ENABLE_CLUSTERING,			\
+-	use_new_eh_code: 0					\
+-}
+-#else
+-#define AIC7XXX	{						\
+-	next: NULL,						\
+-	usage_count: NULL,					\
+-	proc_dir: NULL, 					\
+-	proc_info: aic7xxx_proc_info,				\
+-	name: NULL,						\
+-	detect: aic7xxx_detect,					\
+-	release: aic7xxx_release,				\
+-	info: aic7xxx_info,					\
+-	command: NULL,						\
+-	queuecommand: aic7xxx_queue,				\
+-	abort: aic7xxx_abort,					\
+-	reset: aic7xxx_reset,					\
+-	slave_attach: NULL,					\
+-	bios_param: AIC7XXX_BIOSPARAM,				\
+-	can_queue: 255,		/* max simultaneous cmds      */\
+-	this_id: -1,		/* scsi id of host adapter    */\
+-	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+-	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+-	present: 0,		/* number of 7xxx's present   */\
+-	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+-	use_clustering: ENABLE_CLUSTERING			\
+-}
+-#endif
+-
+-extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+-extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
+-extern int aic7xxx_detect(Scsi_Host_Template *);
+-extern int aic7xxx_command(Scsi_Cmnd *);
+-extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
+-extern int aic7xxx_abort(Scsi_Cmnd *);
+-extern int aic7xxx_release(struct Scsi_Host *);
+-
+-extern const char *aic7xxx_info(struct Scsi_Host *);
+-
+-extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
+-
+-#endif /* _aic7xxx_h */
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
+--- linux-2.2.17/drivers/scsi/aic7xxx_proc.c	Wed May  3 20:16:44 2000
++++ linux/drivers/scsi/aic7xxx_proc.c	Wed Dec 31 19:00:00 1969
+@@ -1,414 +0,0 @@
+-/*+M*************************************************************************
+- * Adaptec AIC7xxx device driver proc support for Linux.
+- *
+- * Copyright (c) 1995, 1996 Dean W. Gehnert
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2, or (at your option)
+- * any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; see the file COPYING.  If not, write to
+- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+- *
+- * ----------------------------------------------------------------
+- *  o Modified from the EATA-DMA /proc support.
+- *  o Additional support for device block statistics provided by
+- *    Matthew Jacob.
+- *  o Correction of overflow by Heinz Mauelshagen
+- *  o Adittional corrections by Doug Ledford
+- *
+- *  Dean W. Gehnert, deang@teleport.com, 05/01/96
+- *
+- *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
+- *-M*************************************************************************/
+-
+-#include <linux/config.h>
+-
+-#define	BLS	(&aic7xxx_buffer[size])
+-#define HDRB \
+-"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
+-
+-#ifdef PROC_DEBUG
+-extern int vsprintf(char *, const char *, va_list);
+-
+-static void
+-proc_debug(const char *fmt, ...)
+-{
+-  va_list ap;
+-  char buf[256];
+-
+-  va_start(ap, fmt);
+-  vsprintf(buf, fmt, ap);
+-  printk(buf);
+-  va_end(ap);
+-}
+-#else /* PROC_DEBUG */
+-#  define proc_debug(fmt, args...)
+-#endif /* PROC_DEBUG */
+-
+-static int aic7xxx_buffer_size = 0;
+-static char *aic7xxx_buffer = NULL;
+-
+-
+-/*+F*************************************************************************
+- * Function:
+- *   aic7xxx_set_info
+- *
+- * Description:
+- *   Set parameters for the driver from the /proc filesystem.
+- *-F*************************************************************************/
+-int
+-aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+-{
+-  proc_debug("aic7xxx_set_info(): %s\n", buffer);
+-  return (-ENOSYS);  /* Currently this is a no-op */
+-}
+-
+-
+-/*+F*************************************************************************
+- * Function:
+- *   aic7xxx_proc_info
+- *
+- * Description:
+- *   Return information to handle /proc support for the driver.
+- *-F*************************************************************************/
+-int
+-aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
+-                    int hostno, int inout)
+-{
+-  struct Scsi_Host *HBAptr;
+-  struct aic7xxx_host *p;
+-  int    size = 0;
+-  unsigned char i;
+-  struct aic7xxx_xferstats *sp;
+-  unsigned char target;
+-
+-  HBAptr = NULL;
+-
+-  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+-    ;
+-
+-  if (!p)
+-  {
+-    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
+-    if (size > length)
+-    {
+-      return (size);
+-    }
+-    else
+-    {
+-      return (length);
+-    }
+-  }
+-
+-  HBAptr = p->host;
+-
+-  if (inout == TRUE) /* Has data been written to the file? */ 
+-  {
+-    return (aic7xxx_set_info(buffer, length, HBAptr));
+-  }
+-
+-  p = (struct aic7xxx_host *) HBAptr->hostdata;
+-
+-  /*
+-   * It takes roughly 1K of space to hold all relevant card info, not
+-   * counting any proc stats, so we start out with a 1.5k buffer size and
+-   * if proc_stats is defined, then we sweep the stats structure to see
+-   * how many drives we will be printing out for and add 384 bytes per
+-   * device with active stats.
+-   *
+-   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+-   * can be easily viewed for debugging purposes.  So, we bumped that
+-   * 1.5k to 4k so we can quit having to bump it all the time.
+-   */
+-
+-  size = 4096;
+-  for (target = 0; target < MAX_TARGETS; target++)
+-  {
+-    if (p->dev_flags[target] & DEVICE_PRESENT)
+-#ifdef AIC7XXX_PROC_STATS
+-      size += 512;
+-#else
+-      size += 256;
+-#endif
+-  }
+-  if (aic7xxx_buffer_size != size)
+-  {
+-    if (aic7xxx_buffer != NULL) 
+-    {
+-      kfree(aic7xxx_buffer);
+-      aic7xxx_buffer_size = 0;
+-    }
+-    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
+-  }
+-  if (aic7xxx_buffer == NULL)
+-  {
+-    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
+-        __LINE__);
+-    return size;
+-  }
+-  aic7xxx_buffer_size = size;
+-
+-  size = 0;
+-  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
+-  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+-  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
+-  size += sprintf(BLS, "\n");
+-  size += sprintf(BLS, "Compile Options:\n");
+-#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+-  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
+-#else
+-  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
+-#endif
+-#ifdef AIC7XXX_PROC_STATS
+-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
+-#else
+-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
+-#endif
+-  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
+-  size += sprintf(BLS, "\n");
+-  size += sprintf(BLS, "Adapter Configuration:\n");
+-  size += sprintf(BLS, "           SCSI Adapter: %s\n",
+-      board_names[p->board_name_index]);
+-  if (p->flags & AHC_TWIN)
+-    size += sprintf(BLS, "                         Twin Channel Controller ");
+-  else
+-  {
+-    char *channel = "";
+-    char *ultra = "";
+-    char *wide = "Narrow ";
+-    if (p->flags & AHC_MULTI_CHANNEL)
+-    {
+-      channel = " Channel A";
+-      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+-        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+-    }
+-    if (p->features & AHC_WIDE)
+-      wide = "Wide ";
+-    if (p->features & AHC_ULTRA3)
+-    {
+-      switch(p->chip & AHC_CHIPID_MASK)
+-      {
+-        case AHC_AIC7892:
+-        case AHC_AIC7899:
+-          ultra = "Ultra-160/m LVD/SE ";
+-          break;
+-        default:
+-          ultra = "Ultra-3 LVD/SE ";
+-          break;
+-      }
+-    }
+-    else if (p->features & AHC_ULTRA2)
+-      ultra = "Ultra-2 LVD/SE ";
+-    else if (p->features & AHC_ULTRA)
+-      ultra = "Ultra ";
+-    size += sprintf(BLS, "                           %s%sController%s ",
+-      ultra, wide, channel);
+-  }
+-  switch(p->chip & ~AHC_CHIPID_MASK)
+-  {
+-    case AHC_VL:
+-      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+-      break;
+-    case AHC_EISA:
+-      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+-      break;
+-    default:
+-      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+-        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
+-      break;
+-  }
+-  if( !(p->maddr) )
+-  {
+-    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+-  }
+-  else
+-  {
+-    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+-  }
+-  if( (p->chip & (AHC_VL | AHC_EISA)) )
+-  {
+-    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+-  }
+-  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
+-          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
+-         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
+-           "SEEPROM not found, using leftover BIOS values.") );
+-  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+-          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+-  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
+-  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+-            p->activescbs, p->max_activescbs);
+-  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+-            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+-            p->scb_data->maxscbs);
+-  if (p->flags & AHC_EXTERNAL_SRAM)
+-    size += sprintf(BLS, "                         Using External SCB SRAM\n");
+-  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+-  if (p->chip & AHC_EISA)
+-  {
+-    size += sprintf(BLS, " %s\n",
+-        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
+-  }
+-  else
+-  {
+-    size += sprintf(BLS, "\n");
+-  }
+-  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+-            p->bios_control);
+-  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+-            p->adapter_control);
+-  size += sprintf(BLS, "   Extended Translation: %sabled\n",
+-      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
+-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+-  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
+-  {
+-    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+-  }
+-  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+-  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
+-  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+-                       "instance %d:\n", p->instance);
+-  size += sprintf(BLS, "      {");
+-  for(i=0; i < (MAX_TARGETS - 1); i++)
+-    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+-  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+-  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+-                       "instance %d:\n", p->instance);
+-  size += sprintf(BLS, "      {");
+-  for(i=0; i < (MAX_TARGETS - 1); i++)
+-    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+-  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+-
+-  size += sprintf(BLS, "\n");
+-  size += sprintf(BLS, "Statistics:\n\n");
+-  for (target = 0; target < MAX_TARGETS; target++)
+-  {
+-    sp = &p->stats[target];
+-    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
+-    {
+-      continue;
+-    }
+-    if (p->features & AHC_TWIN)
+-    {
+-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+-          p->host_no, (target >> 3), (target & 0x7), 0);
+-    }
+-    else
+-    {
+-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+-          p->host_no, 0, target, 0);
+-    }
+-    size += sprintf(BLS, "  Device using %s/%s",
+-          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+-          "Wide" : "Narrow",
+-          (p->transinfo[target].cur_offset != 0) ?
+-          "Sync transfers at " : "Async transfers.\n" );
+-    if (p->transinfo[target].cur_offset != 0)
+-    {
+-      struct aic7xxx_syncrate *sync_rate;
+-      unsigned char options = p->transinfo[target].cur_options;
+-      int period = p->transinfo[target].cur_period;
+-      int rate = (p->transinfo[target].cur_width ==
+-                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+-
+-      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
+-      if (sync_rate != NULL)
+-      {
+-        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+-                        sync_rate->rate[rate],
+-                        p->transinfo[target].cur_offset );
+-      }
+-      else
+-      {
+-        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+-                        p->transinfo[target].cur_offset );
+-      }
+-    }
+-    size += sprintf(BLS, "  Transinfo settings: ");
+-    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
+-                    p->transinfo[target].cur_period,
+-                    p->transinfo[target].cur_offset,
+-                    p->transinfo[target].cur_width,
+-                    p->transinfo[target].cur_options);
+-    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
+-                    p->transinfo[target].goal_period,
+-                    p->transinfo[target].goal_offset,
+-                    p->transinfo[target].goal_width,
+-                    p->transinfo[target].goal_options);
+-    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
+-                    p->transinfo[target].user_period,
+-                    p->transinfo[target].user_offset,
+-                    p->transinfo[target].user_width,
+-                    p->transinfo[target].user_options);
+-#ifdef AIC7XXX_PROC_STATS
+-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+-    size += sprintf(BLS, "%s\n", HDRB);
+-    size += sprintf(BLS, "   Reads:");
+-    for (i = 0; i < NUMBER(sp->r_bins); i++)
+-    {
+-      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
+-    }
+-    size += sprintf(BLS, "\n");
+-    size += sprintf(BLS, "  Writes:");
+-    for (i = 0; i < NUMBER(sp->w_bins); i++)
+-    {
+-      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
+-    }
+-    size += sprintf(BLS, "\n");
+-#else
+-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+-#endif /* AIC7XXX_PROC_STATS */
+-    size += sprintf(BLS, "\n\n");
+-  }
+-
+-  if (size >= aic7xxx_buffer_size)
+-  {
+-    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
+-  }
+-
+-  if (offset > size - 1)
+-  {
+-    kfree(aic7xxx_buffer);
+-    aic7xxx_buffer = NULL;
+-    aic7xxx_buffer_size = length = 0;
+-    *start = NULL;
+-  }
+-  else
+-  {
+-    *start = buffer;
+-    length = MIN(length, size - offset);
+-    memcpy(buffer, &aic7xxx_buffer[offset], length);
+-  }
+-
+-  return (length);
+-}
+-
+-/*
+- * Overrides for Emacs so that we follow Linus's tabbing style.
+- * Emacs will notice this stuff at the end of the file and automatically
+- * adjust the settings for this buffer only.  This must remain at the end
+- * of the file.
+- * ---------------------------------------------------------------------------
+- * Local variables:
+- * c-indent-level: 2
+- * c-brace-imaginary-offset: 0
+- * c-brace-offset: -2
+- * c-argdecl-indent: 2
+- * c-label-offset: -2
+- * c-continued-statement-offset: 2
+- * c-continued-brace-offset: 0
+- * indent-tabs-mode: nil
+- * tab-width: 8
+- * End:
+- */
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx_reg.h linux/drivers/scsi/aic7xxx_reg.h
+--- linux-2.2.17/drivers/scsi/aic7xxx_reg.h	Wed May  3 20:16:44 2000
++++ linux/drivers/scsi/aic7xxx_reg.h	Wed Dec 31 19:00:00 1969
+@@ -1,629 +0,0 @@
+-/*
+-  * DO NOT EDIT - This file is automatically generated.
+-  */
+-
+-#define	SCSISEQ         		0x00
+-#define		TEMODE          	0x80
+-#define		ENSELO          	0x40
+-#define		ENSELI          	0x20
+-#define		ENRSELI         	0x10
+-#define		ENAUTOATNO      	0x08
+-#define		ENAUTOATNI      	0x04
+-#define		ENAUTOATNP      	0x02
+-#define		SCSIRSTO        	0x01
+-
+-#define	SXFRCTL0        		0x01
+-#define		DFON            	0x80
+-#define		DFPEXP          	0x40
+-#define		FAST20          	0x20
+-#define		CLRSTCNT        	0x10
+-#define		SPIOEN          	0x08
+-#define		SCAMEN          	0x04
+-#define		CLRCHN          	0x02
+-
+-#define	SXFRCTL1        		0x02
+-#define		BITBUCKET       	0x80
+-#define		SWRAPEN         	0x40
+-#define		ENSPCHK         	0x20
+-#define		STIMESEL        	0x18
+-#define		ENSTIMER        	0x04
+-#define		ACTNEGEN        	0x02
+-#define		STPWEN          	0x01
+-
+-#define	SCSISIGO        		0x03
+-#define		CDO             	0x80
+-#define		IOO             	0x40
+-#define		MSGO            	0x20
+-#define		ATNO            	0x10
+-#define		SELO            	0x08
+-#define		BSYO            	0x04
+-#define		REQO            	0x02
+-#define		ACKO            	0x01
+-
+-#define	SCSISIGI        		0x03
+-#define		ATNI            	0x10
+-#define		SELI            	0x08
+-#define		BSYI            	0x04
+-#define		REQI            	0x02
+-#define		ACKI            	0x01
+-
+-#define	SCSIRATE        		0x04
+-#define		WIDEXFER        	0x80
+-#define		SXFR_ULTRA2     	0x7f
+-#define		SXFR            	0x70
+-#define		SOFS            	0x0f
+-
+-#define	SCSIID          		0x05
+-#define	SCSIOFFSET      		0x05
+-#define		SOFS_ULTRA2     	0x7f
+-
+-#define	SCSIDATL        		0x06
+-
+-#define	SCSIDATH        		0x07
+-
+-#define	STCNT           		0x08
+-
+-#define	OPTIONMODE      		0x08
+-#define		AUTORATEEN      	0x80
+-#define		AUTOACKEN       	0x40
+-#define		ATNMGMNTEN      	0x20
+-#define		BUSFREEREV      	0x10
+-#define		EXPPHASEDIS     	0x08
+-#define		SCSIDATL_IMGEN  	0x04
+-#define		AUTO_MSGOUT_DE  	0x02
+-#define		DIS_MSGIN_DUALEDGE	0x01
+-
+-#define	CLRSINT0        		0x0b
+-#define		CLRSELDO        	0x40
+-#define		CLRSELDI        	0x20
+-#define		CLRSELINGO      	0x10
+-#define		CLRSWRAP        	0x08
+-#define		CLRSPIORDY      	0x02
+-
+-#define	SSTAT0          		0x0b
+-#define		TARGET          	0x80
+-#define		SELDO           	0x40
+-#define		SELDI           	0x20
+-#define		SELINGO         	0x10
+-#define		IOERR           	0x08
+-#define		SWRAP           	0x08
+-#define		SDONE           	0x04
+-#define		SPIORDY         	0x02
+-#define		DMADONE         	0x01
+-
+-#define	CLRSINT1        		0x0c
+-#define		CLRSELTIMEO     	0x80
+-#define		CLRATNO         	0x40
+-#define		CLRSCSIRSTI     	0x20
+-#define		CLRBUSFREE      	0x08
+-#define		CLRSCSIPERR     	0x04
+-#define		CLRPHASECHG     	0x02
+-#define		CLRREQINIT      	0x01
+-
+-#define	SSTAT1          		0x0c
+-#define		SELTO           	0x80
+-#define		ATNTARG         	0x40
+-#define		SCSIRSTI        	0x20
+-#define		PHASEMIS        	0x10
+-#define		BUSFREE         	0x08
+-#define		SCSIPERR        	0x04
+-#define		PHASECHG        	0x02
+-#define		REQINIT         	0x01
+-
+-#define	SSTAT2          		0x0d
+-#define		OVERRUN         	0x80
+-#define		SHVALID         	0x40
+-#define		WIDE_RES        	0x20
+-#define		SFCNT           	0x1f
+-#define		EXP_ACTIVE      	0x10
+-#define		CRCVALERR       	0x08
+-#define		CRCENDERR       	0x04
+-#define		CRCREQERR       	0x02
+-#define		DUAL_EDGE_ERROR 	0x01
+-
+-#define	SSTAT3          		0x0e
+-#define		SCSICNT         	0xf0
+-#define		OFFCNT          	0x0f
+-
+-#define	SCSIID_ULTRA2   		0x0f
+-#define		OID             	0x0f
+-
+-#define	SIMODE0         		0x10
+-#define		ENSELDO         	0x40
+-#define		ENSELDI         	0x20
+-#define		ENSELINGO       	0x10
+-#define		ENIOERR         	0x08
+-#define		ENSWRAP         	0x08
+-#define		ENSDONE         	0x04
+-#define		ENSPIORDY       	0x02
+-#define		ENDMADONE       	0x01
+-
+-#define	SIMODE1         		0x11
+-#define		ENSELTIMO       	0x80
+-#define		ENATNTARG       	0x40
+-#define		ENSCSIRST       	0x20
+-#define		ENPHASEMIS      	0x10
+-#define		ENBUSFREE       	0x08
+-#define		ENSCSIPERR      	0x04
+-#define		ENPHASECHG      	0x02
+-#define		ENREQINIT       	0x01
+-
+-#define	SCSIBUSL        		0x12
+-
+-#define	SCSIBUSH        		0x13
+-
+-#define	SHADDR          		0x14
+-
+-#define	SELTIMER        		0x18
+-#define		STAGE6          	0x20
+-#define		STAGE5          	0x10
+-#define		STAGE4          	0x08
+-#define		STAGE3          	0x04
+-#define		STAGE2          	0x02
+-#define		STAGE1          	0x01
+-
+-#define	SELID           		0x19
+-#define		SELID_MASK      	0xf0
+-#define		ONEBIT          	0x08
+-
+-#define	SPIOCAP         		0x1b
+-#define		SOFT1           	0x80
+-#define		SOFT0           	0x40
+-#define		SOFTCMDEN       	0x20
+-#define		HAS_BRDCTL      	0x10
+-#define		SEEPROM         	0x08
+-#define		EEPROM          	0x04
+-#define		ROM             	0x02
+-#define		SSPIOCPS        	0x01
+-
+-#define	BRDCTL          		0x1d
+-#define		BRDDAT7         	0x80
+-#define		BRDDAT6         	0x40
+-#define		BRDDAT5         	0x20
+-#define		BRDDAT4         	0x10
+-#define		BRDSTB          	0x10
+-#define		BRDCS           	0x08
+-#define		BRDDAT3         	0x08
+-#define		BRDDAT2         	0x04
+-#define		BRDRW           	0x04
+-#define		BRDRW_ULTRA2    	0x02
+-#define		BRDCTL1         	0x02
+-#define		BRDCTL0         	0x01
+-#define		BRDSTB_ULTRA2   	0x01
+-
+-#define	SEECTL          		0x1e
+-#define		EXTARBACK       	0x80
+-#define		EXTARBREQ       	0x40
+-#define		SEEMS           	0x20
+-#define		SEERDY          	0x10
+-#define		SEECS           	0x08
+-#define		SEECK           	0x04
+-#define		SEEDO           	0x02
+-#define		SEEDI           	0x01
+-
+-#define	SBLKCTL         		0x1f
+-#define		DIAGLEDEN       	0x80
+-#define		DIAGLEDON       	0x40
+-#define		AUTOFLUSHDIS    	0x20
+-#define		ENAB40          	0x08
+-#define		ENAB20          	0x04
+-#define		SELWIDE         	0x02
+-#define		XCVR            	0x01
+-
+-#define	SRAM_BASE       		0x20
+-
+-#define	TARG_SCSIRATE   		0x20
+-
+-#define	ULTRA_ENB       		0x30
+-
+-#define	DISC_DSB        		0x32
+-
+-#define	MSG_OUT         		0x34
+-
+-#define	DMAPARAMS       		0x35
+-#define		PRELOADEN       	0x80
+-#define		WIDEODD         	0x40
+-#define		SCSIEN          	0x20
+-#define		SDMAENACK       	0x10
+-#define		SDMAEN          	0x10
+-#define		HDMAEN          	0x08
+-#define		HDMAENACK       	0x08
+-#define		DIRECTION       	0x04
+-#define		FIFOFLUSH       	0x02
+-#define		FIFORESET       	0x01
+-
+-#define	SEQ_FLAGS       		0x36
+-#define		IDENTIFY_SEEN   	0x80
+-#define		SCBPTR_VALID    	0x20
+-#define		DPHASE          	0x10
+-#define		AMTARGET        	0x08
+-#define		WIDE_BUS        	0x02
+-#define		TWIN_BUS        	0x01
+-
+-#define	SAVED_TCL       		0x37
+-
+-#define	SG_COUNT        		0x38
+-
+-#define	SG_NEXT         		0x39
+-
+-#define	LASTPHASE       		0x3d
+-#define		P_MESGIN        	0xe0
+-#define		PHASE_MASK      	0xe0
+-#define		P_STATUS        	0xc0
+-#define		P_MESGOUT       	0xa0
+-#define		P_COMMAND       	0x80
+-#define		CDI             	0x80
+-#define		IOI             	0x40
+-#define		P_DATAIN        	0x40
+-#define		MSGI            	0x20
+-#define		P_BUSFREE       	0x01
+-#define		P_DATAOUT       	0x00
+-
+-#define	WAITING_SCBH    		0x3e
+-
+-#define	DISCONNECTED_SCBH		0x3f
+-
+-#define	FREE_SCBH       		0x40
+-
+-#define	HSCB_ADDR       		0x41
+-
+-#define	SCBID_ADDR      		0x45
+-
+-#define	TMODE_CMDADDR   		0x49
+-
+-#define	KERNEL_QINPOS   		0x4d
+-
+-#define	QINPOS          		0x4e
+-
+-#define	QOUTPOS         		0x4f
+-
+-#define	TMODE_CMDADDR_NEXT		0x50
+-
+-#define	ARG_1           		0x51
+-#define	RETURN_1        		0x51
+-#define		SEND_MSG        	0x80
+-#define		SEND_SENSE      	0x40
+-#define		SEND_REJ        	0x20
+-#define		MSGOUT_PHASEMIS 	0x10
+-
+-#define	ARG_2           		0x52
+-#define	RETURN_2        		0x52
+-
+-#define	LAST_MSG        		0x53
+-
+-#define	PREFETCH_CNT    		0x54
+-
+-#define	SCSICONF        		0x5a
+-#define		TERM_ENB        	0x80
+-#define		RESET_SCSI      	0x40
+-#define		HWSCSIID        	0x0f
+-#define		HSCSIID         	0x07
+-
+-#define	HOSTCONF        		0x5d
+-
+-#define	HA_274_BIOSCTRL 		0x5f
+-#define		BIOSMODE        	0x30
+-#define		BIOSDISABLED    	0x30
+-#define		CHANNEL_B_PRIMARY	0x08
+-
+-#define	SEQCTL          		0x60
+-#define		PERRORDIS       	0x80
+-#define		PAUSEDIS        	0x40
+-#define		FAILDIS         	0x20
+-#define		FASTMODE        	0x10
+-#define		BRKADRINTEN     	0x08
+-#define		STEP            	0x04
+-#define		SEQRESET        	0x02
+-#define		LOADRAM         	0x01
+-
+-#define	SEQRAM          		0x61
+-
+-#define	SEQADDR0        		0x62
+-
+-#define	SEQADDR1        		0x63
+-#define		SEQADDR1_MASK   	0x01
+-
+-#define	ACCUM           		0x64
+-
+-#define	SINDEX          		0x65
+-
+-#define	DINDEX          		0x66
+-
+-#define	ALLONES         		0x69
+-
+-#define	ALLZEROS        		0x6a
+-
+-#define	NONE            		0x6a
+-
+-#define	FLAGS           		0x6b
+-#define		ZERO            	0x02
+-#define		CARRY           	0x01
+-
+-#define	SINDIR          		0x6c
+-
+-#define	DINDIR          		0x6d
+-
+-#define	FUNCTION1       		0x6e
+-
+-#define	STACK           		0x6f
+-
+-#define	TARG_OFFSET     		0x70
+-
+-#define	BCTL            		0x84
+-#define		ACE             	0x08
+-#define		ENABLE          	0x01
+-
+-#define	DSCOMMAND0      		0x84
+-#define		INTSCBRAMSEL    	0x08
+-#define		RAMPS           	0x04
+-#define		USCBSIZE32      	0x02
+-#define		CIOPARCKEN      	0x01
+-
+-#define	DSCOMMAND       		0x84
+-#define		CACHETHEN       	0x80
+-#define		DPARCKEN        	0x40
+-#define		MPARCKEN        	0x20
+-#define		EXTREQLCK       	0x10
+-
+-#define	BUSTIME         		0x85
+-#define		BOFF            	0xf0
+-#define		BON             	0x0f
+-
+-#define	BUSSPD          		0x86
+-#define		DFTHRSH         	0xc0
+-#define		STBOFF          	0x38
+-#define		STBON           	0x07
+-
+-#define	DSPCISTATUS     		0x86
+-#define		DFTHRSH_100     	0xc0
+-
+-#define	HCNTRL          		0x87
+-#define		POWRDN          	0x40
+-#define		SWINT           	0x10
+-#define		IRQMS           	0x08
+-#define		PAUSE           	0x04
+-#define		INTEN           	0x02
+-#define		CHIPRST         	0x01
+-#define		CHIPRSTACK      	0x01
+-
+-#define	HADDR           		0x88
+-
+-#define	HCNT            		0x8c
+-
+-#define	SCBPTR          		0x90
+-
+-#define	INTSTAT         		0x91
+-#define		SEQINT_MASK     	0xf1
+-#define		DATA_OVERRUN    	0xe1
+-#define		MSGIN_PHASEMIS  	0xd1
+-#define		TRACEPOINT2     	0xc1
+-#define		TRACEPOINT      	0xb1
+-#define		AWAITING_MSG    	0xa1
+-#define		RESIDUAL        	0x81
+-#define		BAD_STATUS      	0x71
+-#define		REJECT_MSG      	0x61
+-#define		WIDE_RESIDUE    	0x51
+-#define		EXTENDED_MSG    	0x41
+-#define		NO_MATCH        	0x31
+-#define		NO_IDENT        	0x21
+-#define		SEND_REJECT     	0x11
+-#define		INT_PEND        	0x0f
+-#define		BRKADRINT       	0x08
+-#define		SCSIINT         	0x04
+-#define		CMDCMPLT        	0x02
+-#define		BAD_PHASE       	0x01
+-#define		SEQINT          	0x01
+-
+-#define	CLRINT          		0x92
+-#define		CLRPARERR       	0x10
+-#define		CLRBRKADRINT    	0x08
+-#define		CLRSCSIINT      	0x04
+-#define		CLRCMDINT       	0x02
+-#define		CLRSEQINT       	0x01
+-
+-#define	ERROR           		0x92
+-#define		CIOPARERR       	0x80
+-#define		PCIERRSTAT      	0x40
+-#define		MPARERR         	0x20
+-#define		DPARERR         	0x10
+-#define		SQPARERR        	0x08
+-#define		ILLOPCODE       	0x04
+-#define		DSCTMOUT        	0x02
+-#define		ILLSADDR        	0x02
+-#define		ILLHADDR        	0x01
+-
+-#define	DFCNTRL         		0x93
+-
+-#define	DFSTATUS        		0x94
+-#define		PRELOAD_AVAIL   	0x80
+-#define		DWORDEMP        	0x20
+-#define		MREQPEND        	0x10
+-#define		HDONE           	0x08
+-#define		DFTHRESH        	0x04
+-#define		FIFOFULL        	0x02
+-#define		FIFOEMP         	0x01
+-
+-#define	DFDAT           		0x99
+-
+-#define	SCBCNT          		0x9a
+-#define		SCBAUTO         	0x80
+-#define		SCBCNT_MASK     	0x1f
+-
+-#define	QINFIFO         		0x9b
+-
+-#define	QINCNT          		0x9c
+-
+-#define	SCSIDATL_IMG    		0x9c
+-
+-#define	QOUTFIFO        		0x9d
+-
+-#define	CRCCONTROL1     		0x9d
+-#define		CRCONSEEN       	0x80
+-#define		CRCVALCHKEN     	0x40
+-#define		CRCENDCHKEN     	0x20
+-#define		CRCREQCHKEN     	0x10
+-#define		TARGCRCENDEN    	0x08
+-#define		TARGCRCCNTEN    	0x04
+-
+-#define	QOUTCNT         		0x9e
+-
+-#define	SCSIPHASE       		0x9e
+-#define		SP_STATUS       	0x20
+-#define		SP_COMMAND      	0x10
+-#define		SP_MSG_IN       	0x08
+-#define		SP_MSG_OUT      	0x04
+-#define		SP_DATA_IN      	0x02
+-#define		SP_DATA_OUT     	0x01
+-
+-#define	SFUNCT          		0x9f
+-#define		ALT_MODE        	0x80
+-
+-#define	SCB_CONTROL     		0xa0
+-#define		MK_MESSAGE      	0x80
+-#define		DISCENB         	0x40
+-#define		TAG_ENB         	0x20
+-#define		DISCONNECTED    	0x04
+-#define		SCB_TAG_TYPE    	0x03
+-
+-#define	SCB_BASE        		0xa0
+-
+-#define	SCB_TCL         		0xa1
+-#define		TID             	0xf0
+-#define		SELBUSB         	0x08
+-#define		LID             	0x07
+-
+-#define	SCB_TARGET_STATUS		0xa2
+-
+-#define	SCB_SGCOUNT     		0xa3
+-
+-#define	SCB_SGPTR       		0xa4
+-
+-#define	SCB_RESID_SGCNT 		0xa8
+-
+-#define	SCB_RESID_DCNT  		0xa9
+-
+-#define	SCB_DATAPTR     		0xac
+-
+-#define	SCB_DATACNT     		0xb0
+-
+-#define	SCB_CMDPTR      		0xb4
+-
+-#define	SCB_CMDLEN      		0xb8
+-
+-#define	SCB_TAG         		0xb9
+-
+-#define	SCB_NEXT        		0xba
+-
+-#define	SCB_PREV        		0xbb
+-
+-#define	SCB_BUSYTARGETS 		0xbc
+-
+-#define	SEECTL_2840     		0xc0
+-#define		CS_2840         	0x04
+-#define		CK_2840         	0x02
+-#define		DO_2840         	0x01
+-
+-#define	STATUS_2840     		0xc1
+-#define		EEPROM_TF       	0x80
+-#define		BIOS_SEL        	0x60
+-#define		ADSEL           	0x1e
+-#define		DI_2840         	0x01
+-
+-#define	CCHADDR         		0xe0
+-
+-#define	CCHCNT          		0xe8
+-
+-#define	CCSGRAM         		0xe9
+-
+-#define	CCSGADDR        		0xea
+-
+-#define	CCSGCTL         		0xeb
+-#define		CCSGDONE        	0x80
+-#define		CCSGEN          	0x08
+-#define		FLAG            	0x02
+-#define		CCSGRESET       	0x01
+-
+-#define	CCSCBRAM        		0xec
+-
+-#define	CCSCBADDR       		0xed
+-
+-#define	CCSCBCTL        		0xee
+-#define		CCSCBDONE       	0x80
+-#define		ARRDONE         	0x40
+-#define		CCARREN         	0x10
+-#define		CCSCBEN         	0x08
+-#define		CCSCBDIR        	0x04
+-#define		CCSCBRESET      	0x01
+-
+-#define	CCSCBCNT        		0xef
+-
+-#define	CCSCBPTR        		0xf1
+-
+-#define	HNSCB_QOFF      		0xf4
+-
+-#define	HESCB_QOFF      		0xf5
+-
+-#define	SNSCB_QOFF      		0xf6
+-
+-#define	SESCB_QOFF      		0xf7
+-
+-#define	SDSCB_QOFF      		0xf8
+-
+-#define	QOFF_CTLSTA     		0xfa
+-#define		ESTABLISH_SCB_AVAIL	0x80
+-#define		SCB_AVAIL       	0x40
+-#define		SNSCB_ROLLOVER  	0x20
+-#define		SDSCB_ROLLOVER  	0x10
+-#define		SESCB_ROLLOVER  	0x08
+-#define		SCB_QSIZE       	0x07
+-#define		SCB_QSIZE_256   	0x06
+-
+-#define	DFF_THRSH       		0xfb
+-#define		WR_DFTHRSH      	0x70
+-#define		WR_DFTHRSH_MAX  	0x70
+-#define		WR_DFTHRSH_90   	0x60
+-#define		WR_DFTHRSH_85   	0x50
+-#define		WR_DFTHRSH_75   	0x40
+-#define		WR_DFTHRSH_63   	0x30
+-#define		WR_DFTHRSH_50   	0x20
+-#define		WR_DFTHRSH_25   	0x10
+-#define		RD_DFTHRSH_MAX  	0x07
+-#define		RD_DFTHRSH      	0x07
+-#define		RD_DFTHRSH_90   	0x06
+-#define		RD_DFTHRSH_85   	0x05
+-#define		RD_DFTHRSH_75   	0x04
+-#define		RD_DFTHRSH_63   	0x03
+-#define		RD_DFTHRSH_50   	0x02
+-#define		RD_DFTHRSH_25   	0x01
+-#define		RD_DFTHRSH_MIN  	0x00
+-#define		WR_DFTHRSH_MIN  	0x00
+-
+-#define	SG_CACHEPTR     		0xfc
+-#define		SG_USER_DATA    	0xfc
+-#define		LAST_SEG        	0x02
+-#define		LAST_SEG_DONE   	0x01
+-
+-
+-#define	CMD_GROUP_CODE_SHIFT	0x05
+-#define	BUS_8_BIT	0x00
+-#define	QOUTFIFO_OFFSET	0x01
+-#define	CCSGRAM_MAXSEGS	0x10
+-#define	CMD_GROUP2_BYTE_DELTA	0xfa
+-#define	MAX_OFFSET_8BIT	0x0f
+-#define	BUS_16_BIT	0x01
+-#define	QINFIFO_OFFSET	0x02
+-#define	CMD_GROUP5_BYTE_DELTA	0x0b
+-#define	MAX_OFFSET_ULTRA2	0x7f
+-#define	MAX_OFFSET_16BIT	0x08
+-#define	UNTAGGEDSCB_OFFSET	0x00
+-#define	SCB_LIST_NULL	0xff
+-#define	SG_SIZEOF	0x08
+-#define	CMD_GROUP4_BYTE_DELTA	0x04
+-#define	CMD_GROUP0_BYTE_DELTA	0xfc
+-#define	HOST_MSG	0xff
+-#define	BUS_32_BIT	0x02
+-#define	CCSGADDR_MAX	0x80
+-
+-
+-/* Downloaded Constant Definitions */
+-#define	TMODE_NUMCMDS	0x00
+diff -U 3 -rN linux-2.2.17/drivers/scsi/aic7xxx_seq.c linux/drivers/scsi/aic7xxx_seq.c
+--- linux-2.2.17/drivers/scsi/aic7xxx_seq.c	Mon Sep  4 13:39:21 2000
++++ linux/drivers/scsi/aic7xxx_seq.c	Wed Dec 31 19:00:00 1969
+@@ -1,745 +0,0 @@
+-/*
+-  * DO NOT EDIT - This file is automatically generated.
+-  */
+-static unsigned char seqprog[] = {
+-	0xff, 0x6a, 0x06, 0x08,
+-	0x7f, 0x02, 0x04, 0x08,
+-	0x12, 0x6a, 0x00, 0x00,
+-	0xff, 0x6a, 0xd6, 0x09,
+-	0xff, 0x6a, 0xdc, 0x09,
+-	0x00, 0x65, 0xca, 0x58,
+-	0xf7, 0x01, 0x02, 0x08,
+-	0xff, 0x4e, 0xc8, 0x08,
+-	0xbf, 0x60, 0xc0, 0x08,
+-	0x60, 0x0b, 0x86, 0x68,
+-	0x40, 0x00, 0x0c, 0x68,
+-	0x08, 0x1f, 0x3e, 0x10,
+-	0x60, 0x0b, 0x86, 0x68,
+-	0x40, 0x00, 0x0c, 0x68,
+-	0x08, 0x1f, 0x3e, 0x10,
+-	0xff, 0x3e, 0x48, 0x60,
+-	0x40, 0xfa, 0x10, 0x78,
+-	0xff, 0xf6, 0xd4, 0x08,
+-	0x01, 0x4e, 0x9c, 0x18,
+-	0x40, 0x60, 0xc0, 0x00,
+-	0x00, 0x4d, 0x10, 0x70,
+-	0x01, 0x4e, 0x9c, 0x18,
+-	0xbf, 0x60, 0xc0, 0x08,
+-	0x00, 0x6a, 0x3e, 0x5c,
+-	0xff, 0x4e, 0xc8, 0x18,
+-	0x02, 0x6a, 0x54, 0x5b,
+-	0xff, 0x52, 0x20, 0x09,
+-	0x0d, 0x6a, 0x6a, 0x00,
+-	0x00, 0x52, 0xca, 0x5b,
+-	0x03, 0xb0, 0x52, 0x31,
+-	0xff, 0xb0, 0x52, 0x09,
+-	0xff, 0xb1, 0x54, 0x09,
+-	0xff, 0xb2, 0x56, 0x09,
+-	0xff, 0xa3, 0x50, 0x09,
+-	0xff, 0x3e, 0x74, 0x09,
+-	0xff, 0x90, 0x7c, 0x08,
+-	0xff, 0x3e, 0x20, 0x09,
+-	0x00, 0x65, 0x4e, 0x58,
+-	0x00, 0x65, 0x0c, 0x40,
+-	0xf7, 0x1f, 0xca, 0x08,
+-	0x08, 0xa1, 0xc8, 0x08,
+-	0x00, 0x65, 0xca, 0x00,
+-	0xff, 0x65, 0x3e, 0x08,
+-	0xf0, 0xa1, 0xc8, 0x08,
+-	0x0f, 0x0f, 0x1e, 0x08,
+-	0x00, 0x0f, 0x1e, 0x00,
+-	0xf0, 0xa1, 0xc8, 0x08,
+-	0x0f, 0x05, 0x0a, 0x08,
+-	0x00, 0x05, 0x0a, 0x00,
+-	0xff, 0x6a, 0x0c, 0x08,
+-	0x5a, 0x6a, 0x00, 0x04,
+-	0x12, 0x65, 0x02, 0x00,
+-	0x31, 0x6a, 0xca, 0x00,
+-	0x80, 0x37, 0x6e, 0x68,
+-	0xff, 0x65, 0xca, 0x18,
+-	0xff, 0x37, 0xdc, 0x08,
+-	0xff, 0x6e, 0xc8, 0x08,
+-	0x00, 0x6c, 0x76, 0x78,
+-	0x20, 0x01, 0x02, 0x00,
+-	0x4c, 0x37, 0xc8, 0x28,
+-	0x08, 0x1f, 0x7e, 0x78,
+-	0x08, 0x37, 0x6e, 0x00,
+-	0x08, 0x64, 0xc8, 0x00,
+-	0x70, 0x64, 0xca, 0x18,
+-	0xff, 0x6c, 0x0a, 0x08,
+-	0x20, 0x64, 0xca, 0x18,
+-	0xff, 0x6c, 0x08, 0x0c,
+-	0x40, 0x0b, 0x96, 0x68,
+-	0x20, 0x6a, 0x16, 0x00,
+-	0xf0, 0x19, 0x6e, 0x08,
+-	0x08, 0x6a, 0x18, 0x00,
+-	0x08, 0x11, 0x22, 0x00,
+-	0x08, 0x6a, 0x66, 0x58,
+-	0x08, 0x6a, 0x68, 0x00,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x12, 0x6a, 0x00, 0x00,
+-	0x40, 0x6a, 0x16, 0x00,
+-	0xff, 0x3e, 0x20, 0x09,
+-	0xff, 0xba, 0x7c, 0x08,
+-	0xff, 0xa1, 0x6e, 0x08,
+-	0x08, 0x6a, 0x18, 0x00,
+-	0x08, 0x11, 0x22, 0x00,
+-	0x08, 0x6a, 0x66, 0x58,
+-	0x80, 0x6a, 0x68, 0x00,
+-	0x80, 0x36, 0x6c, 0x00,
+-	0x00, 0x65, 0x9e, 0x5b,
+-	0xff, 0x3d, 0xc8, 0x08,
+-	0xbf, 0x64, 0xe2, 0x78,
+-	0x80, 0x64, 0xac, 0x71,
+-	0xa0, 0x64, 0xdc, 0x71,
+-	0xc0, 0x64, 0xd4, 0x71,
+-	0xe0, 0x64, 0x1c, 0x72,
+-	0x01, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0xf7, 0x11, 0x22, 0x08,
+-	0x00, 0x65, 0xca, 0x58,
+-	0xff, 0x06, 0xd4, 0x08,
+-	0xf7, 0x01, 0x02, 0x08,
+-	0x09, 0x0c, 0xc4, 0x78,
+-	0x08, 0x0c, 0x0c, 0x68,
+-	0x01, 0x6a, 0x22, 0x01,
+-	0xff, 0x6a, 0x26, 0x09,
+-	0x02, 0x6a, 0x08, 0x30,
+-	0xff, 0x6a, 0x08, 0x08,
+-	0xdf, 0x01, 0x02, 0x08,
+-	0x01, 0x6a, 0x7a, 0x00,
+-	0xff, 0x6a, 0x6c, 0x0c,
+-	0x04, 0x14, 0x10, 0x31,
+-	0x03, 0xa9, 0x18, 0x31,
+-	0x03, 0xa9, 0x10, 0x30,
+-	0x08, 0x6a, 0xcc, 0x00,
+-	0xa9, 0x6a, 0xb4, 0x5b,
+-	0x00, 0x65, 0x02, 0x41,
+-	0xa8, 0x6a, 0x6a, 0x00,
+-	0x79, 0x6a, 0x6a, 0x00,
+-	0x40, 0x3d, 0xea, 0x68,
+-	0x04, 0x35, 0x6a, 0x00,
+-	0x00, 0x65, 0x0e, 0x5b,
+-	0x80, 0x6a, 0xd4, 0x01,
+-	0x10, 0x36, 0xd6, 0x68,
+-	0x10, 0x36, 0x6c, 0x00,
+-	0x07, 0xac, 0x10, 0x31,
+-	0x03, 0x8c, 0x10, 0x30,
+-	0x05, 0xa3, 0x70, 0x30,
+-	0x88, 0x6a, 0xcc, 0x00,
+-	0xac, 0x6a, 0xac, 0x5b,
+-	0x00, 0x65, 0xa6, 0x5b,
+-	0x38, 0x6a, 0xcc, 0x00,
+-	0xa3, 0x6a, 0xb0, 0x5b,
+-	0xff, 0x38, 0x12, 0x69,
+-	0x80, 0x02, 0x04, 0x00,
+-	0xe7, 0x35, 0x6a, 0x08,
+-	0x03, 0x69, 0x18, 0x31,
+-	0x03, 0x69, 0x10, 0x30,
+-	0xff, 0x6a, 0x10, 0x00,
+-	0xff, 0x6a, 0x12, 0x00,
+-	0xff, 0x6a, 0x14, 0x00,
+-	0x01, 0x38, 0x18, 0x61,
+-	0xbf, 0x35, 0x6a, 0x08,
+-	0x02, 0x6a, 0xf8, 0x01,
+-	0xff, 0x69, 0xca, 0x08,
+-	0xff, 0x35, 0x26, 0x09,
+-	0x04, 0x0b, 0x1c, 0x69,
+-	0x04, 0x0b, 0x28, 0x69,
+-	0x10, 0x0c, 0x1e, 0x79,
+-	0x04, 0x0b, 0x28, 0x69,
+-	0xff, 0x6a, 0xca, 0x08,
+-	0x00, 0x35, 0xee, 0x5a,
+-	0x80, 0x02, 0x7c, 0x69,
+-	0xff, 0x65, 0x6c, 0x79,
+-	0xff, 0x38, 0x70, 0x18,
+-	0xff, 0x38, 0x6c, 0x79,
+-	0x80, 0xea, 0x48, 0x61,
+-	0xef, 0x38, 0xc8, 0x18,
+-	0x80, 0x6a, 0xc8, 0x00,
+-	0x00, 0x65, 0x3a, 0x49,
+-	0x33, 0x38, 0xc8, 0x28,
+-	0xff, 0x64, 0xd0, 0x09,
+-	0x04, 0x39, 0xc0, 0x31,
+-	0x09, 0x6a, 0xd6, 0x01,
+-	0x80, 0xeb, 0x40, 0x79,
+-	0xf7, 0xeb, 0xd6, 0x09,
+-	0x08, 0xeb, 0x44, 0x69,
+-	0x01, 0x6a, 0xd6, 0x01,
+-	0x08, 0xe9, 0x10, 0x31,
+-	0x03, 0x8c, 0x10, 0x30,
+-	0x88, 0x6a, 0xcc, 0x00,
+-	0x39, 0x6a, 0xb2, 0x5b,
+-	0x08, 0x6a, 0x18, 0x01,
+-	0xff, 0x6a, 0x1a, 0x09,
+-	0xff, 0x6a, 0x1c, 0x09,
+-	0x0d, 0x93, 0x26, 0x01,
+-	0x00, 0x65, 0x30, 0x5c,
+-	0x88, 0x6a, 0x20, 0x5c,
+-	0x00, 0x65, 0xa6, 0x5b,
+-	0xff, 0x6a, 0xc8, 0x08,
+-	0x08, 0x39, 0x72, 0x18,
+-	0x00, 0x3a, 0x74, 0x20,
+-	0x01, 0x0c, 0x64, 0x79,
+-	0x10, 0x0c, 0x02, 0x79,
+-	0xff, 0x35, 0x26, 0x09,
+-	0x04, 0x0b, 0x6a, 0x69,
+-	0x00, 0x65, 0x84, 0x59,
+-	0x03, 0x08, 0x52, 0x31,
+-	0xff, 0x38, 0x50, 0x09,
+-	0xff, 0x08, 0x52, 0x09,
+-	0xff, 0x09, 0x54, 0x09,
+-	0xff, 0x0a, 0x56, 0x09,
+-	0xff, 0x38, 0x50, 0x09,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x00, 0x65, 0x84, 0x59,
+-	0x7f, 0x02, 0x04, 0x08,
+-	0xe1, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x04, 0x93, 0x9a, 0x69,
+-	0xdf, 0x93, 0x26, 0x09,
+-	0x20, 0x93, 0x88, 0x69,
+-	0x02, 0x93, 0x26, 0x01,
+-	0x01, 0x94, 0x8a, 0x79,
+-	0x01, 0x94, 0x8a, 0x79,
+-	0x01, 0x94, 0x8a, 0x79,
+-	0x01, 0x94, 0x8a, 0x79,
+-	0x01, 0x94, 0x8a, 0x79,
+-	0x01, 0x94, 0x8a, 0x79,
+-	0x10, 0x94, 0x98, 0x69,
+-	0x7f, 0x05, 0xa0, 0x69,
+-	0x02, 0x03, 0xa0, 0x79,
+-	0x11, 0x0c, 0x9c, 0x79,
+-	0xd7, 0x93, 0x26, 0x09,
+-	0x28, 0x93, 0xa2, 0x69,
+-	0x03, 0x08, 0x52, 0x31,
+-	0xff, 0x38, 0x50, 0x09,
+-	0x12, 0x01, 0x02, 0x00,
+-	0xff, 0x6a, 0xd4, 0x0c,
+-	0x00, 0x65, 0x0e, 0x5b,
+-	0x05, 0xb4, 0x10, 0x31,
+-	0x02, 0x6a, 0x1a, 0x31,
+-	0x03, 0x8c, 0x10, 0x30,
+-	0x88, 0x6a, 0xcc, 0x00,
+-	0xb4, 0x6a, 0xb0, 0x5b,
+-	0xff, 0x6a, 0x1a, 0x09,
+-	0xff, 0x6a, 0x1c, 0x09,
+-	0x00, 0x65, 0xa6, 0x5b,
+-	0x3d, 0x6a, 0xee, 0x5a,
+-	0xac, 0x6a, 0x26, 0x01,
+-	0x04, 0x0b, 0xc2, 0x69,
+-	0x04, 0x0b, 0xc8, 0x69,
+-	0x10, 0x0c, 0xc4, 0x79,
+-	0x02, 0x03, 0xcc, 0x79,
+-	0x11, 0x0c, 0xc8, 0x79,
+-	0xd7, 0x93, 0x26, 0x09,
+-	0x28, 0x93, 0xce, 0x69,
+-	0x12, 0x01, 0x02, 0x00,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x00, 0x65, 0x0e, 0x5b,
+-	0xff, 0x06, 0x44, 0x09,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x10, 0x3d, 0x06, 0x00,
+-	0xff, 0x34, 0xca, 0x08,
+-	0x80, 0x65, 0x00, 0x62,
+-	0x0f, 0xa1, 0xca, 0x08,
+-	0x07, 0xa1, 0xca, 0x08,
+-	0x40, 0xa0, 0xc8, 0x08,
+-	0x00, 0x65, 0xca, 0x00,
+-	0x80, 0x65, 0xca, 0x00,
+-	0x80, 0xa0, 0xf0, 0x79,
+-	0xff, 0x65, 0x0c, 0x08,
+-	0x00, 0x65, 0x02, 0x42,
+-	0x20, 0xa0, 0x08, 0x7a,
+-	0xff, 0x65, 0x0c, 0x08,
+-	0x00, 0x65, 0x9e, 0x5b,
+-	0xa0, 0x3d, 0x10, 0x62,
+-	0x23, 0xa0, 0x0c, 0x08,
+-	0x00, 0x65, 0x9e, 0x5b,
+-	0xa0, 0x3d, 0x10, 0x62,
+-	0x00, 0xb9, 0x08, 0x42,
+-	0xff, 0x65, 0x08, 0x62,
+-	0xa1, 0x6a, 0x22, 0x01,
+-	0xff, 0x6a, 0xd4, 0x08,
+-	0x10, 0x51, 0x10, 0x72,
+-	0x40, 0x6a, 0x18, 0x00,
+-	0xff, 0x65, 0x0c, 0x08,
+-	0x00, 0x65, 0x9e, 0x5b,
+-	0xa0, 0x3d, 0xda, 0x71,
+-	0x40, 0x6a, 0x18, 0x00,
+-	0xff, 0x34, 0xa6, 0x08,
+-	0x80, 0x34, 0x18, 0x62,
+-	0x7f, 0xa0, 0x40, 0x09,
+-	0x08, 0x6a, 0x68, 0x00,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x64, 0x6a, 0xe4, 0x5a,
+-	0x80, 0x64, 0x8e, 0x6a,
+-	0x04, 0x64, 0x70, 0x72,
+-	0x02, 0x64, 0x76, 0x72,
+-	0x00, 0x6a, 0x38, 0x72,
+-	0x03, 0x64, 0x8a, 0x72,
+-	0x01, 0x64, 0x6c, 0x72,
+-	0x07, 0x64, 0xcc, 0x72,
+-	0x08, 0x64, 0x34, 0x72,
+-	0x23, 0x64, 0xd0, 0x72,
+-	0x11, 0x6a, 0x22, 0x01,
+-	0x07, 0x6a, 0xd6, 0x5a,
+-	0xff, 0x06, 0xd4, 0x08,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0xff, 0xa8, 0x3c, 0x6a,
+-	0xff, 0xa2, 0x54, 0x7a,
+-	0x01, 0x6a, 0x6a, 0x00,
+-	0x00, 0xb9, 0xca, 0x5b,
+-	0xff, 0xa2, 0x54, 0x7a,
+-	0x71, 0x6a, 0x22, 0x01,
+-	0xff, 0x6a, 0xd4, 0x08,
+-	0x40, 0x51, 0x54, 0x62,
+-	0x0d, 0x6a, 0x6a, 0x00,
+-	0x00, 0xb9, 0xca, 0x5b,
+-	0xff, 0x3e, 0x74, 0x09,
+-	0xff, 0x90, 0x7c, 0x08,
+-	0x00, 0x65, 0x4e, 0x58,
+-	0x00, 0x65, 0xbc, 0x40,
+-	0x20, 0xa0, 0x5c, 0x6a,
+-	0xff, 0x37, 0xc8, 0x08,
+-	0x00, 0x6a, 0x74, 0x5b,
+-	0xff, 0x6a, 0x8a, 0x5b,
+-	0xff, 0xf8, 0xc8, 0x08,
+-	0xff, 0x4f, 0xc8, 0x08,
+-	0x01, 0x6a, 0x74, 0x5b,
+-	0x00, 0xb9, 0x8a, 0x5b,
+-	0x01, 0x4f, 0x9e, 0x18,
+-	0x02, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0x38, 0x5c,
+-	0x00, 0x65, 0xbc, 0x40,
+-	0x41, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0x04, 0xa0, 0x40, 0x01,
+-	0x00, 0x65, 0x50, 0x5c,
+-	0x00, 0x65, 0xbc, 0x40,
+-	0x10, 0x36, 0x34, 0x7a,
+-	0x05, 0x38, 0x46, 0x31,
+-	0x04, 0x14, 0x58, 0x31,
+-	0x03, 0xa9, 0x60, 0x31,
+-	0xa3, 0x6a, 0xcc, 0x00,
+-	0x38, 0x6a, 0xb0, 0x5b,
+-	0xac, 0x6a, 0xcc, 0x00,
+-	0x14, 0x6a, 0xb2, 0x5b,
+-	0xa9, 0x6a, 0xb4, 0x5b,
+-	0x00, 0x65, 0x34, 0x42,
+-	0xef, 0x36, 0x6c, 0x08,
+-	0x00, 0x65, 0x34, 0x42,
+-	0x0f, 0x64, 0xc8, 0x08,
+-	0x07, 0x64, 0xc8, 0x08,
+-	0x00, 0x37, 0x6e, 0x00,
+-	0xff, 0x6a, 0xa4, 0x00,
+-	0x00, 0x65, 0x44, 0x5b,
+-	0xff, 0x51, 0xa0, 0x72,
+-	0x20, 0x36, 0xaa, 0x7a,
+-	0x00, 0x90, 0x32, 0x5b,
+-	0x00, 0x65, 0xac, 0x42,
+-	0xff, 0x06, 0xd4, 0x08,
+-	0x00, 0x65, 0x9e, 0x5b,
+-	0xe0, 0x3d, 0xc6, 0x62,
+-	0x20, 0x12, 0xc6, 0x62,
+-	0x51, 0x6a, 0xda, 0x5a,
+-	0x00, 0x65, 0x2c, 0x5b,
+-	0xff, 0x37, 0xc8, 0x08,
+-	0x00, 0xa1, 0xbe, 0x62,
+-	0x04, 0xa0, 0xbe, 0x7a,
+-	0xfb, 0xa0, 0x40, 0x09,
+-	0x80, 0x36, 0x6c, 0x00,
+-	0x80, 0xa0, 0x34, 0x7a,
+-	0x7f, 0xa0, 0x40, 0x09,
+-	0xff, 0x6a, 0xd6, 0x5a,
+-	0x00, 0x65, 0x34, 0x42,
+-	0x04, 0xa0, 0xc4, 0x7a,
+-	0x00, 0x65, 0x50, 0x5c,
+-	0x00, 0x65, 0xc6, 0x42,
+-	0x00, 0x65, 0x38, 0x5c,
+-	0x31, 0x6a, 0x22, 0x01,
+-	0x0c, 0x6a, 0xd6, 0x5a,
+-	0x00, 0x65, 0x34, 0x42,
+-	0x61, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0x34, 0x42,
+-	0x51, 0x6a, 0xda, 0x5a,
+-	0x51, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0x34, 0x42,
+-	0x10, 0x3d, 0x06, 0x00,
+-	0xff, 0x65, 0x68, 0x0c,
+-	0xff, 0x06, 0xd4, 0x08,
+-	0x01, 0x0c, 0xdc, 0x7a,
+-	0x04, 0x0c, 0xde, 0x6a,
+-	0xe0, 0x03, 0x7a, 0x08,
+-	0xe0, 0x3d, 0xea, 0x62,
+-	0xff, 0x65, 0xcc, 0x08,
+-	0xff, 0x12, 0xda, 0x0c,
+-	0xff, 0x06, 0xd4, 0x0c,
+-	0xd1, 0x6a, 0x22, 0x01,
+-	0x00, 0x65, 0xaa, 0x40,
+-	0xff, 0x65, 0x26, 0x09,
+-	0x01, 0x0b, 0xfe, 0x6a,
+-	0x10, 0x0c, 0xf0, 0x7a,
+-	0x04, 0x0b, 0xf8, 0x6a,
+-	0xff, 0x6a, 0xca, 0x08,
+-	0x04, 0x93, 0xfc, 0x6a,
+-	0x01, 0x94, 0xfa, 0x7a,
+-	0x10, 0x94, 0xfc, 0x6a,
+-	0x80, 0x3d, 0x02, 0x73,
+-	0x0f, 0x04, 0x06, 0x6b,
+-	0x02, 0x03, 0x06, 0x7b,
+-	0x11, 0x0c, 0x02, 0x7b,
+-	0xc7, 0x93, 0x26, 0x09,
+-	0xff, 0x99, 0xd4, 0x08,
+-	0x38, 0x93, 0x08, 0x6b,
+-	0xff, 0x6a, 0xd4, 0x0c,
+-	0x80, 0x36, 0x0c, 0x6b,
+-	0x21, 0x6a, 0x22, 0x05,
+-	0xff, 0x65, 0x20, 0x09,
+-	0xff, 0x51, 0x1a, 0x63,
+-	0xff, 0x37, 0xc8, 0x08,
+-	0xa1, 0x6a, 0x26, 0x43,
+-	0xff, 0x51, 0xc8, 0x08,
+-	0xb9, 0x6a, 0x26, 0x43,
+-	0xff, 0x90, 0xa4, 0x08,
+-	0xff, 0xba, 0x2a, 0x73,
+-	0xff, 0xba, 0x20, 0x09,
+-	0xff, 0x65, 0xca, 0x18,
+-	0x00, 0x6c, 0x1e, 0x63,
+-	0xff, 0x90, 0xca, 0x0c,
+-	0xff, 0x6a, 0xca, 0x04,
+-	0x20, 0x36, 0x3e, 0x7b,
+-	0x00, 0x90, 0x12, 0x5b,
+-	0xff, 0x65, 0x3e, 0x73,
+-	0xff, 0x52, 0x3c, 0x73,
+-	0xff, 0xba, 0xcc, 0x08,
+-	0xff, 0x52, 0x20, 0x09,
+-	0xff, 0x66, 0x74, 0x09,
+-	0xff, 0x65, 0x20, 0x0d,
+-	0xff, 0xba, 0x7e, 0x0c,
+-	0x00, 0x6a, 0x3e, 0x5c,
+-	0x0d, 0x6a, 0x6a, 0x00,
+-	0x00, 0x51, 0xca, 0x43,
+-	0xff, 0x3f, 0x98, 0x73,
+-	0xff, 0x6a, 0xa2, 0x00,
+-	0x00, 0x3f, 0x12, 0x5b,
+-	0xff, 0x65, 0x98, 0x73,
+-	0x20, 0x36, 0x6c, 0x00,
+-	0x20, 0xa0, 0x52, 0x6b,
+-	0xff, 0xb9, 0xa2, 0x0c,
+-	0xff, 0x6a, 0xa2, 0x04,
+-	0xff, 0x65, 0xa4, 0x08,
+-	0xe0, 0x6a, 0xcc, 0x00,
+-	0x45, 0x6a, 0xbe, 0x5b,
+-	0x01, 0x6a, 0xd0, 0x01,
+-	0x09, 0x6a, 0xd6, 0x01,
+-	0x80, 0xeb, 0x5e, 0x7b,
+-	0x01, 0x6a, 0xd6, 0x01,
+-	0x01, 0xe9, 0xa4, 0x34,
+-	0x88, 0x6a, 0xcc, 0x00,
+-	0x45, 0x6a, 0xbe, 0x5b,
+-	0x01, 0x6a, 0x18, 0x01,
+-	0xff, 0x6a, 0x1a, 0x09,
+-	0xff, 0x6a, 0x1c, 0x09,
+-	0x0d, 0x6a, 0x26, 0x01,
+-	0x00, 0x65, 0x30, 0x5c,
+-	0xff, 0x99, 0xa4, 0x0c,
+-	0xff, 0x65, 0xa4, 0x08,
+-	0xe0, 0x6a, 0xcc, 0x00,
+-	0x45, 0x6a, 0xbe, 0x5b,
+-	0x01, 0x6a, 0xd0, 0x01,
+-	0x01, 0x6a, 0xdc, 0x05,
+-	0x88, 0x6a, 0xcc, 0x00,
+-	0x45, 0x6a, 0xbe, 0x5b,
+-	0x01, 0x6a, 0x18, 0x01,
+-	0xff, 0x6a, 0x1a, 0x09,
+-	0xff, 0x6a, 0x1c, 0x09,
+-	0x01, 0x6a, 0x26, 0x05,
+-	0x01, 0x65, 0xd8, 0x31,
+-	0x09, 0xee, 0xdc, 0x01,
+-	0x80, 0xee, 0x8e, 0x7b,
+-	0xff, 0x6a, 0xdc, 0x0d,
+-	0xff, 0x65, 0x32, 0x09,
+-	0x0a, 0x93, 0x26, 0x01,
+-	0x00, 0x65, 0x30, 0x44,
+-	0xff, 0x37, 0xc8, 0x08,
+-	0x00, 0x6a, 0x54, 0x5b,
+-	0xff, 0x52, 0xa2, 0x0c,
+-	0x01, 0x0c, 0x9e, 0x7b,
+-	0x04, 0x0c, 0x9e, 0x6b,
+-	0xe0, 0x03, 0x06, 0x08,
+-	0xe0, 0x03, 0x7a, 0x0c,
+-	0xff, 0x8c, 0x10, 0x08,
+-	0xff, 0x8d, 0x12, 0x08,
+-	0xff, 0x8e, 0x14, 0x0c,
+-	0xff, 0x6c, 0xda, 0x08,
+-	0xff, 0x6c, 0xda, 0x08,
+-	0xff, 0x6c, 0xda, 0x08,
+-	0xff, 0x6c, 0xda, 0x08,
+-	0xff, 0x6c, 0xda, 0x08,
+-	0xff, 0x6c, 0xda, 0x08,
+-	0xff, 0x6c, 0xda, 0x0c,
+-	0x3d, 0x64, 0xa4, 0x28,
+-	0x55, 0x64, 0xc8, 0x28,
+-	0x00, 0x6c, 0xda, 0x18,
+-	0xff, 0x52, 0xc8, 0x08,
+-	0x00, 0x6c, 0xda, 0x20,
+-	0xff, 0x6a, 0xc8, 0x08,
+-	0x00, 0x6c, 0xda, 0x20,
+-	0x00, 0x6c, 0xda, 0x24,
+-	0xff, 0x65, 0xc8, 0x08,
+-	0xe0, 0x6a, 0xcc, 0x00,
+-	0x41, 0x6a, 0xba, 0x5b,
+-	0xff, 0x90, 0xe2, 0x09,
+-	0x20, 0x6a, 0xd0, 0x01,
+-	0x04, 0x35, 0xdc, 0x7b,
+-	0x1d, 0x6a, 0xdc, 0x01,
+-	0xdc, 0xee, 0xd8, 0x63,
+-	0x00, 0x65, 0xe8, 0x43,
+-	0x01, 0x6a, 0xdc, 0x01,
+-	0x20, 0xa0, 0xd8, 0x31,
+-	0x09, 0xee, 0xdc, 0x01,
+-	0x80, 0xee, 0xe2, 0x7b,
+-	0x19, 0x6a, 0xdc, 0x01,
+-	0xd8, 0xee, 0xe6, 0x63,
+-	0xff, 0x6a, 0xdc, 0x09,
+-	0x18, 0xee, 0xea, 0x6b,
+-	0xff, 0x6a, 0xd4, 0x0c,
+-	0x88, 0x6a, 0xcc, 0x00,
+-	0x41, 0x6a, 0xba, 0x5b,
+-	0x20, 0x6a, 0x18, 0x01,
+-	0xff, 0x6a, 0x1a, 0x09,
+-	0xff, 0x6a, 0x1c, 0x09,
+-	0xff, 0x35, 0x26, 0x09,
+-	0x04, 0x35, 0x14, 0x6c,
+-	0xa0, 0x6a, 0xca, 0x00,
+-	0x20, 0x65, 0xc8, 0x18,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0xff, 0x6c, 0x32, 0x09,
+-	0x00, 0x65, 0x00, 0x64,
+-	0x0a, 0x93, 0x26, 0x01,
+-	0x00, 0x65, 0x30, 0x5c,
+-	0x04, 0x35, 0x0c, 0x7b,
+-	0xa0, 0x6a, 0x20, 0x5c,
+-	0x00, 0x65, 0x22, 0x5c,
+-	0x00, 0x65, 0x22, 0x5c,
+-	0x00, 0x65, 0x22, 0x44,
+-	0xff, 0x65, 0xcc, 0x08,
+-	0xff, 0x99, 0xda, 0x08,
+-	0xff, 0x99, 0xda, 0x08,
+-	0xff, 0x99, 0xda, 0x08,
+-	0xff, 0x99, 0xda, 0x08,
+-	0xff, 0x99, 0xda, 0x08,
+-	0xff, 0x99, 0xda, 0x08,
+-	0xff, 0x99, 0xda, 0x0c,
+-	0x08, 0x94, 0x30, 0x7c,
+-	0xf7, 0x93, 0x26, 0x09,
+-	0x08, 0x93, 0x34, 0x6c,
+-	0xff, 0x6a, 0xd4, 0x0c,
+-	0xff, 0x40, 0x74, 0x09,
+-	0xff, 0x90, 0x80, 0x08,
+-	0xff, 0x6a, 0x72, 0x05,
+-	0xff, 0x40, 0x4c, 0x64,
+-	0xff, 0x3f, 0x44, 0x64,
+-	0xff, 0x6a, 0xca, 0x04,
+-	0xff, 0x3f, 0x20, 0x09,
+-	0x01, 0x6a, 0x6a, 0x00,
+-	0x00, 0xb9, 0xca, 0x5b,
+-	0xff, 0xba, 0x7e, 0x0c,
+-	0xff, 0x40, 0x20, 0x09,
+-	0xff, 0xba, 0x80, 0x0c,
+-	0xff, 0x3f, 0x74, 0x09,
+-	0xff, 0x90, 0x7e, 0x0c,
+-};
+-
+-static int aic7xxx_patch12_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch12_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_WIDE) != 0);
+-}
+-
+-static int aic7xxx_patch11_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch11_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_ULTRA2) == 0);
+-}
+-
+-static int aic7xxx_patch10_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch10_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_CMD_CHAN) == 0);
+-}
+-
+-static int aic7xxx_patch9_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch9_func(struct aic7xxx_host *p)
+-{
+-	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+-}
+-
+-static int aic7xxx_patch8_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch8_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_ULTRA) != 0);
+-}
+-
+-static int aic7xxx_patch7_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch7_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_ULTRA2) != 0);
+-}
+-
+-static int aic7xxx_patch6_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch6_func(struct aic7xxx_host *p)
+-{
+-	return ((p->flags & AHC_PAGESCBS) == 0);
+-}
+-
+-static int aic7xxx_patch5_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch5_func(struct aic7xxx_host *p)
+-{
+-	return ((p->flags & AHC_PAGESCBS) != 0);
+-}
+-
+-static int aic7xxx_patch4_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch4_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_QUEUE_REGS) != 0);
+-}
+-
+-static int aic7xxx_patch3_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch3_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_TWIN) != 0);
+-}
+-
+-static int aic7xxx_patch2_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch2_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_QUEUE_REGS) == 0);
+-}
+-
+-static int aic7xxx_patch1_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch1_func(struct aic7xxx_host *p)
+-{
+-	return ((p->features & AHC_CMD_CHAN) != 0);
+-}
+-
+-static int aic7xxx_patch0_func(struct aic7xxx_host *p);
+-
+-static int
+-aic7xxx_patch0_func(struct aic7xxx_host *p)
+-{
+-	return (0);
+-}
+-
+-struct sequencer_patch {
+-	int		(*patch_func)(struct aic7xxx_host *);
+-	unsigned int	begin	   :10,
+-			skip_instr :10,
+-			skip_patch :12;
+-} sequencer_patches[] = {
+-	{ aic7xxx_patch1_func, 3, 2, 1 },
+-	{ aic7xxx_patch2_func, 7, 1, 1 },
+-	{ aic7xxx_patch2_func, 8, 1, 1 },
+-	{ aic7xxx_patch3_func, 11, 4, 1 },
+-	{ aic7xxx_patch4_func, 16, 3, 2 },
+-	{ aic7xxx_patch0_func, 19, 4, 1 },
+-	{ aic7xxx_patch5_func, 23, 1, 1 },
+-	{ aic7xxx_patch6_func, 26, 1, 1 },
+-	{ aic7xxx_patch1_func, 29, 1, 2 },
+-	{ aic7xxx_patch0_func, 30, 3, 1 },
+-	{ aic7xxx_patch3_func, 39, 4, 1 },
+-	{ aic7xxx_patch7_func, 43, 3, 2 },
+-	{ aic7xxx_patch0_func, 46, 3, 1 },
+-	{ aic7xxx_patch8_func, 52, 7, 1 },
+-	{ aic7xxx_patch3_func, 60, 3, 1 },
+-	{ aic7xxx_patch7_func, 63, 2, 1 },
+-	{ aic7xxx_patch7_func, 102, 1, 2 },
+-	{ aic7xxx_patch0_func, 103, 2, 1 },
+-	{ aic7xxx_patch7_func, 107, 2, 1 },
+-	{ aic7xxx_patch9_func, 109, 1, 1 },
+-	{ aic7xxx_patch10_func, 110, 2, 1 },
+-	{ aic7xxx_patch7_func, 113, 1, 2 },
+-	{ aic7xxx_patch0_func, 114, 1, 1 },
+-	{ aic7xxx_patch1_func, 118, 1, 1 },
+-	{ aic7xxx_patch1_func, 121, 3, 2 },
+-	{ aic7xxx_patch0_func, 124, 5, 1 },
+-	{ aic7xxx_patch1_func, 132, 2, 3 },
+-	{ aic7xxx_patch7_func, 132, 1, 1 },
+-	{ aic7xxx_patch0_func, 134, 3, 1 },
+-	{ aic7xxx_patch11_func, 138, 1, 2 },
+-	{ aic7xxx_patch0_func, 139, 1, 1 },
+-	{ aic7xxx_patch7_func, 140, 7, 2 },
+-	{ aic7xxx_patch0_func, 147, 1, 1 },
+-	{ aic7xxx_patch1_func, 152, 14, 3 },
+-	{ aic7xxx_patch11_func, 165, 1, 1 },
+-	{ aic7xxx_patch0_func, 166, 9, 1 },
+-	{ aic7xxx_patch7_func, 180, 2, 1 },
+-	{ aic7xxx_patch7_func, 182, 1, 1 },
+-	{ aic7xxx_patch11_func, 183, 6, 3 },
+-	{ aic7xxx_patch1_func, 183, 2, 2 },
+-	{ aic7xxx_patch0_func, 185, 4, 1 },
+-	{ aic7xxx_patch7_func, 190, 1, 1 },
+-	{ aic7xxx_patch7_func, 194, 20, 1 },
+-	{ aic7xxx_patch1_func, 215, 3, 3 },
+-	{ aic7xxx_patch11_func, 217, 1, 1 },
+-	{ aic7xxx_patch0_func, 218, 5, 1 },
+-	{ aic7xxx_patch11_func, 223, 1, 2 },
+-	{ aic7xxx_patch0_func, 224, 9, 1 },
+-	{ aic7xxx_patch12_func, 240, 1, 2 },
+-	{ aic7xxx_patch0_func, 241, 1, 1 },
+-	{ aic7xxx_patch4_func, 302, 1, 2 },
+-	{ aic7xxx_patch0_func, 303, 1, 1 },
+-	{ aic7xxx_patch2_func, 306, 1, 1 },
+-	{ aic7xxx_patch1_func, 316, 3, 2 },
+-	{ aic7xxx_patch0_func, 319, 5, 1 },
+-	{ aic7xxx_patch12_func, 327, 1, 2 },
+-	{ aic7xxx_patch0_func, 328, 1, 1 },
+-	{ aic7xxx_patch5_func, 333, 1, 1 },
+-	{ aic7xxx_patch11_func, 375, 15, 1 },
+-	{ aic7xxx_patch1_func, 427, 7, 2 },
+-	{ aic7xxx_patch0_func, 434, 8, 1 },
+-	{ aic7xxx_patch1_func, 443, 4, 2 },
+-	{ aic7xxx_patch0_func, 447, 6, 1 },
+-	{ aic7xxx_patch1_func, 453, 4, 2 },
+-	{ aic7xxx_patch0_func, 457, 3, 1 },
+-	{ aic7xxx_patch10_func, 467, 10, 1 },
+-	{ aic7xxx_patch1_func, 486, 17, 4 },
+-	{ aic7xxx_patch9_func, 494, 4, 2 },
+-	{ aic7xxx_patch0_func, 498, 2, 1 },
+-	{ aic7xxx_patch0_func, 503, 33, 1 },
+-	{ aic7xxx_patch10_func, 536, 4, 1 },
+-	{ aic7xxx_patch5_func, 540, 2, 1 },
+-	{ aic7xxx_patch5_func, 543, 9, 1 },
+-
+-};
diff -urN linux-2.2.19-pre9/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.2.19-pre9/arch/ppc/config.in	Mon Dec  3 21:00:54 2001
+++ linux/arch/ppc/config.in	Mon Dec  3 21:01:13 2001
@@ -179,8 +179,8 @@
 
 bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID
 if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
-  define_bool CONFIG_INPUT_KEYBDEV $CONFIG_INPUT_ADBHID $CONFIG_VT
-  define_bool CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT_ADBHID
+  define_bool CONFIG_INPUT_KEYBDEV $CONFIG_VT
+  define_bool CONFIG_INPUT_MOUSEDEV y
   define_bool CONFIG_MAC_HID y
   bool '  Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
   bool '  Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
diff -urN linux-2.2.19-pre9/drivers/isdn/divert/divert_procfs.c linux/drivers/isdn/divert/divert_procfs.c
--- linux-2.2.19-pre9/drivers/isdn/divert/divert_procfs.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/divert/divert_procfs.c	Mon Dec  3 21:01:22 2001
@@ -40,7 +40,7 @@
 ulong if_used = 0;		/* number of interface users */
 static struct divert_info *divert_info_head = NULL;	/* head of queue */
 static struct divert_info *divert_info_tail = NULL;	/* pointer to last entry */
-static struct wait_queue *rd_queue = 0;		/* Queue IO */
+static wait_queue_head_t rd_queue;
 
 /*********************************/
 /* put an info buffer into queue */
@@ -305,6 +305,7 @@
 divert_dev_init(void)
 {
 
+	init_waitqueue_head(&rd_queue);
 
 #ifdef CONFIG_PROC_FS
 	isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
diff -urN linux-2.2.19-pre9/drivers/isdn/divert/isdn_divert.c linux/drivers/isdn/divert/isdn_divert.c
--- linux-2.2.19-pre9/drivers/isdn/divert/isdn_divert.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/divert/isdn_divert.c	Mon Dec  3 21:01:22 2001
@@ -1,5 +1,5 @@
 /* 
- * $Id: isdn_divert.c,v 1.6 2000/11/13 22:51:47 kai Exp $
+ * $Id: isdn_divert.c,v 1.6.6.1 2001/02/07 11:31:31 kai Exp $
  *
  * DSS1 main diversion supplementary handling for i4l.
  *
@@ -187,7 +187,7 @@
   restore_flags(flags);
   *procid = cs->ics.parm.dss1_io.ll_id;  
 
-  sprintf(cs->info,"%d 0x%lx %s%s 0 %s %0x %d%s%s\n",
+  sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
 	  (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
           cs->ics.parm.dss1_io.ll_id,
           (mode != 2) ? "" : "0 ",
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/amd7930.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/amd7930.c	Mon Dec  3 21:01:22 2001
@@ -734,8 +734,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init
+setup_amd7930(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/arcofi.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/arcofi.c	Mon Dec  3 21:01:22 2001
@@ -128,5 +128,6 @@
 	cs->dc.isac.arcofitimer.function = (void *) arcofi_timer;
 	cs->dc.isac.arcofitimer.data = (long) cs;
 	init_timer(&cs->dc.isac.arcofitimer);
+	init_waitqueue_head(&cs->dc.isac.arcofi_wait);
 	test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
 }
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/asuscom.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/asuscom.c	Mon Dec  3 21:01:22 2001
@@ -11,6 +11,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -306,8 +307,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init
+setup_asuscom(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/avm_a1.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/avm_a1.c	Mon Dec  3 21:01:22 2001
@@ -8,6 +8,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -171,8 +172,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_avm_a1(struct IsdnCard *card))
+int __init
+setup_avm_a1(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/avm_a1p.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/avm_a1p.c	Mon Dec  3 21:01:22 2001
@@ -10,6 +10,7 @@
  *  This file is (c) under GNU PUBLIC LICENSE
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -244,8 +245,8 @@
 	return 0;
 }
 
-__initfunc(int
-setup_avm_a1_pcmcia(struct IsdnCard *card))
+int 
+setup_avm_a1_pcmcia(struct IsdnCard *card)
 {
 	u_char model, vers;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/avm_pci.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/avm_pci.c	Mon Dec  3 21:01:22 2001
@@ -10,6 +10,7 @@
  */
 #define __NO_VERSION__
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "isdnl1.h"
@@ -642,8 +643,8 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_hdlc_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_hdlc_ints(struct IsdnCardState *cs)
 {
 	u_int val;
 
@@ -672,8 +673,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-inithdlc(struct IsdnCardState *cs))
+void __init
+inithdlc(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_hdlc;
 	cs->bcs[1].BC_SetStack = setstack_hdlc;
@@ -757,10 +758,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_avm __initdata = NULL;
+static struct pci_dev *dev_avm __initdata = NULL;
 
-__initfunc(int
-setup_avm_pcipnp(struct IsdnCard *card))
+int __init
+setup_avm_pcipnp(struct IsdnCard *card)
 {
 	u_int val, ver;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/bkm_a4t.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/bkm_a4t.c	Mon Dec  3 21:01:22 2001
@@ -13,6 +13,7 @@
 #define __NO_VERSION__
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -265,8 +266,8 @@
 
 static struct pci_dev *dev_a4t __initdata = NULL;
 
-__initfunc(int
-	   setup_bkm_a4t(struct IsdnCard *card))
+int __init
+setup_bkm_a4t(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/bkm_a8.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/bkm_a8.c	Mon Dec  3 21:01:22 2001
@@ -12,6 +12,7 @@
 #define __NO_VERSION__
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -268,8 +269,8 @@
 	return (0);
 }
 
-__initfunc(int
-sct_alloc_io(u_int adr, u_int len))
+int __init
+sct_alloc_io(u_int adr, u_int len)
 {
 	if (check_region(adr, len)) {
 		printk(KERN_WARNING
@@ -291,8 +292,8 @@
 
 #endif /* CONFIG_PCI */
 
-__initfunc(int
-setup_sct_quadro(struct IsdnCard *card))
+int __init
+setup_sct_quadro(struct IsdnCard *card)
 {
 #if CONFIG_PCI
 	struct IsdnCardState *cs = card->cs;
@@ -463,6 +464,5 @@
 	return (1);
 #else
 	printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-	return (0);
 #endif /* CONFIG_PCI */
 }
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/callc.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/callc.c	Mon Dec  3 21:01:22 2001
@@ -11,8 +11,8 @@
  *              Fritz Elfert
  *
  */
-
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "../avmb1/capicmd.h"  /* this should be moved in a common place */
 
@@ -780,7 +780,7 @@
 }
 
 /* *INDENT-OFF* */
-static struct FsmNode fnlist[] HISAX_INITDATA =
+static struct FsmNode fnlist[] __initdata =
 {
         {ST_NULL,               EV_DIAL,                lli_prep_dialout},
         {ST_NULL,               EV_RESUME,              lli_resume},
@@ -850,8 +850,8 @@
 
 #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
 
-HISAX_INITFUNC(void
-CallcNew(void))
+void __init
+CallcNew(void)
 {
 	callcfsm.state_count = STATE_COUNT;
 	callcfsm.event_count = EVENT_COUNT;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/config.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/config.c	Mon Dec  3 21:01:22 2001
@@ -10,6 +10,7 @@
 #include <linux/stddef.h>
 #include <linux/timer.h>
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include <linux/module.h>
 #include <linux/kernel_stat.h>
@@ -383,8 +384,8 @@
 extern char *lli_revision;
 extern char *tei_revision;
 
-HISAX_INITFUNC(char *
-HiSax_getrev(const char *revision))
+char *
+HiSax_getrev(const char *revision)
 {
 	char *rev;
 	char *p;
@@ -398,8 +399,8 @@
 	return rev;
 }
 
-HISAX_INITFUNC(void
-HiSaxVersion(void))
+void __init
+HiSaxVersion(void)
 {
 	char tmp[64];
 
@@ -849,7 +850,8 @@
 	ll_unload(csta);
 }
 
-HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
+static int 
+init_card(struct IsdnCardState *cs)
 {
 	int irq_cnt, cnt = 3;
 	long flags;
@@ -896,8 +898,8 @@
 	return(3);
 }
 
-HISAX_INITFUNC(static int
-checkcard(int cardnr, char *id, int *busy_flag))
+static int 
+checkcard(int cardnr, char *id, int *busy_flag)
 {
 	long flags;
 	int ret = 0;
@@ -1170,7 +1172,6 @@
 	cs->tx_skb = NULL;
 	cs->tx_cnt = 0;
 	cs->event = 0;
-	cs->tqueue.next = 0;
 	cs->tqueue.sync = 0;
 	cs->tqueue.data = cs;
 
@@ -1194,8 +1195,8 @@
 	return (1);
 }
 
-HISAX_INITFUNC(void
-HiSax_shiftcards(int idx))
+void 
+HiSax_shiftcards(int idx)
 {
 	int i;
 
@@ -1203,8 +1204,8 @@
 		memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-HISAX_INITFUNC(int
-HiSax_inithardware(int *busy_flag))
+int 
+HiSax_inithardware(int *busy_flag)
 {
 	int foundcards = 0;
 	int i = 0;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/diva.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/diva.c	Mon Dec  3 21:01:22 2001
@@ -13,6 +13,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
@@ -819,12 +820,12 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_diva __initdata = NULL;
-static 	struct pci_dev *dev_diva_u __initdata = NULL;
-static 	struct pci_dev *dev_diva201 __initdata = NULL;
+static struct pci_dev *dev_diva __initdata = NULL;
+static struct pci_dev *dev_diva_u __initdata = NULL;
+static struct pci_dev *dev_diva201 __initdata = NULL;
 
-__initfunc(int
-setup_diva(struct IsdnCard *card))
+int __init
+setup_diva(struct IsdnCard *card)
 {
 	int bytecnt;
 	u_char val;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/elsa.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/elsa.c	Mon Dec  3 21:01:22 2001
@@ -16,6 +16,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "arcofi.h"
@@ -859,7 +860,7 @@
 static 	struct pci_dev *dev_qs1000  = NULL;
 static 	struct pci_dev *dev_qs3000  = NULL;
 
-int
+int 
 setup_elsa(struct IsdnCard *card)
 {
 	long flags;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/fsm.c linux/drivers/isdn/hisax/fsm.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/fsm.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/fsm.c	Mon Dec  3 21:01:22 2001
@@ -10,13 +10,13 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 
 #define FSM_TIMER_DEBUG 0
 
-HISAX_INITFUNC(void
-FsmNew(struct Fsm *fsm,
-       struct FsmNode *fnlist, int fncount))
+void __init
+FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
 {
 	int i;
 
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/gazel.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/gazel.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  *
  */
 #include <linux/config.h>
+#include <linux/init.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isac.h"
@@ -631,8 +632,8 @@
 	return (0);
 }
 
-__initfunc(int
-	   setup_gazel(struct IsdnCard *card))
+int __init
+setup_gazel(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/hfc_2bds0.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Mon Dec  3 21:01:22 2001
@@ -8,6 +8,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
@@ -1104,8 +1105,8 @@
 {
 }
 
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int __init
+*init_send_hfcd(int cnt)
 {
 	int i, *send;
 
@@ -1119,8 +1120,8 @@
 	return(send);
 }
 
-__initfunc(void
-init2bds0(struct IsdnCardState *cs))
+void __init
+init2bds0(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcd;
 	cs->dbusytimer.function = (void *) hfc_dbusy_timer;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/hfc_2bs0.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hfc_2bs0.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_2bs0.h"
 #include "isac.h"
@@ -570,8 +571,8 @@
 	return (0);
 }
 
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init
+init_send(struct BCState *bcs)
 {
 	int i;
 
@@ -584,8 +585,8 @@
 		bcs->hw.hfc.send[i] = 0x1fff;
 }
 
-__initfunc(void
-inithfc(struct IsdnCardState *cs))
+void __init
+inithfc(struct IsdnCardState *cs)
 {
 	init_send(&cs->bcs[0]);
 	init_send(&cs->bcs[1]);
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/hfc_pci.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hfc_pci.c	Mon Dec  3 21:01:22 2001
@@ -24,6 +24,7 @@
  *
  */
 
+#include <linux/init.h>
 #include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
@@ -1571,8 +1572,8 @@
 /********************************/
 /* called for card init message */
 /********************************/
-__initfunc(void
-	   inithfcpci(struct IsdnCardState *cs))
+void __init
+inithfcpci(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcpci;
 	cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
@@ -1632,8 +1633,7 @@
 
 #endif				/* CONFIG_PCI */
 
-__initfunc(int
-	   setup_hfcpci(struct IsdnCard *card))
+int __init setup_hfcpci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	unsigned short cmd;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hfc_sx.c linux/drivers/isdn/hisax/hfc_sx.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/hfc_sx.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hfc_sx.c	Mon Dec  3 21:01:22 2001
@@ -24,6 +24,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_sx.h"
 #include "isdnl1.h"
@@ -1415,8 +1416,8 @@
 /********************************/
 /* called for card init message */
 /********************************/
-__initfunc(void
-	   inithfcsx(struct IsdnCardState *cs))
+void 
+inithfcsx(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcsx;
 	cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
@@ -1472,8 +1473,8 @@
 
 
 
-__initfunc(int
-	   setup_hfcsx(struct IsdnCard *card))
+int 
+setup_hfcsx(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/hfcscard.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hfcscard.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
@@ -136,8 +137,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_hfcs(struct IsdnCard *card))
+int __init
+setup_hfcs(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- linux-2.2.19-pre9/drivers/isdn/hisax/hisax.h	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hisax.h	Mon Dec  3 21:01:22 2001
@@ -787,8 +787,8 @@
 	unsigned char *sfifo_e;
 	int sfifo_cnt;
 	unsigned int stat;
-	struct wait_queue *rwaitq;
-	struct wait_queue *swaitq;
+	wait_queue_head_t rwaitq;
+	wait_queue_head_t swaitq;
 };
 #endif
 
@@ -808,7 +808,7 @@
 	int mon_rxp;
 	struct arcofi_msg *arcofi_list;
 	struct timer_list arcofitimer;
-	struct wait_queue *arcofi_wait;
+	wait_queue_head_t arcofi_wait;
 	u_char arcofi_bc;
 	u_char arcofi_state;
 	u_char mocr;
@@ -840,7 +840,7 @@
 	int mon_rxp;
 	struct arcofi_msg *arcofi_list;
 	struct timer_list arcofitimer;
-	struct wait_queue *arcofi_wait;
+	wait_queue_head_t arcofi_wait;
 	u_char arcofi_bc;
 	u_char arcofi_state;
 	u_char mocr;
@@ -995,17 +995,6 @@
 #undef ISDN_CHIP_ISAC
 #endif
 
-#ifndef __initfunc
-#define __initfunc(__arginit) __arginit
-#endif
-
-#ifndef __initdata
-#define __initdata
-#endif
-
-#define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
-#define HISAX_INITDATA __initdata
-
 #ifdef	CONFIG_HISAX_16_0
 #define  CARD_TELES0 1
 #ifndef ISDN_CHIP_ISAC
@@ -1065,10 +1054,6 @@
 #ifndef ISDN_CHIP_ISAC
 #define ISDN_CHIP_ISAC 1
 #endif
-#undef HISAX_INITFUNC
-#define HISAX_INITFUNC(__arginit) __arginit
-#undef HISAX_INITDATA
-#define HISAX_INITDATA
 #else
 #define  CARD_ELSA  0
 #endif
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/hscx.c linux/drivers/isdn/hisax/hscx.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/hscx.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/hscx.c	Mon Dec  3 21:01:22 2001
@@ -9,18 +9,19 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hscx.h"
 #include "isac.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 
-static char *HSCXVer[] HISAX_INITDATA =
+static char *HSCXVer[] __initdata =
 {"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
  "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
 
-HISAX_INITFUNC(int
-HscxVersion(struct IsdnCardState *cs, char *s))
+int __init
+HscxVersion(struct IsdnCardState *cs, char *s)
 {
 	int verA, verB;
 
@@ -218,8 +219,8 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_hscx_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_hscx_ints(struct IsdnCardState *cs)
 {
 	int val, eval;
 
@@ -244,8 +245,8 @@
 	cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
 }
 
-HISAX_INITFUNC(void
-inithscx(struct IsdnCardState *cs))
+void __init
+inithscx(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_hscx;
 	cs->bcs[1].BC_SetStack = setstack_hscx;
@@ -261,8 +262,8 @@
 	modehscx(cs->bcs + 1, 0, 0);
 }
 
-HISAX_INITFUNC(void
-inithscxisac(struct IsdnCardState *cs, int part))
+void __init
+inithscxisac(struct IsdnCardState *cs, int part)
 {
 	if (part & 1) {
 		clear_pending_isac_ints(cs);
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/icc.c linux/drivers/isdn/hisax/icc.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/icc.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/icc.c	Mon Dec  3 21:01:22 2001
@@ -15,6 +15,7 @@
 //-----------------------------------------------------------------------------
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "icc.h"
 // #include "arcofi.h"
@@ -24,7 +25,7 @@
 #define DBUSY_TIMER_VALUE 80
 #define ARCOFI_USE 0
 
-static char *ICCVer[] HISAX_INITDATA =
+static char *ICCVer[] __initdata =
 {"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
 
 void
@@ -622,8 +623,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-initicc(struct IsdnCardState *cs))
+void __init
+initicc(struct IsdnCardState *cs)
 {
 	cs->tqueue.routine = (void *) (void *) icc_bh;
 	cs->setstack_d = setstack_icc;
@@ -659,8 +660,8 @@
 	ph_command(cs, ICC_CMD_DI);
 }
 
-HISAX_INITFUNC(void
-clear_pending_icc_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_icc_ints(struct IsdnCardState *cs)
 {
 	int val, eval;
 
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/isac.c linux/drivers/isdn/hisax/isac.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/isac.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/isac.c	Mon Dec  3 21:01:22 2001
@@ -15,11 +15,12 @@
 #include "arcofi.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #define DBUSY_TIMER_VALUE 80
 #define ARCOFI_USE 1
 
-static char *ISACVer[] HISAX_INITDATA =
+static char *ISACVer[]  =
 {"2086/2186 V1.1", "2085 B1", "2085 B2",
  "2085 V2.3"};
 
@@ -620,8 +621,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-initisac(struct IsdnCardState *cs))
+void 
+initisac(struct IsdnCardState *cs)
 {
 	cs->tqueue.routine = (void *) (void *) isac_bh;
 	cs->setstack_d = setstack_isac;
@@ -656,8 +657,8 @@
 	cs->writeisac(cs, ISAC_MASK, 0x0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_isac_ints(struct IsdnCardState *cs))
+void 
+clear_pending_isac_ints(struct IsdnCardState *cs)
 {
 	int val, eval;
 
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/isar.c linux/drivers/isdn/hisax/isar.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/isar.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/isar.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isar.h"
 #include "isdnl1.h"
@@ -1782,8 +1783,8 @@
 	return(0);
 }
 
-HISAX_INITFUNC(void 
-initisar(struct IsdnCardState *cs))
+void 
+initisar(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_isar;
 	cs->bcs[1].BC_SetStack = setstack_isar;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/isdnl1.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/isdnl1.c	Mon Dec  3 21:01:22 2001
@@ -18,6 +18,7 @@
 const char *l1_revision = "$Revision: 2.41.6.1 $";
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl1.h"
 
@@ -342,7 +343,6 @@
 
 	bcs->cs = cs;
 	bcs->channel = bc;
-	bcs->tqueue.next = 0;
 	bcs->tqueue.sync = 0;
 	bcs->tqueue.routine = (void *) (void *) BChannel_bh;
 	bcs->tqueue.data = bcs;
@@ -579,7 +579,7 @@
 	}
 }
 
-static struct FsmNode L1SFnList[] HISAX_INITDATA =
+static struct FsmNode L1SFnList[] __initdata =
 {
 	{ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
 	{ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
@@ -664,7 +664,7 @@
 	st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL);
 }
 
-static struct FsmNode L1UFnList[] HISAX_INITDATA =
+static struct FsmNode L1UFnList[] __initdata =
 {
 	{ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
 	{ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
@@ -726,7 +726,7 @@
 	st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
 }
 
-static struct FsmNode L1BFnList[] HISAX_INITDATA =
+static struct FsmNode L1BFnList[] __initdata =
 {
 	{ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
 	{ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
@@ -736,7 +736,8 @@
 
 #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
 
-HISAX_INITFUNC(void Isdnl1New(void))
+void __init 
+Isdnl1New(void)
 {
 #ifdef HISAX_UINTERFACE
 	l1fsm_u.state_count = L1U_STATE_COUNT;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/isdnl2.c linux/drivers/isdn/hisax/isdnl2.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/isdnl2.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/isdnl2.c	Mon Dec  3 21:01:22 2001
@@ -12,6 +12,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl2.h"
 
@@ -1533,7 +1534,7 @@
 	test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
 }
 
-static struct FsmNode L2FnList[] HISAX_INITDATA =
+static struct FsmNode L2FnList[] __initdata =
 {
 	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
 	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
@@ -1830,8 +1831,8 @@
 {
 }
 
-HISAX_INITFUNC(void
-Isdnl2New(void))
+void __init
+Isdnl2New(void)
 {
 	l2fsm.state_count = L2_STATE_COUNT;
 	l2fsm.event_count = L2_EVENT_COUNT;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/isdnl3.c linux/drivers/isdn/hisax/isdnl3.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/isdnl3.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/isdnl3.c	Mon Dec  3 21:01:22 2001
@@ -13,11 +13,12 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.17 $";
+const char *l3_revision = "$Revision: 2.17.6.1 $";
 
 static struct Fsm l3fsm;
 
@@ -520,7 +521,7 @@
 
 
 /* *INDENT-OFF* */
-static struct FsmNode L3FnList[] HISAX_INITDATA =
+static struct FsmNode L3FnList[] __initdata =
 {
 	{ST_L3_LC_REL,		EV_ESTABLISH_REQ,	lc_activate},
 	{ST_L3_LC_REL,		EV_ESTABLISH_IND,	lc_connect},
@@ -575,8 +576,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-Isdnl3New(void))
+void __init
+Isdnl3New(void)
 {
 	l3fsm.state_count = L3_STATE_COUNT;
 	l3fsm.event_count = L3_EVENT_COUNT;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/isurf.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/isurf.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "isar.h"
@@ -188,8 +189,8 @@
 	return(isar_auxcmd(cs, ic));
 }
 
-__initfunc(int
-setup_isurf(struct IsdnCard *card))
+int __init
+setup_isurf(struct IsdnCard *card)
 {
 	int ver;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/ix1_micro.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/ix1_micro.c	Mon Dec  3 21:01:22 2001
@@ -43,6 +43,7 @@
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -243,8 +244,8 @@
 }
 
 
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init
+setup_ix1micro(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/jade.c linux/drivers/isdn/hisax/jade.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/jade.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/jade.c	Mon Dec  3 21:01:22 2001
@@ -10,6 +10,7 @@
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hscx.h"
 #include "jade.h"
@@ -17,8 +18,8 @@
 #include <linux/interrupt.h>
 
 
-HISAX_INITFUNC(int
-JadeVersion(struct IsdnCardState *cs, char *s))
+int __init
+JadeVersion(struct IsdnCardState *cs, char *s)
 {
     int ver,i;
     int to = 50;
@@ -262,8 +263,8 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_jade_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_jade_ints(struct IsdnCardState *cs)
 {
 	int val;
 	char tmp[64];
@@ -288,8 +289,8 @@
 	cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
 }
 
-HISAX_INITFUNC(void
-initjade(struct IsdnCardState *cs))
+void __init
+initjade(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_jade;
 	cs->bcs[1].BC_SetStack = setstack_jade;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/mic.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/mic.c	Mon Dec  3 21:01:22 2001
@@ -11,6 +11,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -198,8 +199,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init
+setup_mic(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/netjet.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/netjet.c	Mon Dec  3 21:01:22 2001
@@ -11,7 +11,7 @@
  */
 
 #define __NO_VERSION__
-#include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -801,8 +801,8 @@
 }
 
  
-__initfunc(void
-inittiger(struct IsdnCardState *cs))
+void __init
+inittiger(struct IsdnCardState *cs)
 {
 	if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
 		GFP_KERNEL | GFP_DMA))) {
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/netjet.h linux/drivers/isdn/hisax/netjet.h
--- linux-2.2.19-pre9/drivers/isdn/hisax/netjet.h	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/netjet.h	Mon Dec  3 21:01:22 2001
@@ -65,6 +65,6 @@
 
 void netjet_fill_dma(struct BCState *bcs);
 void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
-__initfunc(void inittiger(struct IsdnCardState *cs));
+void inittiger(struct IsdnCardState *cs);
 void release_io_netjet(struct IsdnCardState *cs);
 
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/niccy.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/niccy.c	Mon Dec  3 21:01:22 2001
@@ -14,6 +14,7 @@
 
 #define __NO_VERSION__
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -234,10 +235,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *niccy_dev __initdata = NULL;
+static struct pci_dev *niccy_dev __initdata = NULL;
 
-__initfunc(int
-setup_niccy(struct IsdnCard *card))
+int __init
+setup_niccy(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/nj_s.c linux/drivers/isdn/hisax/nj_s.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/nj_s.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/nj_s.c	Mon Dec  3 21:01:22 2001
@@ -4,6 +4,7 @@
 //
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
@@ -129,10 +130,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __initdata = NULL;
 
-__initfunc(int
-setup_netjet_s(struct IsdnCard *card))
+int __init
+setup_netjet_s(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/nj_u.c linux/drivers/isdn/hisax/nj_u.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/nj_u.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/nj_u.c	Mon Dec  3 21:01:22 2001
@@ -5,6 +5,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "icc.h"
@@ -131,10 +132,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __initdata = NULL;
 
-__initfunc(int
-setup_netjet_u(struct IsdnCard *card))
+int __init
+setup_netjet_u(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/s0box.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/s0box.c	Mon Dec  3 21:01:22 2001
@@ -8,6 +8,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -213,8 +214,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/saphir.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/saphir.c	Mon Dec  3 21:01:22 2001
@@ -12,6 +12,7 @@
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -253,8 +254,8 @@
 }
 
 
-__initfunc(int
-setup_saphir(struct IsdnCard *card))
+int __init
+setup_saphir(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/sedlbauer.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/sedlbauer.c	Mon Dec  3 21:01:22 2001
@@ -40,6 +40,7 @@
 */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
@@ -528,10 +529,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_sedl __initdata = NULL;
+static 	struct pci_dev *dev_sedl  = NULL;
 
-__initfunc(int
-setup_sedlbauer(struct IsdnCard *card))
+int 
+setup_sedlbauer(struct IsdnCard *card)
 {
 	int bytecnt, ver, val;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/sportster.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/sportster.c	Mon Dec  3 21:01:22 2001
@@ -10,6 +10,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -181,8 +182,8 @@
 	return(0);
 }
 
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+static int __init
+get_io_range(struct IsdnCardState *cs)
 {
 	int i, j, adr;
 	
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/tei.c linux/drivers/isdn/hisax/tei.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/tei.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/tei.c	Mon Dec  3 21:01:22 2001
@@ -12,6 +12,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl2.h"
 #include <linux/random.h>
@@ -428,7 +429,7 @@
 	}
 }
 
-static struct FsmNode TeiFnList[] HISAX_INITDATA =
+static struct FsmNode TeiFnList[] __initdata =
 {
 	{ST_TEI_NOP, EV_IDREQ, tei_id_request},
 	{ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
@@ -445,8 +446,8 @@
 
 #define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
 
-HISAX_INITFUNC(void
-TeiNew(void))
+void __init
+TeiNew(void)
 {
 	teifsm.state_count = TEI_STATE_COUNT;
 	teifsm.event_count = TEI_EVENT_COUNT;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/teleint.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/teleint.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hfc_2bs0.h"
@@ -260,8 +261,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init
+setup_TeleInt(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/teles0.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/teles0.c	Mon Dec  3 21:01:22 2001
@@ -13,6 +13,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl1.h"
 #include "isac.h"
@@ -258,8 +259,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init
+setup_teles0(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/teles3.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/teles3.c	Mon Dec  3 21:01:22 2001
@@ -14,6 +14,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -253,8 +254,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int 
+setup_teles3(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/telespci.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/telespci.c	Mon Dec  3 21:01:22 2001
@@ -9,6 +9,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
@@ -276,8 +277,8 @@
 
 static 	struct pci_dev *dev_tel __initdata = NULL;
 
-__initfunc(int
-setup_telespci(struct IsdnCard *card))
+int __init
+setup_telespci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -urN linux-2.2.19-pre9/drivers/isdn/hisax/w6692.c linux/drivers/isdn/hisax/w6692.c
--- linux-2.2.19-pre9/drivers/isdn/hisax/w6692.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/hisax/w6692.c	Mon Dec  3 21:01:22 2001
@@ -10,6 +10,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "w6692.h"
@@ -857,7 +858,7 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void initW6692(struct IsdnCardState *cs, int part))
+void __init initW6692(struct IsdnCardState *cs, int part)
 {
 	if (part & 1) {
 		cs->tqueue.routine = (void *) (void *) W6692_bh;
diff -urN linux-2.2.19-pre9/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- linux-2.2.19-pre9/drivers/isdn/isdn_common.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/isdn_common.c	Mon Dec  3 21:01:22 2001
@@ -64,7 +64,7 @@
 extern char *isdn_v110_revision;
 
 #ifdef CONFIG_ISDN_DIVERSION
-isdn_divert_if *divert_if; /* interface to diversion module */
+static isdn_divert_if *divert_if; /* = NULL */
 #endif CONFIG_ISDN_DIVERSION
 
 
@@ -73,11 +73,10 @@
 static int isdn_wildmat(char *s, char *p);
 
 void
-isdn_MOD_INC_USE_COUNT(void)
+isdn_lock_drivers(void)
 {
 	int i;
 
-	MOD_INC_USE_COUNT;
 	for (i = 0; i < dev->drivers; i++) {
 		isdn_ctrl cmd;
 
@@ -90,11 +89,17 @@
 }
 
 void
-isdn_MOD_DEC_USE_COUNT(void)
+isdn_MOD_INC_USE_COUNT(void)
+{
+	MOD_INC_USE_COUNT;
+	isdn_lock_drivers();
+}
+
+void
+isdn_unlock_drivers(void)
 {
 	int i;
 
-	MOD_DEC_USE_COUNT;
 	for (i = 0; i < dev->drivers; i++)
 		if (dev->drv[i]->locks > 0) {
 			isdn_ctrl cmd;
@@ -107,6 +112,13 @@
 		}
 }
 
+void
+isdn_MOD_DEC_USE_COUNT(void)
+{
+	MOD_DEC_USE_COUNT;
+	isdn_unlock_drivers();
+}
+
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
 void
 isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
@@ -791,7 +803,7 @@
  * of the mapping (di,ch)<->minor, happen during the sleep? --he 
  */
 int
-isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep)
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
 {
 	int left;
 	int count;
@@ -1488,7 +1500,7 @@
 					int i;
 
 					if ((ret = verify_area(VERIFY_READ, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN)
+					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
 						   * ISDN_MAX_CHANNELS)))
 						return ret;
 
@@ -1497,6 +1509,9 @@
 						     ISDN_MODEM_NUMREG))
 							return -EFAULT;
 						p += ISDN_MODEM_NUMREG;
+						if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
+							return -EFAULT;
+						p += ISDN_LMSNLEN;
 						if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
 							return -EFAULT;
 						p += ISDN_MSNLEN;
@@ -1632,8 +1647,6 @@
 
 /*
  * Open the device code.
- * MOD_INC_USE_COUNT make sure that the driver memory is not freed
- * while the device is in use.
  */
 static int
 isdn_open(struct inode *ino, struct file *filep)
@@ -1641,52 +1654,62 @@
 	uint minor = MINOR(ino->i_rdev);
 	int drvidx;
 	int chidx;
+	int retval = -ENODEV;
+
+	MOD_INC_USE_COUNT;
 
 	if (minor == ISDN_MINOR_STATUS) {
 		infostruct *p;
 
 		if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) {
-			MOD_INC_USE_COUNT;
 			p->next = (char *) dev->infochain;
 			p->private = (char *) &(filep->private_data);
 			dev->infochain = p;
 			/* At opening we allow a single update */
 			filep->private_data = (char *) 1;
-			return 0;
-		} else
-			return -ENOMEM;
+			retval = 0;
+			goto out;
+		} else {
+			retval = -ENOMEM;
+			goto out;
+		}
 	}
 	if (!dev->channels)
-		return -ENODEV;
+		goto out;
 	if (minor < ISDN_MINOR_CTRL) {
 		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0)
-			return -ENODEV;
+			goto out;
 		chidx = isdn_minor2chan(minor);
 		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
+			goto out;
 		if (!(dev->drv[drvidx]->online & (1 << chidx)))
-			return -ENODEV;
-		isdn_MOD_INC_USE_COUNT();
-		return 0;
+			goto out;
+		isdn_lock_drivers();
+		retval = 0;
+		goto out;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 		if (drvidx < 0)
-			return -ENODEV;
-		isdn_MOD_INC_USE_COUNT();
-		return 0;
+			goto out;
+		isdn_lock_drivers();
+		retval = 0;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX) {
-		int ret;
-		if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
-			isdn_MOD_INC_USE_COUNT();
-		return ret;
+		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
+		if (retval == 0)
+			isdn_lock_drivers();
+		goto out;
 	}
 #endif
-	return -ENODEV;
+ out:
+	if (retval)
+		MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 static int
@@ -1698,7 +1721,6 @@
 		infostruct *p = dev->infochain;
 		infostruct *q = NULL;
 
-		MOD_DEC_USE_COUNT;
 		while (p) {
 			if (p->private == (char *) &(filep->private_data)) {
 				if (q)
@@ -1706,26 +1728,29 @@
 				else
 					dev->infochain = (infostruct *) (p->next);
 				kfree(p);
-				return 0;
+				goto out;
 			}
 			q = p;
 			p = (infostruct *) (p->next);
 		}
 		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-		return 0;
+		goto out;
 	}
-	isdn_MOD_DEC_USE_COUNT();
+	isdn_unlock_drivers();
 	if (minor < ISDN_MINOR_CTRL)
-		return 0;
+		goto out;
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		if (dev->profd == current)
 			dev->profd = NULL;
-		return 0;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
 		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
 #endif
+
+ out:
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1983,6 +2008,7 @@
 	int j, k, m;
 	ulong flags;
 
+ 	init_waitqueue_head(&d->st_waitq);
 	if (d->flags & DRV_FLAG_RUNNING)
 		return -1;
        	if (n < 1) return 0;
@@ -2032,8 +2058,9 @@
 
 	if ((adding) && (d->rcv_waitq))
 		kfree(d->rcv_waitq);
-	if (!(d->rcv_waitq = (struct wait_queue **)
-	      kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
+	d->rcv_waitq = (wait_queue_head_t *)
+		kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
+	if (!d->rcv_waitq) {
 		printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
 		if (!adding) {
 			kfree(d->rpqueue);
@@ -2042,22 +2069,11 @@
 		}
 		return -1;
 	}
-	memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m);
-
-	if ((adding) && (d->snd_waitq))
-		kfree(d->snd_waitq);
-	if (!(d->snd_waitq = (struct wait_queue **)
-	      kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
-		printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
-		if (!adding) {
-			kfree(d->rcv_waitq);
-			kfree(d->rpqueue);
-			kfree(d->rcvcount);
-			kfree(d->rcverr);
-		}
-		return -1;
+	d->snd_waitq = d->rcv_waitq + m;
+	for (j = 0; j < m; j++) {
+		init_waitqueue_head(&d->rcv_waitq[j]);
+		init_waitqueue_head(&d->snd_waitq[j]);
 	}
-	memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m);
 
 	dev->channels += n;
 	save_flags(flags);
@@ -2093,7 +2109,6 @@
 }
 
 #ifdef CONFIG_ISDN_DIVERSION
-extern isdn_divert_if *divert_if;
 
 static char *map_drvname(int di)
 {
@@ -2253,12 +2268,15 @@
 	memset((char *) dev, 0, sizeof(isdn_dev));
 	init_timer(&dev->timer);
 	dev->timer.function = isdn_timer_funct;
-	dev->sem = MUTEX;
+	init_MUTEX(&dev->sem);
+	init_waitqueue_head(&dev->info_waitq);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		dev->drvmap[i] = -1;
 		dev->chanmap[i] = -1;
 		dev->m_idx[i] = -1;
 		strcpy(dev->num[i], "???");
+		init_waitqueue_head(&dev->mdm.info[i].open_wait);
+		init_waitqueue_head(&dev->mdm.info[i].close_wait);
 	}
 	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
diff -urN linux-2.2.19-pre9/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- linux-2.2.19-pre9/drivers/isdn/isdn_common.h	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/isdn_common.h	Mon Dec  3 21:01:22 2001
@@ -46,7 +46,7 @@
 extern void isdn_timer_ctrl(int tf, int onoff);
 extern void isdn_unexclusive_channel(int di, int ch);
 extern int isdn_getnum(char **);
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
+extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
 extern int isdn_get_free_channel(int, int, int, int, int, char *);
 extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
 extern int register_isdn(isdn_if * i);
diff -urN linux-2.2.19-pre9/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- linux-2.2.19-pre9/drivers/isdn/isdn_net.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/isdn_net.c	Mon Dec  3 21:01:22 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.140.6.1 2000/12/10 22:01:04 kai Exp $
+/* $Id: isdn_net.c,v 1.140.6.3 2001/02/07 11:31:30 kai Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -154,6 +154,7 @@
 	if (!(isdn_net_device_busy(lp))) {
 		if (!skb_queue_empty(&lp->super_tx_queue)) {
 			queue_task(&lp->tqueue, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
 		} else {
 			isdn_net_device_wake_queue(lp);
 		}
@@ -181,7 +182,7 @@
 int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 
-char *isdn_net_revision = "$Revision: 1.140.6.1 $";
+char *isdn_net_revision = "$Revision: 1.140.6.3 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -986,6 +987,7 @@
 		// so we just queue the packet
 		skb_queue_tail(&lp->super_tx_queue, skb); 
 		queue_task(&lp->tqueue, &tq_immediate);
+ 		mark_bh(IMMEDIATE_BH);
 		return;
 	}
 
@@ -1340,7 +1342,7 @@
 /*
  * Get statistics
  */
-static struct enet_statistics *
+static struct net_device_stats *
 isdn_net_get_stats(struct device *dev)
 {
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
@@ -2312,6 +2314,7 @@
 	memset(netdev, 0, sizeof(isdn_net_dev));
 	if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
 		printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+		kfree(netdev);
 		return NULL;
 	}
 	memset(netdev->local, 0, sizeof(isdn_net_local));
@@ -2353,7 +2356,7 @@
 	netdev->local->netdev = netdev;
 	netdev->local->next = netdev->local;
 
-	memset(&netdev->local->tqueue, 0, sizeof(struct tq_struct));
+	netdev->local->tqueue.sync = 0;
 	netdev->local->tqueue.routine = isdn_net_softint;
 	netdev->local->tqueue.data = netdev->local;
 	spin_lock_init(&netdev->local->xmit_lock);
diff -urN linux-2.2.19-pre9/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- linux-2.2.19-pre9/drivers/isdn/isdn_ppp.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/isdn_ppp.c	Mon Dec  3 21:01:22 2001
@@ -233,8 +233,7 @@
 
 	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
 
-	if (ippp_table[lp->ppp_slot]->wq)
-		wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
 /*
@@ -251,7 +250,7 @@
 		return 0;
 	is = ippp_table[slot];
 
-	if (is->state && is->wq)
+	if (is->state)
 		wake_up_interruptible(&is->wq);
 
 	is->state = IPPP_CLOSEWAIT;
@@ -312,7 +311,7 @@
 	is->mru = 1524;         /* MRU, default 1524 */
 	is->maxcid = 16;        /* VJ: maxcid */
 	is->tk = current;
-	is->wq = NULL;          /* read() wait queue */
+	init_waitqueue_head(&is->wq);
 	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
 	is->last = is->rq;
 	is->minor = min;
@@ -676,8 +675,7 @@
 	is->last = bl->next;
 	restore_flags(flags);
 
-	if (is->wq)
-		wake_up_interruptible(&is->wq);
+	wake_up_interruptible(&is->wq);
 
 	return len;
 }
@@ -1139,9 +1137,9 @@
 			proto = PPP_IPX;	/* untested */
 			break;
 		default:
-			dev_kfree_skb(skb);
 			printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", 
 			       skb->protocol);
+			dev_kfree_skb(skb);
 			return 0;
 	}
 
diff -urN linux-2.2.19-pre9/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- linux-2.2.19-pre9/drivers/isdn/isdn_tty.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/isdn/isdn_tty.c	Mon Dec  3 21:01:22 2001
@@ -1633,8 +1633,7 @@
 static int
 isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
 {
-	struct wait_queue wait =
-	{current, NULL};
+	DECLARE_WAITQUEUE(wait, NULL);
 	int do_clocal = 0;
 	unsigned long flags;
 	int retval;
@@ -2103,7 +2102,7 @@
 			return -3;
 		}
 #endif
-		info->write_sem = MUTEX;
+		init_MUTEX(&info->write_sem);
 		sprintf(info->last_cause, "0000");
 		sprintf(info->last_num, "none");
 		info->last_dir = 0;
@@ -2120,8 +2119,8 @@
 		info->blocked_open = 0;
 		info->callout_termios = m->cua_modem.init_termios;
 		info->normal_termios = m->tty_modem.init_termios;
-		info->open_wait = 0;
-		info->close_wait = 0;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
 		info->isdn_driver = -1;
 		info->isdn_channel = -1;
 		info->drv_index = -1;
diff -urN linux-2.2.19-pre9/drivers/isdn/isdn_v110.c linux/drivers/isdn/isdn_v110.c
--- linux-2.2.19-pre9/drivers/isdn/isdn_v110.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/isdn/isdn_v110.c	Mon Dec  3 21:01:22 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.5 2000/05/11 22:29:21 kai Exp $
+/* $Id: isdn_v110.c,v 1.5.6.1 2001/01/23 17:45:02 kai Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -30,7 +30,7 @@
 
 #undef ISDN_V110_DEBUG
 
-char *isdn_v110_revision = "$Revision: 1.5 $";
+char *isdn_v110_revision = "$Revision: 1.5.6.1 $";
 
 #define V110_38400 255
 #define V110_19200  15
@@ -102,7 +102,7 @@
 	int i;
 	isdn_v110_stream *v;
 
-	if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_KERNEL)) == NULL)
+	if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
 		return NULL;
 	memset(v, 0, sizeof(isdn_v110_stream));
 	v->key = key;
@@ -134,7 +134,7 @@
 	v->b = 0;
 	v->skbres = hdrlen;
 	v->maxsize = maxsize - hdrlen;
-	if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) {
+	if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
 		kfree(v);
 		return NULL;
 	}
diff -urN linux-2.2.19-pre9/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.2.19-pre9/drivers/net/Config.in	Mon Dec  3 21:00:54 2001
+++ linux/drivers/net/Config.in	Mon Dec  3 21:01:22 2001
@@ -136,6 +136,7 @@
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT
diff -urN linux-2.2.19-pre9/drivers/net/Makefile linux/drivers/net/Makefile
--- linux-2.2.19-pre9/drivers/net/Makefile	Mon Dec  3 21:00:54 2001
+++ linux/drivers/net/Makefile	Mon Dec  3 21:01:22 2001
@@ -742,6 +742,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_ADAPTEC_STARFIRE),y)
+L_OBJS += starfire.o
+else
+  ifeq ($(CONFIG_ADAPTEC_STARFIRE),m)
+  M_OBJS += starfire.o
+  endif
+endif
+
 ifeq ($(CONFIG_AC3200),y)
 L_OBJS += ac3200.o
 CONFIG_8390_BUILTIN = y
diff -urN linux-2.2.19-pre9/drivers/net/cosa.c linux/drivers/net/cosa.c
--- linux-2.2.19-pre9/drivers/net/cosa.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/net/cosa.c	Mon Dec  3 21:01:22 2001
@@ -817,7 +817,7 @@
 	up(&chan->rsem);
 
 	if (copy_to_user(buf, kbuf, count)) {
-		kfree(buf);
+		kfree(kbuf);
 		return -EFAULT;
 	}
 	kfree(kbuf);
diff -urN linux-2.2.19-pre9/drivers/net/eepro100.c linux/drivers/net/eepro100.c
--- linux-2.2.19-pre9/drivers/net/eepro100.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/net/eepro100.c	Mon Dec  3 21:01:22 2001
@@ -778,7 +778,7 @@
 		/* The self-test results must be paragraph aligned. */
 		s32 str[6], *volatile self_test_results;
 		int boguscnt = 16000;	/* Timeout for set-test. */
-		if (eeprom[3] & 0x03)
+		if ((eeprom[3] & 0x03) != 0x03)
 			printk(KERN_INFO "  Receiver lock-up bug exists -- enabling"
 				   " work-around.\n");
 		printk(KERN_INFO "  Board assembly %4.4x%2.2x-%3.3d, Physical"
diff -urN linux-2.2.19-pre9/drivers/net/starfire.c linux/drivers/net/starfire.c
--- linux-2.2.19-pre9/drivers/net/starfire.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/starfire.c	Mon Dec  3 21:01:22 2001
@@ -0,0 +1,1903 @@
+/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */
+/*
+	Written 1998-2000 by Donald Becker.
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
+	Support and updates available at
+	http://www.scyld.com/network/starfire.html
+
+	-----------------------------------------------------------
+
+	Linux kernel-specific changes:
+	
+	LK1.1.1 (jgarzik):
+	- Use PCI driver interface
+	- Fix MOD_xxx races
+	- softnet fixups
+
+	LK1.1.2 (jgarzik):
+	- Merge Becker version 0.15
+
+	LK1.1.3 (Andrew Morton)
+	- Timer cleanups
+	
+	LK1.1.4 (jgarzik):
+	- Merge Becker version 1.03
+
+	LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
+	- Support hardware Rx/Tx checksumming
+	- Use the GFP firmware taken from Adaptec's Netware driver
+
+	LK1.2.2 (Ion Badulescu)
+	- Backported to 2.2.x
+*/
+
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n";
+static const char version2[] =
+" Updates and info at http://www.scyld.com/network/starfire.html\n";
+
+static const char version3[] =
+" (unofficial 2.2.x kernel port, version 1.2.2, February 07, 2001)\n";
+
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
+
+/*
+ * Adaptec's license for their Novell drivers (which is where I got the
+ * firmware files) does not allow to redistribute them. Thus, we can't
+ * include them with this driver.
+ *
+ * However, an end-user is allowed to download and use them, after
+ * converting them to C header files using starfire_firmware.pl.
+ * Once that's done, the #undef must be changed into a #define
+ * for this driver to really use the firmware. Note that Rx/Tx
+ * hardware TCP checksumming is not possible without the firmware.
+ *
+ * I'm currently talking to Adaptec about this redistribution issue.
+ * Stay tuned...
+ */
+#undef HAS_FIRMWARE
+/*
+ * The current frame processor firmware fails to checksum a fragment
+ * of length 1. If and when this is fixed, the #define below can be removed.
+ */
+#define HAS_BROKEN_FIRMWARE
+/*
+ * Define this if using the driver with the zero-copy patch
+ */
+#undef ZEROCOPY
+
+/* Used for tuning interrupt latency vs. overhead. */
+static int interrupt_mitigation = 0x0;
+
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int max_interrupt_work = 20;
+static int mtu = 0;
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+   The Starfire has a 512 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static int rx_copybreak = 0;
+
+/* Used to pass the media type, etc.
+   Both 'options[]' and 'full_duplex[]' exist for driver interoperability.
+   The media type is usually passed in 'options[]'.
+*/
+#define MAX_UNITS 8		/* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Operational parameters that are set at compile time. */
+
+/* The "native" ring sizes are either 256 or 2048.
+   However in some modes a descriptor may be marked to wrap the ring earlier.
+   The driver allocates a single page for each descriptor ring, constraining
+   the maximum size in an architecture-dependent way.
+*/
+#define RX_RING_SIZE	256
+#define TX_RING_SIZE	32
+/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */
+#define DONE_Q_SIZE	1024
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+/*
+ * The ia64 doesn't allow for unaligned loads even of integers being
+ * misaligned on a 2 byte boundary. Thus always force copying of
+ * packets as the starfire doesn't allow for misaligned DMAs ;-(
+ * 23/10/2000 - Jes
+ *
+ * Neither does the Alpha. -Ion
+ */
+#if defined(__ia64__) || defined(__alpha__)
+#define PKT_SHOULD_COPY(pkt_len)       1
+#else
+#define PKT_SHOULD_COPY(pkt_len)       (pkt_len < rx_copybreak)
+#endif
+
+#ifdef ZEROCOPY
+#define skb_first_frag_len(skb)	skb_headlen(skb)
+#else  /* not ZEROCOPY */
+#define skb_first_frag_len(skb)	(skb->len)
+#endif /* not ZEROCOPY */
+
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < 0x20300
+#include <linux/kcomp.h>
+
+static LIST_HEAD(pci_drivers);
+
+struct pci_driver_mapping {
+        struct pci_dev *dev;
+        struct pci_driver *drv;
+        void *driver_data;
+};
+
+struct pci_device_id {
+        unsigned int vendor, device;
+        unsigned int subvendor, subdevice;
+        unsigned int class, class_mask;
+        unsigned long driver_data;
+};
+
+struct pci_driver {
+        struct list_head node;
+        struct pci_dev *dev;
+        char *name;
+        const struct pci_device_id *id_table;   /* NULL if wants all devices */
+        int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);      /* New device inserted */
+        void (*remove)(struct pci_dev *dev);    /* Device removed (NULL if not a hot-plug capable driver) */
+        void (*suspend)(struct pci_dev *dev);   /* Device suspended */
+        void (*resume)(struct pci_dev *dev);    /* Device woken up */
+};
+
+#define PCI_MAX_MAPPINGS 16
+static struct pci_driver_mapping drvmap [PCI_MAX_MAPPINGS] = { { NULL, } , };
+
+#define __devinit
+#define __devinitdata
+#define __devexit
+#define MODULE_DEVICE_TABLE(foo,bar)
+#define PCI_ANY_ID (~0)
+#define IORESOURCE_MEM          2
+#define PCI_DMA_FROMDEVICE 0
+#define PCI_DMA_TODEVICE 0
+
+#define request_mem_region(addr, size, name)	((void *)1)
+#define release_mem_region(addr, size)
+#define del_timer_sync(timer)	del_timer(timer)
+
+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+										 dma_addr_t *dma_handle)
+{
+	void *virt_ptr;
+
+	virt_ptr = kmalloc(size, GFP_KERNEL);
+	*dma_handle = virt_to_bus(virt_ptr);
+	return virt_ptr;
+}
+#define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
+#define pci_map_single(cookie, address, size, dir)	virt_to_bus(address)
+#define pci_unmap_single(cookie, address, size, dir)
+#define pci_dma_sync_single(cookie, address, size, dir)
+#undef  pci_resource_flags
+#define pci_resource_flags(dev, i) \
+  ((dev->base_address[i] & IORESOURCE_IO) ? IORESOURCE_IO : IORESOURCE_MEM)
+
+void * pci_get_drvdata (struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_MAX_MAPPINGS; i++)
+		if (drvmap[i].dev == dev)
+			return drvmap[i].driver_data;
+
+	return NULL;
+}
+
+void pci_set_drvdata (struct pci_dev *dev, void *driver_data)
+{
+	int i;
+
+	for (i = 0; i < PCI_MAX_MAPPINGS; i++)
+		if (drvmap[i].dev == dev) {
+			drvmap[i].driver_data = driver_data;
+			return;
+		}
+}
+
+const struct pci_device_id *
+pci_compat_match_device(const struct pci_device_id *ids, struct pci_dev *dev)
+{
+	u16 subsystem_vendor, subsystem_device;
+
+	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subsystem_device);
+
+	while (ids->vendor || ids->subvendor || ids->class_mask) {
+		if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
+			(ids->device == PCI_ANY_ID || ids->device == dev->device) &&
+			(ids->subvendor == PCI_ANY_ID || ids->subvendor == subsystem_vendor) &&
+			(ids->subdevice == PCI_ANY_ID || ids->subdevice == subsystem_device) &&
+			!((ids->class ^ dev->class) & ids->class_mask))
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int
+pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
+{
+	const struct pci_device_id *id;
+	int found, i;
+
+	if (drv->id_table) {
+		id = pci_compat_match_device(drv->id_table, dev);
+		if (!id)
+			return 0;
+	} else
+		id = NULL;
+
+	found = 0;
+	for (i = 0; i < PCI_MAX_MAPPINGS && !found; i++)
+		if (!drvmap[i].dev) {
+			drvmap[i].dev = dev;
+			drvmap[i].drv = drv;
+			found = 1;
+		}
+
+	if (drv->probe(dev, id) >= 0) {
+		if(found)
+			return 1;
+	} else {
+		drvmap[i - 1].dev = NULL;
+	}
+	return 0;
+}
+
+int
+pci_register_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+	int count = 0, found, i;
+#ifdef CONFIG_PCI
+	list_add_tail(&drv->node, &pci_drivers);
+	for (dev = pci_devices; dev; dev = dev->next) {
+		found = 0;
+		for (i = 0; i < PCI_MAX_MAPPINGS && !found; i++)
+			if (drvmap[i].dev == dev)
+				found = 1;
+		if (!found)
+			count += pci_announce_device(drv, dev);
+	}
+#endif
+	return count;
+}
+
+void
+pci_unregister_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+	int i, found;
+#ifdef CONFIG_PCI
+	list_del(&drv->node);
+	for (dev = pci_devices; dev; dev = dev->next) {
+		found = 0;
+		for (i = 0; i < PCI_MAX_MAPPINGS && !found; i++)
+			if (drvmap[i].dev == dev)
+				found = 1;
+		if (found) {
+			if (drv->remove)
+				drv->remove(dev);
+			drvmap[i - 1].dev = NULL;
+		}
+	}
+#endif
+}
+
+void *compat_request_region (unsigned long start, unsigned long n, const char *name)
+{
+	if (check_region (start, n) != 0)
+		return NULL;
+	request_region (start, n, name);
+	return (void *) 1;
+}
+
+static inline int pci_module_init(struct pci_driver *drv)
+{
+	int rc = pci_register_driver (drv);
+
+	if (rc > 0)
+		return 0;
+
+	/* if we get here, we need to clean up pci driver instance
+	 * and return some sort of error */
+	pci_unregister_driver (drv);
+
+	return -ENODEV;
+}
+
+#endif /* LINUX_VERSION_CODE < 0x20300 */
+
+#ifdef HAS_FIRMWARE
+#include "starfire_firmware.h"
+#endif /* HAS_FIRMWARE */
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(mtu, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(interrupt_mitigation, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This driver is for the Adaptec 6915 "Starfire" 64 bit PCI Ethernet adapter.
+
+II. Board-specific settings
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Starfire hardware uses multiple fixed-size descriptor queues/rings.  The
+ring sizes are set fixed by the hardware, but may optionally be wrapped
+earlier by the END bit in the descriptor.
+This driver uses that hardware queue size for the Rx ring, where a large
+number of entries has no ill effect beyond increases the potential backlog.
+The Tx ring is wrapped with the END bit, since a large hardware Tx queue
+disables the queue layer priority ordering and we have no mechanism to
+utilize the hardware two-level priority queue.  When modifying the
+RX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warning
+levels.
+
+IIIb/c. Transmit/Receive Structure
+
+See the Adaptec manual for the many possible structures, and options for
+each structure.  There are far too many to document here.
+
+For transmit this driver uses type 0/1 transmit descriptors (depending
+on the presence of the zerocopy patches), and relies on automatic
+minimum-length padding.  It does not use the completion queue
+consumer index, but instead checks for non-zero status entries.
+
+For receive this driver uses type 0 receive descriptors.  The driver
+allocates full frame size skbuffs for the Rx ring buffers, so all frames
+should fit in a single descriptor.  The driver does not use the completion
+queue consumer index, but instead checks for non-zero status entries.
+
+When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff
+is allocated and the frame is copied to the new skbuff.  When the incoming
+frame is larger, the skbuff is passed directly up the protocol stack.
+Buffers consumed this way are replaced by newly allocated skbuffs in a
+later phase of receive.
+
+A notable aspect of operation is that unaligned buffers are not permitted by
+the Starfire hardware.  The IP header at offset 14 in an ethernet frame thus
+isn't longword aligned, which may cause problems on some machine
+e.g. Alphas and IA64. For these architectures, the driver is forced to copy
+the frame into a new skbuff unconditionally. Copied frames are put into the
+skbuff at an offset of "+2", thus 16-byte aligning the IP header.
+
+IIId. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and interrupt handling software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+The Adaptec Starfire manuals, available only from Adaptec.
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
+
+IVc. Errata
+
+*/
+
+
+
+enum chip_capability_flags {CanHaveMII=1, };
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)
+#define MEM_ADDR_SZ 0x80000		/* And maps in 0.5MB(!).  */
+
+#if 0
+#define ADDR_64BITS 1			/* This chip uses 64 bit addresses. */
+#endif
+
+#define HAS_IP_COPYSUM 1
+
+enum chipset {
+	CH_6915 = 0,
+};
+
+static struct pci_device_id starfire_pci_tbl[] __devinitdata = {
+	{ 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
+
+/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
+static struct chip_info {
+	const char *name;
+	int io_size;
+	int drv_flags;
+} netdrv_tbl[] __devinitdata = {
+	{ "Adaptec Starfire 6915", MEM_ADDR_SZ, CanHaveMII },
+};
+
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum register_offsets {
+	PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074,
+	IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088,
+	MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
+	TxDescCtrl=0x50090,
+	TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
+	TxRingHiAddr=0x5009C,		/* 64 bit address extension. */
+	TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4,
+	TxThreshold=0x500B0,
+	CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8,
+	RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0,
+	CompletionQConsumerIdx=0x500C4, RxDMACtrl=0x500D0,
+	RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0,
+	RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4,
+	TxMode=0x55000, TxGfpMem=0x58000, RxGfpMem=0x5a000,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+	IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000,
+	IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000,
+	IntrSoftware=0x800000, IntrRxComplQ1Low=0x400000,
+	IntrTxComplQLow=0x200000, IntrPCI=0x100000,
+	IntrDMAErr=0x080000, IntrTxDataLow=0x040000,
+	IntrRxComplQ2Low=0x020000, IntrRxDescQ1Low=0x010000,
+	IntrNormalSummary=0x8000, IntrTxDone=0x4000,
+	IntrTxDMADone=0x2000, IntrTxEmpty=0x1000,
+	IntrEarlyRxQ2=0x0800, IntrEarlyRxQ1=0x0400,
+	IntrRxQ2Done=0x0200, IntrRxQ1Done=0x0100,
+	IntrRxGFPDead=0x80, IntrRxDescQ2Low=0x40,
+	IntrNoTxCsum=0x20, IntrTxBadID=0x10,
+	IntrHiPriTxBadID=0x08, IntrRxGfp=0x04,
+	IntrTxGfp=0x02, IntrPCIPad=0x01,
+	/* not quite bits */
+	IntrRxDone=IntrRxQ2Done | IntrRxQ1Done,
+	IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low,
+};
+
+/* Bits in the RxFilterMode register. */
+enum rx_mode_bits {
+	AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01,
+	AcceptMulticast=0x10, AcceptMyPhys=0xE040,
+};
+
+/* Bits in the TxDescCtrl register. */
+enum tx_ctrl_bits {
+	TxDescSpaceUnlim=0x00, TxDescSpace32=0x10, TxDescSpace64=0x20,
+	TxDescSpace128=0x30, TxDescSpace256=0x40,
+	TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02,
+	TxDescType3=0x03, TxDescType4=0x04,
+	TxNoDMACompletion=0x08, TxDescQ64bit=0x80,
+	TxHiPriFIFOThreshShift=24, TxPadLenShift=16,
+	TxDMABurstSizeShift=8,
+};
+
+/* Bits in the RxDescQCtrl register. */
+enum rx_ctrl_bits {
+	RxBufferLenShift=16, RxMinDescrThreshShift=0,
+	RxPrefetchMode=0x8000, Rx2048QEntries=0x4000,
+	RxVariableQ=0x2000, RxDesc64bit=0x1000,
+	RxDescQAddr64bit=0x0100,
+	RxDescSpace4=0x000, RxDescSpace8=0x100,
+	RxDescSpace16=0x200, RxDescSpace32=0x300,
+	RxDescSpace64=0x400, RxDescSpace128=0x500,
+	RxConsumerWrEn=0x80,
+};
+
+/* Bits in the RxCompletionAddr register */
+enum rx_compl_bits {
+	RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40,
+	RxComplType0=0x00, RxComplType1=0x10,
+	RxComplType2=0x20, RxComplType3=0x30,
+	RxComplThreshShift=0,
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct starfire_rx_desc {
+	u32 rxaddr;					/* Optionally 64 bits. */
+};
+enum rx_desc_bits {
+	RxDescValid=1, RxDescEndRing=2,
+};
+
+/* Completion queue entry.
+   You must update the page allocation, init_ring and the shift count in rx()
+   if using a larger format. */
+#ifdef HAS_FIRMWARE
+#define csum_rx_status
+#endif /* HAS_FIRMWARE */
+struct rx_done_desc {
+	u32 status;					/* Low 16 bits is length. */
+#ifdef csum_rx_status
+	u32 status2;				/* Low 16 bits is csum */
+#endif /* csum_rx_status */
+#ifdef full_rx_status
+	u32 status2;
+	u16 vlanid;
+	u16 csum; 			/* partial checksum */
+	u32 timestamp;
+#endif /* full_rx_status */
+};
+enum rx_done_bits {
+	RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
+};
+
+#ifdef ZEROCOPY
+/* Type 0 Tx descriptor. */
+/* If more fragments are needed, don't forget to change the
+   descriptor spacing as well! */
+struct starfire_tx_desc {
+	u32 status;
+	u32 nbufs;
+	u32 first_addr;
+	u16 first_len;
+	u16 total_len;
+	struct {
+		u32 addr;
+		u32 len;
+	} frag[6];
+};
+#else  /* not ZEROCOPY */
+/* Type 1 Tx descriptor. */
+struct starfire_tx_desc {
+	u32 status;					/* Upper bits are status, lower 16 length. */
+	u32 first_addr;
+};
+#endif /* not ZEROCOPY */
+enum tx_desc_bits {
+	TxDescID=0xB0000000,
+	TxCRCEn=0x01000000, TxDescIntr=0x08000000,
+	TxRingWrap=0x04000000, TxCalTCP=0x02000000,
+};
+struct tx_done_report {
+	u32 status;					/* timestamp, index. */
+#if 0
+	u32 intrstatus;				/* interrupt status */
+#endif
+};
+
+#define PRIV_ALIGN	15 	/* Required alignment mask */
+struct rx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+};
+struct tx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t first_mapping;
+#ifdef ZEROCOPY
+	dma_addr_t frag_mapping[6];
+#endif /* ZEROCOPY */
+};
+
+struct netdev_private {
+	/* Descriptor rings first for alignment. */
+	struct starfire_rx_desc *rx_ring;
+	struct starfire_tx_desc *tx_ring;
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
+	/* The addresses of rx/tx-in-place skbuffs. */
+	struct rx_ring_info rx_info[RX_RING_SIZE];
+	struct tx_ring_info tx_info[TX_RING_SIZE];
+	/* Pointers to completion queues (full pages).  I should cache line pad..*/
+	u8 pad0[100];
+	struct rx_done_desc *rx_done_q;
+	dma_addr_t rx_done_q_dma;
+	unsigned int rx_done;
+	struct tx_done_report *tx_done_q;
+	unsigned int tx_done;
+	dma_addr_t tx_done_q_dma;
+	struct net_device_stats stats;
+	struct timer_list timer;	/* Media monitoring timer. */
+	struct pci_dev *pci_dev;
+	/* Frequently used values: keep some adjacent for cache effect. */
+	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned int cur_tx, dirty_tx;
+	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	/* These values are keep track of the transceiver/media in use. */
+	unsigned int full_duplex:1,			/* Full-duplex operation requested. */
+		medialock:1,					/* Xcvr set to fixed speed/duplex. */
+		rx_flowctrl:1,
+		tx_flowctrl:1;					/* Use 802.3x flow control. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	u32 tx_mode;
+	u8 tx_threshold;
+	/* MII transceiver section. */
+	int mii_cnt;						/* MII device addresses. */
+	u16 advertising;					/* NWay media advertisement */
+	unsigned char phys[2];				/* MII device addresses. */
+};
+
+static int  mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int  netdev_open(struct net_device *dev);
+static void check_duplex(struct net_device *dev, int startup);
+static void netdev_timer(unsigned long data);
+static void tx_timeout(struct net_device *dev);
+static void init_ring(struct net_device *dev);
+static int  start_tx(struct sk_buff *skb, struct net_device *dev);
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static void netdev_error(struct net_device *dev, int intr_status);
+static int  netdev_rx(struct net_device *dev);
+static void netdev_error(struct net_device *dev, int intr_status);
+static void set_rx_mode(struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int  netdev_close(struct net_device *dev);
+
+
+
+static int __devinit starfire_init_one (struct pci_dev *pdev,
+					const struct pci_device_id *ent)
+{
+	struct netdev_private *np;
+	int i, irq, option, chip_idx = ent->driver_data;
+	struct net_device *dev;
+	static int card_idx = -1;
+	static int printed_version = 0;
+	long ioaddr;
+	int drv_flags, io_size;
+
+	card_idx++;
+	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+
+	if (!printed_version++)
+		printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
+		       version1, version2, version3);
+
+	if (pci_enable_device (pdev))
+		return -EIO;
+
+	ioaddr = pci_resource_start (pdev, 0);
+	io_size = pci_resource_len (pdev, 0);
+	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
+		printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx);
+		return -ENODEV;
+	}
+	
+	dev = init_etherdev(NULL, sizeof(*np));
+	if (!dev) {
+		printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx);
+		return -ENOMEM;
+	}
+	
+	irq = pdev->irq; 
+
+	if (request_mem_region (ioaddr, io_size, dev->name) == NULL) {
+		printk (KERN_ERR "starfire %d: resource 0x%x @ 0x%lx busy, aborting\n",
+			card_idx, io_size, ioaddr);
+		goto err_out_free_netdev;
+	}
+	
+	ioaddr = (long) ioremap (ioaddr, io_size);
+	if (!ioaddr) {
+		printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n",
+			card_idx, io_size, ioaddr);
+		goto err_out_free_res;
+	}
+
+	pci_set_master (pdev);
+	
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, netdrv_tbl[chip_idx].name, ioaddr);
+
+#ifdef ZEROCOPY
+	/* Starfire can do SG and TCP/UDP checksumming */
+	dev->features |= NETIF_F_SG;
+#ifdef HAS_FIRMWARE
+	dev->features |= NETIF_F_IP_CSUM;
+#endif /* HAS_FIRMWARE */
+#endif /* ZEROCOPY */
+
+	/* Serial EEPROM reads are hidden by the hardware. */
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);
+	for (i = 0; i < 5; i++)
+			printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+#if ! defined(final_version) /* Dump the EEPROM contents during development. */
+	if (debug > 4)
+		for (i = 0; i < 0x20; i++)
+			printk("%2.2x%s", (unsigned int)readb(ioaddr + EEPROMCtrl + i),
+				   i % 16 != 15 ? " " : "\n");
+#endif
+
+	/* Reset the chip to erase previous misconfiguration. */
+	writel(1, ioaddr + PCIDeviceConfig);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	np = dev->priv;
+	pci_set_drvdata(pdev, dev);
+
+	np->pci_dev = pdev;
+	drv_flags = netdrv_tbl[chip_idx].drv_flags;
+
+	if (dev->mem_start)
+		option = dev->mem_start;
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		if (option & 0x200)
+			np->full_duplex = 1;
+		np->default_port = option & 15;
+		if (np->default_port)
+			np->medialock = 1;
+	}
+	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
+		np->full_duplex = 1;
+
+	if (np->full_duplex)
+		np->medialock = 1;
+
+	/* The chip-specific entries in the device structure. */
+	dev->open = &netdev_open;
+	dev->hard_start_xmit = &start_tx;
+	dev->stop = &netdev_close;
+	dev->get_stats = &get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &mii_ioctl;
+
+	if (mtu)
+		dev->mtu = mtu;
+
+	if (drv_flags & CanHaveMII) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				np->phys[phy_idx++] = phy;
+				np->advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII PHY found at address %d, status "
+					   "0x%4.4x advertising %4.4x.\n",
+					   dev->name, phy, mii_status, np->advertising);
+			}
+		}
+		np->mii_cnt = phy_idx;
+	}
+
+	return 0;
+
+err_out_free_res:
+	release_mem_region (ioaddr, io_size);
+err_out_free_netdev:
+	unregister_netdev (dev);
+	kfree (dev);
+	return -ENODEV;
+}
+
+
+/* Read the MII Management Data I/O (MDIO) interfaces. */
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+	int result, boguscnt=1000;
+	/* ??? Should we add a busy-wait here? */
+	do
+		result = readl(mdio_addr);
+	while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
+	return result & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+	writel(value, mdio_addr);
+	/* The busy-wait will occur before a read. */
+	return;
+}
+
+
+static int netdev_open(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i, retval;
+
+	/* Do we ever need to reset the chip??? */
+
+	MOD_INC_USE_COUNT;
+
+	retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	/* Disable the Rx and Tx, and reset the chip. */
+	writel(0, ioaddr + GenCtrl);
+	writel(1, ioaddr + PCIDeviceConfig);
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+			   dev->name, dev->irq);
+	/* Allocate the various queues, failing gracefully. */
+	if (np->tx_done_q == 0)
+		np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma);
+	if (np->rx_done_q == 0)
+		np->rx_done_q = pci_alloc_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, &np->rx_done_q_dma);
+	if (np->tx_ring == 0)
+		np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma);
+	if (np->rx_ring == 0)
+		np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma);
+	if (np->tx_done_q == 0  ||  np->rx_done_q == 0
+		|| np->rx_ring == 0 ||  np->tx_ring == 0) {
+		if (np->tx_done_q)
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
+								np->tx_done_q, np->tx_done_q_dma);
+		if (np->rx_done_q)
+			pci_free_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE,
+								np->rx_done_q, np->rx_done_q_dma);
+		if (np->tx_ring)
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
+								np->tx_ring, np->tx_ring_dma);
+		if (np->rx_ring)
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
+								np->rx_ring, np->rx_ring_dma);
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	init_ring(dev);
+	/* Set the size of the Rx buffers. */
+	writel((np->rx_buf_sz << RxBufferLenShift) |
+		   (0 << RxMinDescrThreshShift) |
+		   RxPrefetchMode | RxVariableQ |
+		   RxDescSpace4,
+		   ioaddr + RxDescQCtrl);
+
+#ifdef ZEROCOPY
+	/* Set Tx descriptor to type 0 and spacing to 64 bytes. */
+	writel((2 << TxHiPriFIFOThreshShift) |
+	       (0 << TxPadLenShift) |
+	       (4 << TxDMABurstSizeShift) |
+	       TxDescSpace64 | TxDescType0,
+	       ioaddr + TxDescCtrl);
+#else  /* not ZEROCOPY */
+	/* Set Tx descriptor to type 1 and padding to 0 bytes. */
+	writel((2 << TxHiPriFIFOThreshShift) |
+	       (0 << TxPadLenShift) |
+	       (4 << TxDMABurstSizeShift) |
+	       TxDescSpaceUnlim | TxDescType1,
+	       ioaddr + TxDescCtrl);
+#endif /* not ZEROCOPY */
+
+#if defined(ADDR_64BITS) && defined(__alpha__)
+	/* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */
+	writel(np->rx_ring_dma >> 32, ioaddr + RxDescQHiAddr);
+	writel(np->tx_ring_dma >> 32, ioaddr + TxRingHiAddr);
+#else
+	writel(0, ioaddr + RxDescQHiAddr);
+	writel(0, ioaddr + TxRingHiAddr);
+	writel(0, ioaddr + CompletionHiAddr);
+#endif
+	writel(np->rx_ring_dma, ioaddr + RxDescQAddr);
+	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
+
+	writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr);
+#ifdef full_rx_status
+	writel(np->rx_done_q_dma |
+		   RxComplType3 |
+		   (0 << RxComplThreshShift),
+		   ioaddr + RxCompletionAddr);
+#else  /* not full_rx_status */
+#ifdef csum_rx_status
+	writel(np->rx_done_q_dma |
+		   RxComplType2 |
+		   (0 << RxComplThreshShift),
+		   ioaddr + RxCompletionAddr);
+#else  /* not csum_rx_status */
+	writel(np->rx_done_q_dma |
+		   RxComplType0 |
+		   (0 << RxComplThreshShift),
+		   ioaddr + RxCompletionAddr);
+#endif /* not csum_rx_status */
+#endif /* not full_rx_status */
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s:  Filling in the station address.\n", dev->name);
+
+	/* Fill both the unused Tx SA register and the Rx perfect filter. */
+	for (i = 0; i < 6; i++)
+		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i);
+	for (i = 0; i < 16; i++) {
+		u16 *eaddrs = (u16 *)dev->dev_addr;
+		long setup_frm = ioaddr + 0x56000 + i*16;
+		writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
+		writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
+		writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
+	}
+
+	/* Initialize other registers. */
+	/* Configure the PCI bus bursts and FIFO thresholds. */
+	np->tx_mode = 0;			/* Initialized when TxMode set. */
+	np->tx_threshold = 4;
+	writel(np->tx_threshold, ioaddr + TxThreshold);
+	writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);
+
+	if (dev->if_port == 0)
+		dev->if_port = np->default_port;
+
+	netif_start_queue(dev);
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s:  Setting the Rx and Tx modes.\n", dev->name);
+	set_rx_mode(dev);
+
+	np->advertising = mdio_read(dev, np->phys[0], 4);
+	check_duplex(dev, 1);
+
+	/* Set the interrupt mask and enable PCI interrupts. */
+	writel(IntrRxDone | IntrRxEmpty | IntrDMAErr |
+	       IntrTxDone | IntrStatsMax | IntrLinkChange |
+	       IntrNormalSummary | IntrAbnormalSummary |
+	       IntrRxGFPDead | IntrNoTxCsum | IntrTxBadID,
+	       ioaddr + IntrEnable);
+	writel(0x00800000 | readl(ioaddr + PCIDeviceConfig),
+		   ioaddr + PCIDeviceConfig);
+
+#ifdef HAS_FIRMWARE
+	/* Load Rx/Tx firmware into the frame processors */
+	for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
+		writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4);
+	for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
+		writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4);
+	/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
+	writel(0x003F, ioaddr + GenCtrl);
+#else  /* not HAS_FIRMWARE */
+	/* Enable the Rx and Tx units only. */
+	writel(0x000F, ioaddr + GenCtrl);
+#endif /* not HAS_FIRMWARE */
+
+	if (debug > 2)
+		printk(KERN_DEBUG "%s: Done netdev_open().\n",
+			   dev->name);
+
+	/* Set the timer to check for link beat. */
+	init_timer(&np->timer);
+	np->timer.expires = jiffies + 3*HZ;
+	np->timer.data = (unsigned long)dev;
+	np->timer.function = &netdev_timer;				/* timer handler */
+	add_timer(&np->timer);
+
+	return 0;
+}
+
+static void check_duplex(struct net_device *dev, int startup)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int new_tx_mode ;
+
+	new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0)
+		| (np->rx_flowctrl ? 0x0400:0);
+	if (np->medialock) {
+		if (np->full_duplex)
+			new_tx_mode |= 2;
+	} else {
+		int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+		int negotiated =  mii_reg5 & np->advertising;
+		int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+		if (duplex)
+			new_tx_mode |= 2;
+		if (np->full_duplex != duplex) {
+			np->full_duplex = duplex;
+			if (debug > 1)
+				printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
+					   " negotiated capability %4.4x.\n", dev->name,
+					   duplex ? "full" : "half", np->phys[0], negotiated);
+		}
+	}
+	if (new_tx_mode != np->tx_mode) {
+		np->tx_mode = new_tx_mode;
+		writel(np->tx_mode | 0x8000, ioaddr + TxMode);
+		writel(np->tx_mode, ioaddr + TxMode);
+	}
+}
+
+static void netdev_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;		/* Check before driver release. */
+
+	if (debug > 3) {
+		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
+			   dev->name, (int)readl(ioaddr + IntrStatus));
+	}
+	check_duplex(dev, 0);
+#if ! defined(final_version)
+	/* This is often falsely triggered. */
+	if (readl(ioaddr + IntrStatus) & 1) {
+		int new_status = readl(ioaddr + IntrStatus);
+		/* Bogus hardware IRQ: Fake an interrupt handler call. */
+		if (new_status & 1) {
+			printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n",
+				   dev->name, new_status, (int)readl(ioaddr + IntrStatus));
+			intr_handler(dev->irq, dev, 0);
+		}
+	}
+#endif
+
+	np->timer.expires = jiffies + next_tick;
+	add_timer(&np->timer);
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
+		   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
+
+#ifndef __alpha__
+	{
+		int i;
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr));
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status));
+		printk("\n");
+	}
+#endif
+
+	/* Perhaps we should reinitialize the hardware here. */
+	dev->if_port = 0;
+	/* Stop and restart the chip's Tx processes . */
+
+	/* Trigger an immediate transmit demand. */
+
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	netif_wake_queue(dev);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void init_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	np->tx_full = 0;
+	np->cur_rx = np->cur_tx = 0;
+	np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0;
+
+	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+		np->rx_info[i].skb = skb;
+		if (skb == NULL)
+			break;
+		np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		skb->dev = dev;			/* Mark as being used by this device. */
+		/* Grrr, we cannot offset to correctly align the IP header. */
+		np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
+	}
+	writew(i - 1, dev->base_addr + RxDescQIdx);
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	/* Clear the remainder of the Rx buffer ring. */
+	for (  ; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rxaddr = 0;
+		np->rx_info[i].skb = NULL;
+		np->rx_info[i].mapping = 0;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing);
+
+	/* Clear the completion rings. */
+	for (i = 0; i < DONE_Q_SIZE; i++) {
+		np->rx_done_q[i].status = 0;
+		np->tx_done_q[i].status = 0;
+	}
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_info[i].skb = NULL;
+		np->tx_info[i].first_mapping = 0;
+#ifdef ZEROCOPY
+		{
+			int j;
+			for (j = 0; j < 6; j++)
+				np->tx_info[i].frag_mapping[j] = 0;
+		}
+#endif /* ZEROCOPY */
+		np->tx_ring[i].status = 0;
+	}
+	return;
+}
+
+static int start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	unsigned int entry;
+#ifdef ZEROCOPY
+	int i;
+#endif
+
+	if (netif_queue_stopped(dev)) {
+		/* If this happens network layer tells us we're broken. */
+		if (jiffies - dev->trans_start > TX_TIMEOUT)
+			tx_timeout(dev);
+	}
+
+	/* Caution: the write order is important here, set the field
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = np->cur_tx % TX_RING_SIZE;
+
+#if defined(ZEROCOPY) && defined(HAS_FIRMWARE) && defined(HAS_BROKEN_FIRMWARE)
+	{
+		int has_bad_length = 0;
+
+		if (skb_first_frag_len(skb) == 1)
+			has_bad_length = 1;
+		else {
+			for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+				if (skb_shinfo(skb)->frags[i].size == 1) {
+					has_bad_length = 1;
+					break;
+				}
+		}
+
+		if (has_bad_length)
+			skb_checksum_help(skb);
+	}
+#endif /* ZEROCOPY && HAS_FIRMWARE && HAS_BROKEN_FIRMWARE */
+
+	np->tx_info[entry].skb = skb;
+	np->tx_info[entry].first_mapping =
+		pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+
+	np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping);
+#ifdef ZEROCOPY
+	np->tx_ring[entry].first_len = cpu_to_le32(skb_first_frag_len(skb));
+	np->tx_ring[entry].total_len = cpu_to_le32(skb->len);
+	/* Add  "| TxDescIntr" to generate Tx-done interrupts. */
+	np->tx_ring[entry].status = cpu_to_le32(TxDescID | TxCRCEn);
+	np->tx_ring[entry].nbufs = cpu_to_le32(skb_shinfo(skb)->nr_frags + 1);
+#else  /* not ZEROCOPY */
+	/* Add  "| TxDescIntr" to generate Tx-done interrupts. */
+	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID | TxCRCEn | 1 << 16);
+#endif /* not ZEROCOPY */
+
+	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
+		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
+
+	/* not ifdef'ed, but shouldn't happen without ZEROCOPY */
+	if (skb->ip_summed == CHECKSUM_HW)
+		np->tx_ring[entry].status |= cpu_to_le32(TxCalTCP);
+
+	if (debug > 5) {
+#ifdef ZEROCOPY
+		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x nbufs %d len %4.4x/%4.4x.\n",
+			   dev->name, np->cur_tx, entry,
+			   le32_to_cpu(np->tx_ring[entry].status),
+			   le32_to_cpu(np->tx_ring[entry].nbufs),
+			   le32_to_cpu(np->tx_ring[entry].first_len),
+			   le32_to_cpu(np->tx_ring[entry].total_len));
+#else  /* not ZEROCOPY */
+		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x.\n",
+			   dev->name, np->cur_tx, entry,
+			   le32_to_cpu(np->tx_ring[entry].status));
+#endif /* not ZEROCOPY */
+	}
+
+#ifdef ZEROCOPY
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		skb_frag_t *this_frag = &skb_shinfo(skb)->frags[i];
+
+		/* we already have the proper value in entry */
+		np->tx_info[entry].frag_mapping[i] =
+			pci_map_single(np->pci_dev, page_address(this_frag->page) + this_frag->page_offset, this_frag->size, PCI_DMA_TODEVICE);
+
+		np->tx_ring[entry].frag[i].addr = cpu_to_le32(np->tx_info[entry].frag_mapping[i]);
+		np->tx_ring[entry].frag[i].len = cpu_to_le32(this_frag->size);
+		if (debug > 5) {
+			printk(KERN_DEBUG "%s: Tx #%d frag %d len %4.4x.\n",
+				   dev->name, np->cur_tx, i,
+				   le32_to_cpu(np->tx_ring[entry].frag[i].len));
+		}
+	}
+#endif /* ZEROCOPY */
+
+	np->cur_tx++;
+
+	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
+		entry = -1;
+	entry++;
+
+	/* Non-x86: explicitly flush descriptor cache lines here. */
+	/* Ensure everything is written back above before the transmit is
+	   initiated. - Jes */
+	wmb();
+
+	/* Update the producer index. */
+	writel(entry * (sizeof(struct starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx);
+
+	if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
+		np->tx_full = 1;
+		netif_stop_queue(dev);
+	}
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct netdev_private *np;
+	long ioaddr;
+	int boguscnt = max_interrupt_work;
+
+#ifndef final_version			/* Can never occur. */
+	if (dev == NULL) {
+		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown "
+				"device.\n", irq);
+		return;
+	}
+#endif
+
+	ioaddr = dev->base_addr;
+	np = dev->priv;
+
+	do {
+		u32 intr_status = readl(ioaddr + IntrClear);
+
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n",
+				   dev->name, intr_status);
+
+		if (intr_status == 0)
+			break;
+
+		if (intr_status & IntrRxDone)
+			netdev_rx(dev);
+
+		/* Scavenge the skbuff list based on the Tx-done queue.
+		   There are redundant checks here that may be cleaned up
+		   after the driver has proven to be reliable. */
+		{
+			int consumer = readl(ioaddr + TxConsumerIdx);
+			int tx_status;
+			if (debug > 4)
+				printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
+					   dev->name, consumer);
+#if 0
+			if (np->tx_done >= 250  || np->tx_done == 0)
+				printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, "
+					   "%d is %8.8x.\n", dev->name,
+					   np->tx_done, le32_to_cpu(np->tx_done_q[np->tx_done].status),
+					   (np->tx_done+1) & (DONE_Q_SIZE-1),
+					   le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
+#endif
+			while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status))
+				   != 0) {
+				if (debug > 4)
+					printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
+						   dev->name, np->tx_done, tx_status);
+				if ((tx_status & 0xe0000000) == 0xa0000000) {
+					np->stats.tx_packets++;
+				} else if ((tx_status & 0xe0000000) == 0x80000000) {
+					struct sk_buff *skb;
+#ifdef ZEROCOPY
+					int i;
+#endif /* ZEROCOPY */
+					u16 entry = tx_status; 		/* Implicit truncate */
+					entry /= sizeof(struct starfire_tx_desc);
+
+					skb = np->tx_info[entry].skb;
+					np->tx_info[entry].skb = NULL;
+					pci_unmap_single(np->pci_dev,
+									 np->tx_info[entry].first_mapping,
+									 skb_first_frag_len(skb),
+									 PCI_DMA_TODEVICE);
+					np->tx_info[entry].first_mapping = 0;
+
+#ifdef ZEROCOPY
+					for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+						pci_unmap_single(np->pci_dev,
+										 np->tx_info[entry].frag_mapping[i],
+										 skb_shinfo(skb)->frags[i].size,
+										 PCI_DMA_TODEVICE);
+						np->tx_info[entry].frag_mapping[i] = 0;
+					}
+#endif /* ZEROCOPY */
+
+					/* Scavenge the descriptor. */
+					dev_kfree_skb_irq(skb);
+
+					np->dirty_tx++;
+				}
+				np->tx_done_q[np->tx_done].status = 0;
+				np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
+			}
+			writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
+		}
+		if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
+			/* The ring is no longer full, wake the queue. */
+			np->tx_full = 0;
+			netif_wake_queue(dev);
+		}
+
+		/* Abnormal error summary/uncommon events handlers. */
+		if (intr_status & IntrAbnormalSummary)
+			netdev_error(dev, intr_status);
+
+		if (--boguscnt < 0) {
+			printk(KERN_WARNING "%s: Too much work at interrupt, "
+				   "status=0x%4.4x.\n",
+				   dev->name, intr_status);
+			break;
+		}
+	} while (1);
+
+	if (debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+			   dev->name, (int)readl(ioaddr + IntrStatus));
+
+#ifndef final_version
+	/* Code that should never be run!  Remove after testing.. */
+	{
+		static int stopit = 10;
+		if (!netif_running(dev)  &&  --stopit < 0) {
+			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
+				   dev->name);
+			free_irq(irq, dev);
+		}
+	}
+#endif
+}
+
+/* This routine is logically part of the interrupt handler, but separated
+   for clarity and better register allocation. */
+static int netdev_rx(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+	u32 desc_status;
+
+	if (np->rx_done_q == 0) {
+		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
+			   dev->name, np->rx_done, np->tx_done_q);
+		return 0;
+	}
+
+	/* If EOP is set on the next entry, it's a new packet. Send it up. */
+	while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n",
+				   np->rx_done, desc_status);
+		if (--boguscnt < 0)
+			break;
+		if ( ! (desc_status & RxOK)) {
+			/* There was a error. */
+			if (debug > 2)
+				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
+					   desc_status);
+			np->stats.rx_errors++;
+			if (desc_status & RxFIFOErr)
+				np->stats.rx_fifo_errors++;
+		} else {
+			struct sk_buff *skb;
+			u16 pkt_len = desc_status;			/* Implicitly Truncate */
+			int entry = (desc_status >> 16) & 0x7ff;
+
+#ifndef final_version
+			if (debug > 4)
+				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
+					   ", bogus_cnt %d.\n",
+					   pkt_len, boguscnt);
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
+			if (PKT_SHOULD_COPY(pkt_len)
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single(np->pci_dev,
+						    np->rx_info[entry].mapping,
+						    pkt_len, PCI_DMA_FROMDEVICE);
+#if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
+				eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+				skb_put(skb, pkt_len);
+#else
+				memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail,
+					   pkt_len);
+#endif
+			} else {
+				char *temp;
+
+				pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+				skb = np->rx_info[entry].skb;
+				temp = skb_put(skb, pkt_len);
+				np->rx_info[entry].skb = NULL;
+				np->rx_info[entry].mapping = 0;
+			}
+#ifndef final_version				/* Remove after testing. */
+			/* You will want this info for the initial debug. */
+			if (debug > 5)
+				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
+					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
+					   "%d.%d.%d.%d.\n",
+					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
+					   skb->data[8], skb->data[9], skb->data[10],
+					   skb->data[11], skb->data[12], skb->data[13],
+					   skb->data[14], skb->data[15], skb->data[16],
+					   skb->data[17]);
+#endif
+			skb->protocol = eth_type_trans(skb, dev);
+#if defined(full_rx_status) || defined(csum_rx_status)
+			if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) {
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			}
+			/*
+			 * This feature doesn't seem to be working, at least
+			 * with the two firmware versions I have. If the GFP sees
+			 * a fragment, it either ignores it completely, or reports
+			 * "bad checksum" on it.
+			 *
+			 * Maybe I missed something -- corrections are welcome.
+			 * Until then, the printk stays. :-) -Ion
+			 */
+			else if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x00400000) {
+				skb->ip_summed = CHECKSUM_HW;
+				skb->csum = le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0xffff;
+				printk(KERN_DEBUG "%s: checksum_hw, status2 = %x\n", dev->name, np->rx_done_q[np->rx_done].status2);
+			}
+#endif
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			np->stats.rx_packets++;
+		}
+		np->cur_rx++;
+		np->rx_done_q[np->rx_done].status = 0;
+		np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);
+	}
+	writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);
+
+	/* Refill the Rx ring buffers. */
+	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+		struct sk_buff *skb;
+		int entry = np->dirty_rx % RX_RING_SIZE;
+		if (np->rx_info[entry].skb == NULL) {
+			skb = dev_alloc_skb(np->rx_buf_sz);
+			np->rx_info[entry].skb = skb;
+			if (skb == NULL)
+				break;			/* Better luck next round. */
+			np->rx_info[entry].mapping =
+				pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			skb->dev = dev;			/* Mark as being used by this device. */
+			np->rx_ring[entry].rxaddr =
+				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
+		}
+		if (entry == RX_RING_SIZE - 1)
+			np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing);
+		/* We could defer this until later... */
+		writew(entry, dev->base_addr + RxDescQIdx);
+	}
+
+	if (debug > 5
+		|| memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1))
+		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x %d.\n",
+			   np->rx_done, desc_status,
+			   memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1));
+
+	/* Restart Rx engine if stopped. */
+	return 0;
+}
+
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+	struct netdev_private *np = dev->priv;
+
+	if (intr_status & IntrLinkChange) {
+		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
+			   " %4.4x  partner %4.4x.\n", dev->name,
+			   mdio_read(dev, np->phys[0], 4),
+			   mdio_read(dev, np->phys[0], 5));
+		check_duplex(dev, 0);
+	}
+	if (intr_status & IntrStatsMax) {
+		get_stats(dev);
+	}
+	/* Came close to underrunning the Tx FIFO, increase threshold. */
+	if (intr_status & IntrTxDataLow)
+		writel(++np->tx_threshold, dev->base_addr + TxThreshold);
+	if ((intr_status &
+		 ~(IntrAbnormalSummary|IntrLinkChange|IntrStatsMax|IntrTxDataLow|1)) && debug)
+		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+			   dev->name, intr_status);
+	/* Hmmmmm, it's not clear how to recover from DMA faults. */
+	if (intr_status & IntrDMAErr)
+		np->stats.tx_fifo_errors++;
+}
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+
+	/* This adapter architecture needs no SMP locks. */
+	np->stats.tx_bytes = readl(ioaddr + 0x57010);
+	np->stats.rx_bytes = readl(ioaddr + 0x57044);
+	np->stats.tx_packets = readl(ioaddr + 0x57000);
+	np->stats.tx_aborted_errors =
+		readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
+	np->stats.tx_window_errors = readl(ioaddr + 0x57018);
+	np->stats.collisions = readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
+
+	/* The chip only need report frame silently dropped. */
+	np->stats.rx_dropped	   += readw(ioaddr + RxDMAStatus);
+	writew(0, ioaddr + RxDMAStatus);
+	np->stats.rx_crc_errors	   = readl(ioaddr + 0x5703C);
+	np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
+	np->stats.rx_length_errors = readl(ioaddr + 0x57058);
+	np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
+
+	return &np->stats;
+}
+
+/* The little-endian AUTODIN II ethernet CRC calculations.
+   A big-endian version is also available.
+   This is slow but compact code.  Do not use this routine for bulk data,
+   use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c.
+   Chips may use the upper or lower CRC bits, and may reverse and/or invert
+   them.  Select the endian-ness that results in minimal calculations.
+*/
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	u32 rx_mode;
+	struct dev_mc_list *mclist;
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;
+	} else if ((dev->mc_count > multicast_filter_limit)
+			   ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to match, or accept all multicasts. */
+		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;
+	} else if (dev->mc_count <= 15) {
+		/* Use the 16 element perfect filter. */
+		long filter_addr = ioaddr + 0x56000 + 1*16;
+		for (i = 1, mclist = dev->mc_list; mclist  &&  i <= dev->mc_count;
+			 i++, mclist = mclist->next) {
+			u16 *eaddrs = (u16 *)mclist->dmi_addr;
+			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
+		}
+		while (i++ < 16) {
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 8;
+		}
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+	} else {
+		/* Must use a multicast hash table. */
+		long filter_addr;
+		u16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter);
+		}
+		/* Clear the perfect filter list. */
+		filter_addr = ioaddr + 0x56000 + 1*16;
+		for (i = 1; i < 16; i++) {
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 8;
+		}
+		for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++)
+			writew(mc_filter[i], filter_addr);
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	}
+	writel(rx_mode, ioaddr + RxFilterMode);
+}
+
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct netdev_private *np = dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = np->phys[0] & 0x1f;
+		/* Fall Through */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (data[0] == np->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				if (value & 0x9000)	/* Autonegotiation. */
+					np->medialock = 0;
+				else {
+					np->full_duplex = (value & 0x0100) ? 1 : 0;
+					np->medialock = 1;
+				}
+				break;
+			case 4: np->advertising = value; break;
+			}
+			check_duplex(dev, 0);
+		}
+		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int netdev_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	netif_device_detach(dev);
+
+	del_timer_sync(&np->timer);
+
+	if (debug > 1) {
+		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n",
+			   dev->name, (int)readl(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+	}
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	writel(0, ioaddr + IntrEnable);
+
+	/* Stop the chip's Tx and Rx processes. */
+
+#ifdef __i386__
+	if (debug > 2) {
+		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+			   np->tx_ring_dma);
+		for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
+			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
+				   i, le32_to_cpu(np->tx_ring[i].status),
+				   le32_to_cpu(np->tx_ring[i].first_addr),
+				   le32_to_cpu(np->tx_done_q[i].status));
+		printk(KERN_DEBUG "  Rx ring at %8.8x -> %p:\n",
+			   np->rx_ring_dma, np->rx_done_q);
+		if (np->rx_done_q)
+			for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {
+				printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",
+					   i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
+		}
+	}
+#endif /* __i386__ debugging only */
+
+	free_irq(dev->irq, dev);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (np->rx_info[i].skb != NULL) {
+			pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(np->rx_info[i].skb);
+		}
+		np->rx_info[i].skb = NULL;
+		np->rx_info[i].mapping = 0;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		struct sk_buff *skb = np->tx_info[i].skb;
+#ifdef ZEROCOPY
+		int j;
+#endif /* ZEROCOPY */
+		if (skb != NULL) {
+			pci_unmap_single(np->pci_dev,
+					 np->tx_info[i].first_mapping,
+					 skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+			np->tx_info[i].first_mapping = 0;
+			dev_kfree_skb(skb);
+			np->tx_info[i].skb = NULL;
+#ifdef ZEROCOPY
+			for (j = 0; j < 6; j++)
+				if (np->tx_info[i].frag_mapping[j]) {
+					pci_unmap_single(np->pci_dev,
+									 np->tx_info[i].frag_mapping[j],
+									 skb_shinfo(skb)->frags[j].size,
+									 PCI_DMA_TODEVICE);
+					np->tx_info[i].frag_mapping[j] = 0;
+				} else
+					break;
+#endif /* ZEROCOPY */
+		}
+	}
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+static void __devexit starfire_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct netdev_private *np;
+	
+	if (!dev)
+		BUG();
+
+	np = dev->priv;
+
+	unregister_netdev(dev);
+	iounmap((char *)dev->base_addr);
+
+	release_mem_region(pci_resource_start (pdev, 0),
+					   pci_resource_len (pdev, 0));
+
+	if (np->tx_done_q)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->tx_done_q, np->tx_done_q_dma);
+	if (np->rx_done_q)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->rx_done_q, np->rx_done_q_dma);
+	if (np->tx_ring)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->tx_ring, np->tx_ring_dma);
+	if (np->rx_ring)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->rx_ring, np->rx_ring_dma);
+
+	kfree(dev);
+}
+
+
+static struct pci_driver starfire_driver = {
+	name:		"starfire",
+	probe:		starfire_init_one,
+	remove:		starfire_remove_one,
+	id_table:	starfire_pci_tbl,
+};
+
+
+static int __init starfire_init (void)
+{
+	return pci_module_init (&starfire_driver);
+}
+
+
+static void __exit starfire_cleanup (void)
+{
+	pci_unregister_driver (&starfire_driver);
+}
+
+
+module_init(starfire_init);
+module_exit(starfire_cleanup);
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c"
+ *  simple-compile-command: "gcc -DMODULE -O6 -c starfire.c"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN linux-2.2.19-pre9/drivers/net/starfire_firmware.pl linux/drivers/net/starfire_firmware.pl
--- linux-2.2.19-pre9/drivers/net/starfire_firmware.pl	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/starfire_firmware.pl	Mon Dec  3 21:01:22 2001
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+# This script can be used to generate a new starfire_firmware.h
+# from GFP_RX.DAT and GFP_TX.DAT, files included with the DDK
+# and also with the Novell drivers.
+
+open FW, "GFP_RX.DAT" || die;
+open FWH, ">starfire_firmware.h" || die;
+
+printf(FWH "static u32 firmware_rx[] = {\n");
+$counter = 0;
+while ($foo = <FW>) {
+  chomp;
+  printf(FWH "  0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4));
+  $counter++;
+}
+
+close FW;
+open FW, "GFP_TX.DAT" || die;
+
+printf(FWH "};\t/* %d Rx instructions */\n#define FIRMWARE_RX_SIZE %d\n\nstatic u32 firmware_tx[] = {\n", $counter, $counter);
+$counter = 0;
+while ($foo = <FW>) {
+  chomp;
+  printf(FWH "  0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4));
+  $counter++;
+}
+
+close FW;
+printf(FWH "};\t/* %d Tx instructions */\n#define FIRMWARE_TX_SIZE %d\n", $counter, $counter);
+close(FWH);
diff -urN linux-2.2.19-pre9/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- linux-2.2.19-pre9/drivers/scsi/aic7xxx/aic7xxx.seq	Mon Dec  3 21:00:54 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Mon Dec  3 21:01:23 2001
@@ -291,11 +291,7 @@
 
 	mov	A, LASTPHASE;
 
-	if ((p->features & AHC_ULTRA2) != 0) {
-		test	A, ~P_DATAIN	jz u2_p_data;
-	} else {
-		test	A, ~P_DATAIN	jz p_data;
-	}
+	test	A, ~P_DATAIN	jz p_data;
 	cmp	A,P_COMMAND	je p_command;
 	cmp	A,P_MESGOUT	je p_mesgout;
 	cmp	A,P_STATUS	je p_status;
@@ -336,73 +332,130 @@
 	/* clear target specific flags */
 	clr	SEQ_FLAGS ret;
 
- 	if ((p->features & AHC_ULTRA2) != 0) {
-
-
 
-u2_data_phase_reinit:
+data_phase_reinit:
 /*
  * If we re-enter the data phase after going through another phase, the
  * STCNT may have been cleared, so restore it from the residual field.
  * On Ultra2, we have to put it into the HCNT field because we have to
  * drop the data down into the shadow layer via the preload ability.
  */
+ 	if ((p->features & AHC_ULTRA2) != 0) {
 		bmov	HADDR, SHADDR, 4;
 		bmov    HCNT, SCB_RESID_DCNT, 3;
-		jmp	u2_data_phase_loop;
-u2_p_data:
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		bmov    STCNT, SCB_RESID_DCNT, 3;
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
+		mvi	DINDEX, STCNT;
+		mvi	SCB_RESID_DCNT	call bcopy_3;
+	}
+	jmp	data_phase_loop;
+p_data:
+ 	if ((p->features & AHC_ULTRA2) != 0) {
 		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
-		test	LASTPHASE, IOI jnz . + 2;
-		or	DMAPARAMS, DIRECTION;
-		call	assert;		/*
-					 * Ensure entering a data
-					 * phase is okay - seen identify, etc.
-					 */
+	} else {
+		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+	}
+	test	LASTPHASE, IOI jnz . + 2;
+	or	DMAPARAMS, DIRECTION;
+	call	assert;		/*
+				 * Ensure entering a data
+				 * phase is okay - seen identify, etc.
+				 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
 		mvi	CCSGADDR, CCSGADDR_MAX;
-		test	SEQ_FLAGS, DPHASE	jnz u2_data_phase_reinit;
-		or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
-		/*
-		 * Initialize the DMA address and counter from the SCB.
-		 * Also set SG_COUNT and SG_NEXT in memory since we cannot
-		 * modify the values in the SCB itself until we see a
-		 * save data pointers message.
-		 */
+	}
+
+	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+	or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
+	/*
+	 * Initialize the DMA address and counter from the SCB.
+	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
+	 * modify the values in the SCB itself until we see a
+	 * save data pointers message.
+	 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
 		bmov	HADDR, SCB_DATAPTR, 7;
 		bmov    SG_COUNT, SCB_SGCOUNT, 5;
-u2_data_phase_loop:
-		/* Guard against overruns */
-		test	SG_COUNT, 0xff jnz u2_data_phase_inbounds;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCB_DATAPTR	call bcopy_7;
+		call	set_stcnt_from_hcnt;
+		mvi	DINDEX, SG_COUNT;
+		mvi	SCB_SGCOUNT	call bcopy_5;
+	}
+data_phase_loop:
+	/* Guard against overruns */
+	test	SG_COUNT, 0xff jnz data_phase_inbounds;
 /*
  * Turn on 'Bit Bucket' mode, set the transfer count to
  * 16meg and let the target run until it changes phase.
  * When the transfer completes, notify the host that we
  * had an overrun.
  */
-		or	SXFRCTL1,BITBUCKET;
-		and	DMAPARAMS, DIRECTION;
+	or	SXFRCTL1,BITBUCKET;
+	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
+	if ((p->features & AHC_ULTRA2) != 0) {
 		bmov	HCNT, ALLONES, 3;
-u2_data_phase_inbounds:
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		bmov	STCNT, ALLONES, 3;
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
+		mvi	STCNT[0], 0xFF;
+		mvi	STCNT[1], 0xFF;
+		mvi	STCNT[2], 0xFF;
+	}
+
+data_phase_inbounds:
 /* If we are the last SG block, tell the hardware. */
+	if ((p->features & AHC_ULTRA2) != 0) {
 		shl	A, 2, SG_COUNT;
-		cmp	SG_COUNT,0x01 jne u2_data_phase_lastseg;
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
 		or	A, LAST_SEG;
-u2_data_phase_lastseg:
+	} else {
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		and	DMAPARAMS, ~WIDEODD;
+	}
+data_phase_wideodd:
+	if ((p->features & AHC_ULTRA2) != 0) {	
 		mov	SG_CACHEPTR, A;
 		mov	DFCNTRL, DMAPARAMS; /* start the operation */
-		test	SXFRCTL1, BITBUCKET jnz u2_data_phase_overrun;
+		test	SXFRCTL1, BITBUCKET jnz data_phase_overrun;
 u2_preload_wait:
 		test	SSTAT1, PHASEMIS jnz u2_phasemis;
 		test	DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
+	} else {
+		mov	DMAPARAMS  call dma;
+data_phase_dma_done:
+/* Go tell the host about any overruns */
+		test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+
+/* Exit if we had an underrun.  dma clears SINDEX in this case. */
+		test	SINDEX,0xff	jz data_phase_finish;
+	}
 /*
  * Advance the scatter-gather pointers 
  */
-u2_sg_advance:
+sg_advance:
+	if ((p->features & AHC_ULTRA2) != 0) {
 		cmp	SG_COUNT, 0x01	je u2_data_phase_finish;
+	} else {
+		dec	SG_COUNT;
+		test	SG_COUNT, 0xff	jz data_phase_finish;
+	}
+
+	if ((p->features & AHC_CMD_CHAN) != 0) {
 
 		/*
 		 * Do we have any prefetch left???
 		 */
-		cmp	CCSGADDR, CCSGADDR_MAX jne u2_prefetch_avail;
+		cmp	CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
 
 		/*
 		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
@@ -418,18 +471,48 @@
 		and	CCSGCTL, ~CCSGEN;
 		test	CCSGCTL, CCSGEN jnz .;
 		mvi	CCSGCTL, CCSGRESET;
-u2_prefetch_avail:
-		/* Test for a phasemis before we drop the stuff into the
-		 * host regs.  We might have actually missed the phasemis
-		 * while doing the dma of the sg segs.
-		 */
-		test	SSTAT1, PHASEMIS jnz u2_phasemis;
-		dec	SG_COUNT;	      /* one less segment to go */
-		bmov 	HADDR, CCSGRAM, 8;    /* drop the address in place */
-		clr	A;		      /* Advance the SG pointer by */
-		add	SG_NEXT[0],SG_SIZEOF; /* adding SG_SIZEOF to addr0 */
-		adc	SG_NEXT[1],A;         /* and adding any carry to */
-		jmp	u2_data_phase_loop;   /* addr1 */
+prefetch_avail:
+		bmov 	HADDR, CCSGRAM, 8;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		} else {
+			dec	SG_COUNT;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SG_NEXT	call bcopy_4;
+
+		mvi	HCNT[0],SG_SIZEOF;
+		clr	HCNT[1];
+		clr	HCNT[2];
+
+		or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+		call	dma_finish;
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count.
+ * This assumes that the SG segments are of the form:
+ * struct ahc_dma_seg {
+ *	u_int32_t	addr;	four bytes, little-endian order
+ *	u_int32_t	len;	four bytes, little endian order
+ * };
+ */
+ 		mvi	DINDEX, HADDR;
+		call	dfdat_in_7;
+		call	set_stcnt_from_hcnt;
+	}
+/* Advance the SG pointer */
+	clr	A;		/* add sizeof(struct scatter) */
+	add	SG_NEXT[0],SG_SIZEOF;
+	adc	SG_NEXT[1],A;
+
+	if ((p->features & AHC_ULTRA2) != 0) {
+		jmp	data_phase_loop;
+	} else {
+		test    SSTAT1, REQINIT jz .;
+		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	}
 
 
 /*
@@ -438,23 +521,24 @@
  * we'll get a phasemis if we do finish, all we really need to do is wait
  * for a phasemis then check if we did actually complete all the segments.
  */
+	if ((p->features & AHC_ULTRA2) != 0) {
 u2_data_phase_finish:
 		test	SSTAT1, PHASEMIS jnz u2_phasemis;
 		test	SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
 		clr	SG_COUNT;
 		test	SSTAT1, REQINIT	jz .;
-		test	SSTAT1, PHASEMIS jz u2_data_phase_loop;
+		test	SSTAT1, PHASEMIS jz data_phase_loop;
 u2_phasemis:
 		call	ultra2_dmafinish;
-		test	SG_CACHEPTR, LAST_SEG_DONE jnz u2_phasemis_end;
+		test	SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish;
 		test	SSTAT2, SHVALID jnz u2_fixup_residual;
 		mvi	INTSTAT, SEQ_SG_FIXUP;
-		jmp	u2_phasemis_end;
+		jmp	data_phase_finish;
 u2_fixup_residual:
 		shr	ARG_1, 2, SG_CACHEPTR;
 u2_phasemis_loop:
 		and	A, 0x3f, SG_COUNT;
-		cmp	ARG_1, A je u2_phasemis_end;
+		cmp	ARG_1, A je data_phase_finish;
 /*
  * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
  */
@@ -463,11 +547,44 @@
 		adc	SG_NEXT[1], 0xff;
 		inc	SG_COUNT;
 		jmp	u2_phasemis_loop;
-u2_phasemis_end:
-		bmov	SCB_RESID_DCNT, STCNT, 3;
+	}
+
+data_phase_finish:
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_RESID_DCNT, STCNT, 3;
 		mov	SCB_RESID_SGCNT, SG_COUNT;
-		or	SXFRCTL0, CLRSTCNT|CLRCHN;
-		jmp	ITloop;
+		if ((p->features & AHC_ULTRA2) != 0) {
+			or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		}
+	} else {
+		mov	SCB_RESID_DCNT[0],STCNT[0];
+		mov	SCB_RESID_DCNT[1],STCNT[1];
+		mov	SCB_RESID_DCNT[2],STCNT[2];
+		mov	SCB_RESID_SGCNT, SG_COUNT;
+	}
+
+	jmp	ITloop;
+
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+	if ((p->features & AHC_ULTRA2) != 0) {
+/*
+ * Wait for the target to quit transferring data on the SCSI bus
+ */
+ 		test	SSTAT1, PHASEMIS jz .;
+		call	ultra2_dmafinish;
+	}
+	and	SXFRCTL1, ~BITBUCKET;
+	mvi	INTSTAT,DATA_OVERRUN;
+	jmp	ITloop;
+
 
 
 
@@ -478,6 +595,7 @@
  * brought into the data phase again (or are still in it after our last
  * segment) that we will properly signal an overrun to the kernel.
  */
+	if ((p->features & AHC_ULTRA2) != 0) {
 ultra2_dmafinish:
 		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
 		and	DFCNTRL, ~SCSIEN;
@@ -515,196 +633,6 @@
 		and     DFCNTRL, ~(HDMAEN|SCSIEN);
 		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
 		ret;
-
-u2_data_phase_overrun:
-/*
- * Wait for the target to quit transferring data on the SCSI bus
- */
- 		test	SSTAT1, PHASEMIS jz .;
-		call	ultra2_dmafinish;
-/*
- * Turn off BITBUCKET mode and notify the host
- */
-		and	SXFRCTL1, ~BITBUCKET;
-		mvi	INTSTAT,DATA_OVERRUN;
-		jmp	ITloop;
-
-
-
-	} else {  /* NOT Ultra2 */
-
-
-
-data_phase_reinit:
-/*
- * If we re-enter the data phase after going through another phase, the
- * STCNT may have been cleared, so restore it from the residual field.
- */
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov    STCNT, SCB_RESID_DCNT, 3;
-		} else {
-			mvi	DINDEX, STCNT;
-			mvi	SCB_RESID_DCNT	call bcopy_3;
-		}
-		jmp	data_phase_loop;
-p_data:
-		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-		test	LASTPHASE, IOI jnz . + 2;
-		or	DMAPARAMS, DIRECTION;
-		call	assert;		/*
-					 * Ensure entering a data
-					 * phase is okay - seen identify, etc.
-					 */
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			mvi	CCSGADDR, CCSGADDR_MAX;
-		}
-		test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
-		or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
-		/*
-		 * Initialize the DMA address and counter from the SCB.
-		 * Also set SG_COUNT and SG_NEXT in memory since we cannot
-		 * modify the values in the SCB itself until we see a
-		 * save data pointers message.
-		 */
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov	HADDR, SCB_DATAPTR, 7;
-			bmov    STCNT, HCNT, 3;
-			bmov    SG_COUNT, SCB_SGCOUNT, 5;
-		} else {
-			mvi	DINDEX, HADDR;
-			mvi	SCB_DATAPTR	call bcopy_7;
-			call	set_stcnt_from_hcnt;
-			mvi	DINDEX, SG_COUNT;
-			mvi	SCB_SGCOUNT	call bcopy_5;
-		}
-data_phase_loop:
-		/* Guard against overruns */
-		test	SG_COUNT, 0xff jnz data_phase_inbounds;
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
-		or	SXFRCTL1,BITBUCKET;
-		and	DMAPARAMS, ~(HDMAEN|SDMAEN);
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov	STCNT, ALLONES, 3;
-		} else {
-			mvi	STCNT[0], 0xFF;
-			mvi	STCNT[1], 0xFF;
-			mvi	STCNT[2], 0xFF;
-		}
-
-data_phase_inbounds:
-/* If we are the last SG block, tell the hardware. */
-		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
-		and	DMAPARAMS, ~WIDEODD;
-data_phase_wideodd:
-		mov	DMAPARAMS  call dma;
-data_phase_dma_done:
-/* Go tell the host about any overruns */
-		test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
-
-/* Exit if we had an underrun.  dma clears SINDEX in this case. */
-		test	SINDEX,0xff	jz data_phase_finish;
-/*
- * Advance the scatter-gather pointers if needed 
- */
-sg_advance:
-		cmp	SG_COUNT, 0x01	je data_phase_finish; /* Are we done? */
-		dec	SG_COUNT;	/* one less segment to go */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			/*
-			 * Do we have any prefetch left???
-			 */
-			cmp	CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
-
-			/*
-			 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
-			 */
-			add	A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
-			mvi	A, CCSGADDR_MAX;
-			jc	. + 2;
-			shl	A, 3, SG_COUNT;
-			mov	CCHCNT, A;
-			bmov	CCHADDR, SG_NEXT, 4;
-			mvi	CCSGCTL, CCSGEN|CCSGRESET;
-			test	CCSGCTL, CCSGDONE jz .;
-			and	CCSGCTL, ~CCSGEN;
-			test	CCSGCTL, CCSGEN jnz .;
-			mvi	CCSGCTL, CCSGRESET;
-prefetch_avail:
-			bmov 	HADDR, CCSGRAM, 8;
-			bmov    STCNT, HCNT, 3;
-		} else {
-			mvi	DINDEX, HADDR;
-			mvi	SG_NEXT	call bcopy_4;
-
-			mvi	HCNT[0],SG_SIZEOF;
-			clr	HCNT[1];
-			clr	HCNT[2];
-
-			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
-
-			call	dma_finish;
-
-/*
- * Copy data from FIFO into SCB data pointer and data count.
- * This assumes that the SG segments are of the form:
- * struct ahc_dma_seg {
- *	u_int32_t	addr;	four bytes, little-endian order
- *	u_int32_t	len;	four bytes, little endian order
- * };
- */
-			mvi	HADDR	call dfdat_in_7;
-			call	set_stcnt_from_hcnt;
-		}
-/* Advance the SG pointer */
-		clr	A;		/* add sizeof(struct scatter) */
-		add	SG_NEXT[0],SG_SIZEOF;
-		adc	SG_NEXT[1],A;
-
-		test    SSTAT1, REQINIT jz .;
-		test	SSTAT1,PHASEMIS	jz data_phase_loop;
-
-data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
- * were transferred on the SCSI (as opposed to the host) bus.
- */
-		clr	SG_COUNT;
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov    SCB_RESID_DCNT, STCNT, 3;
-			mov	SCB_RESID_SGCNT, SG_COUNT;
-		} else {
-			mov	SCB_RESID_DCNT[0],STCNT[0];
-			mov	SCB_RESID_DCNT[1],STCNT[1];
-			mov	SCB_RESID_DCNT[2],STCNT[2];
-			mov	SCB_RESID_SGCNT, SG_COUNT;
-		}
-
-		jmp	ITloop;
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
-		and	SXFRCTL1, ~BITBUCKET;
-		mvi	INTSTAT,DATA_OVERRUN;
-		jmp	ITloop;
-
-
-
 	}
 
 /*
@@ -1437,21 +1365,25 @@
 			bmov	CCSCBRAM, SCB_CONTROL, 32;
 			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
 			test	CCSCBCTL, CCSCBDONE jz .;
-		} else if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
-                        mvi     CCSCBCTL, CCARREN|CCSCBRESET;
-			cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
-                        mvi     CCHCNT, 32;
-			mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
-			cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
-		} else {
-			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
-			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+		}
+		if ((p->features & AHC_ULTRA2) != 0) {
+			if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
+				mvi     CCSCBCTL, CCARREN|CCSCBRESET;
+				cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
+                        	mvi     CCHCNT, 32;
+				mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
+				cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+			} else {
+				mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+				cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+			}
 		}
 dma_scb_finish:
 		clr	CCSCBCTL;
 		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
 		ret;
-	} else {
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
 		mvi	DINDEX, HADDR;
 		mvi	HSCB_ADDR call set_32byte_addr;
 		mvi	HCNT[0], 32;
diff -urN linux-2.2.19-pre9/drivers/scsi/aic7xxx/aic7xxx_seq.c linux/drivers/scsi/aic7xxx/aic7xxx_seq.c
--- linux-2.2.19-pre9/drivers/scsi/aic7xxx/aic7xxx_seq.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.c	Mon Dec  3 21:01:23 2001
@@ -7,7 +7,7 @@
 	0x12, 0x6a, 0x00, 0x00,
 	0xff, 0x6a, 0xd6, 0x09,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x00, 0x65, 0xcc, 0x58,
+	0x00, 0x65, 0xca, 0x58,
 	0xf7, 0x01, 0x02, 0x08,
 	0xff, 0x4e, 0xc8, 0x08,
 	0xbf, 0x60, 0xc0, 0x08,
@@ -25,12 +25,12 @@
 	0x00, 0x4d, 0x10, 0x70,
 	0x01, 0x4e, 0x9c, 0x18,
 	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0xce, 0x5c,
+	0x00, 0x6a, 0x86, 0x5c,
 	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0xb8, 0x5b,
+	0x02, 0x6a, 0x70, 0x5b,
 	0xff, 0x52, 0x20, 0x09,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0x2e, 0x5c,
+	0x00, 0x52, 0xe6, 0x5b,
 	0x03, 0xb0, 0x52, 0x31,
 	0xff, 0xb0, 0x52, 0x09,
 	0xff, 0xb1, 0x54, 0x09,
@@ -87,21 +87,20 @@
 	0x08, 0x6a, 0x66, 0x58,
 	0x80, 0x6a, 0x68, 0x00,
 	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0x02, 0x5c,
+	0x00, 0x65, 0xba, 0x5b,
 	0xff, 0x3d, 0xc8, 0x08,
-	0xbf, 0x64, 0xde, 0x78,
-	0xbf, 0x64, 0x88, 0x79,
-	0x80, 0x64, 0x10, 0x72,
-	0xa0, 0x64, 0x40, 0x72,
-	0xc0, 0x64, 0x38, 0x72,
-	0xe0, 0x64, 0x80, 0x72,
+	0xbf, 0x64, 0xe2, 0x78,
+	0x80, 0x64, 0xc8, 0x71,
+	0xa0, 0x64, 0xf8, 0x71,
+	0xc0, 0x64, 0xf0, 0x71,
+	0xe0, 0x64, 0x38, 0x72,
 	0x01, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
 	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0xcc, 0x58,
+	0x00, 0x65, 0xca, 0x58,
 	0xff, 0x06, 0xd4, 0x08,
 	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0xc6, 0x78,
+	0x09, 0x0c, 0xc4, 0x78,
 	0x08, 0x0c, 0x0c, 0x68,
 	0x01, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0x26, 0x09,
@@ -112,411 +111,376 @@
 	0xff, 0x6a, 0x6c, 0x0c,
 	0x04, 0x14, 0x10, 0x31,
 	0x03, 0xa9, 0x18, 0x31,
-	0x00, 0x65, 0xf0, 0x40,
-	0xa8, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0xe4, 0x68,
-	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x72, 0x5b,
-	0x80, 0x6a, 0xd4, 0x01,
-	0x10, 0x36, 0xd8, 0x68,
-	0x10, 0x36, 0x6c, 0x00,
-	0x07, 0xac, 0x10, 0x31,
-	0x05, 0xa3, 0x70, 0x30,
-	0xff, 0x38, 0xf8, 0x68,
-	0x80, 0x02, 0x04, 0x00,
-	0x04, 0x35, 0x6a, 0x08,
-	0x03, 0x69, 0x18, 0x31,
-	0x22, 0x38, 0xc8, 0x28,
-	0x01, 0x38, 0xfe, 0x60,
-	0x02, 0x64, 0xc8, 0x00,
-	0xff, 0x64, 0xf8, 0x09,
-	0xff, 0x35, 0x26, 0x09,
-	0x80, 0x02, 0x76, 0x69,
-	0x10, 0x0c, 0x3a, 0x69,
-	0x80, 0x94, 0x04, 0x79,
-	0x01, 0x38, 0x30, 0x71,
-	0x80, 0xea, 0x22, 0x61,
-	0xef, 0x38, 0xc8, 0x18,
-	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0x14, 0x49,
-	0x33, 0x38, 0xc8, 0x28,
-	0xff, 0x64, 0xd0, 0x09,
-	0x04, 0x39, 0xc0, 0x31,
-	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x1a, 0x79,
-	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0x1e, 0x69,
-	0x01, 0x6a, 0xd6, 0x01,
-	0x10, 0x0c, 0x3a, 0x69,
-	0xff, 0x38, 0x70, 0x18,
-	0x08, 0xe9, 0x10, 0x31,
-	0xff, 0x6a, 0xc8, 0x08,
-	0x08, 0x39, 0x72, 0x18,
-	0x00, 0x3a, 0x74, 0x20,
-	0x00, 0x65, 0xf0, 0x40,
-	0x10, 0x0c, 0x3a, 0x69,
-	0x01, 0xfc, 0x30, 0x79,
-	0xff, 0x6a, 0x70, 0x08,
-	0x01, 0x0c, 0x36, 0x79,
-	0x10, 0x0c, 0xf0, 0x78,
-	0x00, 0x65, 0x5c, 0x59,
-	0x01, 0xfc, 0x54, 0x69,
-	0x40, 0x0d, 0x44, 0x69,
-	0xb1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x54, 0x41,
-	0x2e, 0xfc, 0xa2, 0x28,
-	0x3f, 0x38, 0xc8, 0x08,
-	0x00, 0x51, 0x54, 0x71,
-	0xff, 0x6a, 0xc8, 0x08,
-	0xf8, 0x39, 0x72, 0x18,
-	0xff, 0x3a, 0x74, 0x20,
-	0x01, 0x38, 0x70, 0x18,
-	0x00, 0x65, 0x46, 0x41,
-	0x03, 0x08, 0x52, 0x31,
-	0xff, 0x38, 0x50, 0x09,
-	0x12, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x04, 0x93, 0x70, 0x69,
-	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x60, 0x69,
-	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0x64, 0x79,
-	0x01, 0x94, 0x64, 0x79,
-	0x01, 0x94, 0x64, 0x79,
-	0x01, 0x94, 0x64, 0x79,
-	0x01, 0x94, 0x64, 0x79,
-	0x10, 0x94, 0x6e, 0x69,
-	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0x72, 0x69,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x10, 0x0c, 0x76, 0x79,
-	0x00, 0x65, 0x5c, 0x59,
-	0x7f, 0x02, 0x04, 0x08,
-	0xe1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
 	0x03, 0xa9, 0x10, 0x30,
 	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0x18, 0x5c,
-	0x00, 0x65, 0xa6, 0x41,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x02, 0x41,
+	0xa8, 0x6a, 0x6a, 0x00,
 	0x79, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0x8e, 0x69,
+	0x40, 0x3d, 0xea, 0x68,
 	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x72, 0x5b,
+	0x00, 0x65, 0x2a, 0x5b,
 	0x80, 0x6a, 0xd4, 0x01,
-	0x10, 0x36, 0x80, 0x69,
+	0x10, 0x36, 0xd6, 0x68,
 	0x10, 0x36, 0x6c, 0x00,
 	0x07, 0xac, 0x10, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
 	0x05, 0xa3, 0x70, 0x30,
+	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0x10, 0x5c,
-	0x00, 0x65, 0x0a, 0x5c,
+	0xac, 0x6a, 0xc8, 0x5b,
+	0x00, 0x65, 0xc2, 0x5b,
 	0x38, 0x6a, 0xcc, 0x00,
-	0xa3, 0x6a, 0x14, 0x5c,
-	0xff, 0x38, 0xb4, 0x69,
+	0xa3, 0x6a, 0xcc, 0x5b,
+	0xff, 0x38, 0x12, 0x69,
 	0x80, 0x02, 0x04, 0x00,
 	0xe7, 0x35, 0x6a, 0x08,
+	0x03, 0x69, 0x18, 0x31,
 	0x03, 0x69, 0x10, 0x30,
 	0xff, 0x6a, 0x10, 0x00,
 	0xff, 0x6a, 0x12, 0x00,
 	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0xb8, 0x61,
+	0x22, 0x38, 0xc8, 0x28,
+	0x01, 0x38, 0x1c, 0x61,
+	0x02, 0x64, 0xc8, 0x00,
+	0x01, 0x38, 0x1c, 0x61,
 	0xbf, 0x35, 0x6a, 0x08,
-	0x00, 0x35, 0x52, 0x5b,
-	0x80, 0x02, 0x0a, 0x6a,
-	0xff, 0x65, 0xfa, 0x79,
-	0x01, 0x38, 0xfa, 0x71,
+	0xff, 0x64, 0xf8, 0x09,
+	0xff, 0x35, 0x26, 0x09,
+	0x80, 0x02, 0xa4, 0x69,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x80, 0x94, 0x22, 0x79,
+	0x00, 0x35, 0x0a, 0x5b,
+	0x80, 0x02, 0xa4, 0x69,
+	0xff, 0x65, 0x94, 0x79,
+	0x01, 0x38, 0x70, 0x71,
 	0xff, 0x38, 0x70, 0x18,
-	0x80, 0xea, 0xda, 0x61,
+	0xff, 0x38, 0x94, 0x79,
+	0x80, 0xea, 0x4a, 0x61,
 	0xef, 0x38, 0xc8, 0x18,
 	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0xcc, 0x49,
+	0x00, 0x65, 0x3c, 0x49,
 	0x33, 0x38, 0xc8, 0x28,
 	0xff, 0x64, 0xd0, 0x09,
 	0x04, 0x39, 0xc0, 0x31,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xd2, 0x79,
+	0x80, 0xeb, 0x42, 0x79,
 	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0xd6, 0x69,
+	0x08, 0xeb, 0x46, 0x69,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x08, 0xe9, 0x10, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
+	0xff, 0x38, 0x70, 0x18,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0x16, 0x5c,
+	0x39, 0x6a, 0xce, 0x5b,
 	0x08, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xc0, 0x5c,
-	0x88, 0x6a, 0xb2, 0x5c,
-	0x00, 0x65, 0x0a, 0x5c,
+	0x00, 0x65, 0x78, 0x5c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x00, 0x65, 0x6a, 0x5c,
+	0x00, 0x65, 0xc2, 0x5b,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x08, 0x39, 0x72, 0x18,
 	0x00, 0x3a, 0x74, 0x20,
-	0x01, 0x0c, 0xf6, 0x79,
-	0x10, 0x0c, 0xa6, 0x79,
+	0x00, 0x65, 0x02, 0x41,
+	0x01, 0x0c, 0x6c, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x01, 0xfc, 0x70, 0x79,
 	0xff, 0x6a, 0x70, 0x08,
+	0x01, 0x0c, 0x76, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x00, 0x65, 0xae, 0x59,
+	0x01, 0xfc, 0x94, 0x69,
+	0x40, 0x0d, 0x84, 0x69,
+	0xb1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x94, 0x41,
+	0x2e, 0xfc, 0xa2, 0x28,
+	0x3f, 0x38, 0xc8, 0x08,
+	0x00, 0x51, 0x94, 0x71,
+	0xff, 0x6a, 0xc8, 0x08,
+	0xf8, 0x39, 0x72, 0x18,
+	0xff, 0x3a, 0x74, 0x20,
+	0x01, 0x38, 0x70, 0x18,
+	0x00, 0x65, 0x86, 0x41,
 	0x03, 0x08, 0x52, 0x31,
 	0xff, 0x38, 0x50, 0x09,
+	0x12, 0x01, 0x02, 0x00,
 	0xff, 0x08, 0x52, 0x09,
 	0xff, 0x09, 0x54, 0x09,
 	0xff, 0x0a, 0x56, 0x09,
 	0xff, 0x38, 0x50, 0x09,
 	0x00, 0x65, 0xaa, 0x40,
+	0x10, 0x0c, 0xa4, 0x79,
+	0x00, 0x65, 0xae, 0x59,
 	0x7f, 0x02, 0x04, 0x08,
 	0xe1, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x72, 0x5b,
+	0x04, 0x93, 0xc2, 0x69,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0xb2, 0x69,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x10, 0x94, 0xc0, 0x69,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xc4, 0x69,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x2a, 0x5b,
 	0x05, 0xb4, 0x10, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0x14, 0x5c,
+	0xb4, 0x6a, 0xcc, 0x5b,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0x0a, 0x5c,
-	0x3d, 0x6a, 0x52, 0x5b,
+	0x00, 0x65, 0xc2, 0x5b,
+	0x3d, 0x6a, 0x0a, 0x5b,
 	0xac, 0x6a, 0x26, 0x01,
-	0x04, 0x0b, 0x26, 0x6a,
-	0x04, 0x0b, 0x2c, 0x6a,
-	0x10, 0x0c, 0x28, 0x7a,
-	0x02, 0x03, 0x30, 0x7a,
-	0x11, 0x0c, 0x2c, 0x7a,
+	0x04, 0x0b, 0xde, 0x69,
+	0x04, 0x0b, 0xe4, 0x69,
+	0x10, 0x0c, 0xe0, 0x79,
+	0x02, 0x03, 0xe8, 0x79,
+	0x11, 0x0c, 0xe4, 0x79,
 	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0x32, 0x6a,
+	0x28, 0x93, 0xea, 0x69,
 	0x12, 0x01, 0x02, 0x00,
 	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x72, 0x5b,
+	0x00, 0x65, 0x2a, 0x5b,
 	0xff, 0x06, 0x44, 0x09,
 	0x00, 0x65, 0xaa, 0x40,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x64, 0x62,
+	0x80, 0x65, 0x1c, 0x62,
 	0x0f, 0xa1, 0xca, 0x08,
 	0x07, 0xa1, 0xca, 0x08,
 	0x40, 0xa0, 0xc8, 0x08,
 	0x00, 0x65, 0xca, 0x00,
 	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0x54, 0x7a,
+	0x80, 0xa0, 0x0c, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x66, 0x42,
-	0x20, 0xa0, 0x6c, 0x7a,
+	0x00, 0x65, 0x1e, 0x42,
+	0x20, 0xa0, 0x24, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x02, 0x5c,
-	0xa0, 0x3d, 0x74, 0x62,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
 	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0x02, 0x5c,
-	0xa0, 0x3d, 0x74, 0x62,
-	0x00, 0xb9, 0x6c, 0x42,
-	0xff, 0x65, 0x6c, 0x62,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
+	0x00, 0xb9, 0x24, 0x42,
+	0xff, 0x65, 0x24, 0x62,
 	0xa1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x74, 0x72,
+	0x10, 0x51, 0x2c, 0x72,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x02, 0x5c,
-	0xa0, 0x3d, 0x3e, 0x72,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0xf6, 0x71,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x7c, 0x62,
+	0x80, 0x34, 0x34, 0x62,
 	0x7f, 0xa0, 0x40, 0x09,
 	0x08, 0x6a, 0x68, 0x00,
 	0x00, 0x65, 0xaa, 0x40,
-	0x64, 0x6a, 0x48, 0x5b,
-	0x80, 0x64, 0xf2, 0x6a,
-	0x04, 0x64, 0xd4, 0x72,
-	0x02, 0x64, 0xda, 0x72,
-	0x00, 0x6a, 0x9c, 0x72,
-	0x03, 0x64, 0xee, 0x72,
-	0x01, 0x64, 0xd0, 0x72,
-	0x07, 0x64, 0x30, 0x73,
-	0x08, 0x64, 0x98, 0x72,
-	0x23, 0x64, 0x34, 0x73,
+	0x64, 0x6a, 0x00, 0x5b,
+	0x80, 0x64, 0xaa, 0x6a,
+	0x04, 0x64, 0x8c, 0x72,
+	0x02, 0x64, 0x92, 0x72,
+	0x00, 0x6a, 0x54, 0x72,
+	0x03, 0x64, 0xa6, 0x72,
+	0x01, 0x64, 0x88, 0x72,
+	0x07, 0x64, 0xe8, 0x72,
+	0x08, 0x64, 0x50, 0x72,
+	0x23, 0x64, 0xec, 0x72,
 	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0x3a, 0x5b,
+	0x07, 0x6a, 0xf2, 0x5a,
 	0xff, 0x06, 0xd4, 0x08,
 	0x00, 0x65, 0xaa, 0x40,
-	0xff, 0xa8, 0xa0, 0x6a,
-	0xff, 0xa2, 0xb8, 0x7a,
+	0xff, 0xa8, 0x58, 0x6a,
+	0xff, 0xa2, 0x70, 0x7a,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x2e, 0x5c,
-	0xff, 0xa2, 0xb8, 0x7a,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0xa2, 0x70, 0x7a,
 	0x71, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0xb8, 0x62,
+	0x40, 0x51, 0x70, 0x62,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x2e, 0x5c,
+	0x00, 0xb9, 0xe6, 0x5b,
 	0xff, 0x3e, 0x74, 0x09,
 	0xff, 0x90, 0x7c, 0x08,
 	0x00, 0x65, 0x4e, 0x58,
-	0x00, 0x65, 0xbe, 0x40,
-	0x20, 0xa0, 0xc0, 0x6a,
+	0x00, 0x65, 0xbc, 0x40,
+	0x20, 0xa0, 0x78, 0x6a,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xd8, 0x5b,
-	0xff, 0x6a, 0xee, 0x5b,
+	0x00, 0x6a, 0x90, 0x5b,
+	0xff, 0x6a, 0xa6, 0x5b,
 	0xff, 0xf8, 0xc8, 0x08,
 	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0xd8, 0x5b,
-	0x00, 0xb9, 0xee, 0x5b,
+	0x01, 0x6a, 0x90, 0x5b,
+	0x00, 0xb9, 0xa6, 0x5b,
 	0x01, 0x4f, 0x9e, 0x18,
 	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xc8, 0x5c,
-	0x00, 0x65, 0xbe, 0x40,
+	0x00, 0x65, 0x80, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
 	0x41, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
 	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0xe0, 0x5c,
-	0x00, 0x65, 0xbe, 0x40,
-	0x10, 0x36, 0x98, 0x7a,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x10, 0x36, 0x50, 0x7a,
 	0x05, 0x38, 0x46, 0x31,
 	0x04, 0x14, 0x58, 0x31,
 	0x03, 0xa9, 0x60, 0x31,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0x38, 0x6a, 0x14, 0x5c,
+	0x38, 0x6a, 0xcc, 0x5b,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0x16, 0x5c,
-	0xa9, 0x6a, 0x18, 0x5c,
-	0x00, 0x65, 0x98, 0x42,
+	0x14, 0x6a, 0xce, 0x5b,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x50, 0x42,
 	0xef, 0x36, 0x6c, 0x08,
-	0x00, 0x65, 0x98, 0x42,
+	0x00, 0x65, 0x50, 0x42,
 	0x0f, 0x64, 0xc8, 0x08,
 	0x07, 0x64, 0xc8, 0x08,
 	0x00, 0x37, 0x6e, 0x00,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0xa8, 0x5b,
-	0xff, 0x51, 0x04, 0x73,
-	0x20, 0x36, 0x0e, 0x7b,
-	0x00, 0x90, 0x96, 0x5b,
-	0x00, 0x65, 0x10, 0x43,
+	0x00, 0x65, 0x60, 0x5b,
+	0xff, 0x51, 0xbc, 0x72,
+	0x20, 0x36, 0xc6, 0x7a,
+	0x00, 0x90, 0x4e, 0x5b,
+	0x00, 0x65, 0xc8, 0x42,
 	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x02, 0x5c,
-	0xe0, 0x3d, 0x2a, 0x63,
-	0x20, 0x12, 0x2a, 0x63,
-	0x51, 0x6a, 0x3e, 0x5b,
-	0x00, 0x65, 0x90, 0x5b,
+	0x00, 0x65, 0xba, 0x5b,
+	0xe0, 0x3d, 0xe2, 0x62,
+	0x20, 0x12, 0xe2, 0x62,
+	0x51, 0x6a, 0xf6, 0x5a,
+	0x00, 0x65, 0x48, 0x5b,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0xa1, 0x22, 0x63,
-	0x04, 0xa0, 0x22, 0x7b,
+	0x00, 0xa1, 0xda, 0x62,
+	0x04, 0xa0, 0xda, 0x7a,
 	0xfb, 0xa0, 0x40, 0x09,
 	0x80, 0x36, 0x6c, 0x00,
-	0x80, 0xa0, 0x98, 0x7a,
+	0x80, 0xa0, 0x50, 0x7a,
 	0x7f, 0xa0, 0x40, 0x09,
-	0xff, 0x6a, 0x3a, 0x5b,
-	0x00, 0x65, 0x98, 0x42,
-	0x04, 0xa0, 0x28, 0x7b,
-	0x00, 0x65, 0xe0, 0x5c,
-	0x00, 0x65, 0x2a, 0x43,
-	0x00, 0x65, 0xc8, 0x5c,
+	0xff, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x04, 0xa0, 0xe0, 0x7a,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xe2, 0x42,
+	0x00, 0x65, 0x80, 0x5c,
 	0x31, 0x6a, 0x22, 0x01,
-	0x0c, 0x6a, 0x3a, 0x5b,
-	0x00, 0x65, 0x98, 0x42,
+	0x0c, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
 	0x61, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x98, 0x42,
-	0x51, 0x6a, 0x3e, 0x5b,
+	0x00, 0x65, 0x50, 0x42,
+	0x51, 0x6a, 0xf6, 0x5a,
 	0x51, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x98, 0x42,
+	0x00, 0x65, 0x50, 0x42,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x65, 0x68, 0x0c,
 	0xff, 0x06, 0xd4, 0x08,
-	0x01, 0x0c, 0x40, 0x7b,
-	0x04, 0x0c, 0x42, 0x6b,
+	0x01, 0x0c, 0xf8, 0x7a,
+	0x04, 0x0c, 0xfa, 0x6a,
 	0xe0, 0x03, 0x7a, 0x08,
-	0xe0, 0x3d, 0x4e, 0x63,
+	0xe0, 0x3d, 0x06, 0x63,
 	0xff, 0x65, 0xcc, 0x08,
 	0xff, 0x12, 0xda, 0x0c,
 	0xff, 0x06, 0xd4, 0x0c,
 	0xd1, 0x6a, 0x22, 0x01,
 	0x00, 0x65, 0xaa, 0x40,
 	0xff, 0x65, 0x26, 0x09,
-	0x01, 0x0b, 0x62, 0x6b,
-	0x10, 0x0c, 0x54, 0x7b,
-	0x04, 0x0b, 0x5c, 0x6b,
+	0x01, 0x0b, 0x1a, 0x6b,
+	0x10, 0x0c, 0x0c, 0x7b,
+	0x04, 0x0b, 0x14, 0x6b,
 	0xff, 0x6a, 0xca, 0x08,
-	0x04, 0x93, 0x60, 0x6b,
-	0x01, 0x94, 0x5e, 0x7b,
-	0x10, 0x94, 0x60, 0x6b,
-	0x80, 0x3d, 0x66, 0x73,
-	0x0f, 0x04, 0x6a, 0x6b,
-	0x02, 0x03, 0x6a, 0x7b,
-	0x11, 0x0c, 0x66, 0x7b,
+	0x04, 0x93, 0x18, 0x6b,
+	0x01, 0x94, 0x16, 0x7b,
+	0x10, 0x94, 0x18, 0x6b,
+	0x80, 0x3d, 0x1e, 0x73,
+	0x0f, 0x04, 0x22, 0x6b,
+	0x02, 0x03, 0x22, 0x7b,
+	0x11, 0x0c, 0x1e, 0x7b,
 	0xc7, 0x93, 0x26, 0x09,
 	0xff, 0x99, 0xd4, 0x08,
-	0x38, 0x93, 0x6c, 0x6b,
+	0x38, 0x93, 0x24, 0x6b,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0x36, 0x70, 0x6b,
+	0x80, 0x36, 0x28, 0x6b,
 	0x21, 0x6a, 0x22, 0x05,
 	0xff, 0x65, 0x20, 0x09,
-	0xff, 0x51, 0x7e, 0x63,
+	0xff, 0x51, 0x36, 0x63,
 	0xff, 0x37, 0xc8, 0x08,
-	0xa1, 0x6a, 0x8a, 0x43,
+	0xa1, 0x6a, 0x42, 0x43,
 	0xff, 0x51, 0xc8, 0x08,
-	0xb9, 0x6a, 0x8a, 0x43,
+	0xb9, 0x6a, 0x42, 0x43,
 	0xff, 0x90, 0xa4, 0x08,
-	0xff, 0xba, 0x8e, 0x73,
+	0xff, 0xba, 0x46, 0x73,
 	0xff, 0xba, 0x20, 0x09,
 	0xff, 0x65, 0xca, 0x18,
-	0x00, 0x6c, 0x82, 0x63,
+	0x00, 0x6c, 0x3a, 0x63,
 	0xff, 0x90, 0xca, 0x0c,
 	0xff, 0x6a, 0xca, 0x04,
-	0x20, 0x36, 0xa2, 0x7b,
-	0x00, 0x90, 0x76, 0x5b,
-	0xff, 0x65, 0xa2, 0x73,
-	0xff, 0x52, 0xa0, 0x73,
+	0x20, 0x36, 0x5a, 0x7b,
+	0x00, 0x90, 0x2e, 0x5b,
+	0xff, 0x65, 0x5a, 0x73,
+	0xff, 0x52, 0x58, 0x73,
 	0xff, 0xba, 0xcc, 0x08,
 	0xff, 0x52, 0x20, 0x09,
 	0xff, 0x66, 0x74, 0x09,
 	0xff, 0x65, 0x20, 0x0d,
 	0xff, 0xba, 0x7e, 0x0c,
-	0x00, 0x6a, 0xce, 0x5c,
+	0x00, 0x6a, 0x86, 0x5c,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x51, 0x2e, 0x44,
-	0xff, 0x3f, 0xfc, 0x73,
+	0x00, 0x51, 0xe6, 0x43,
+	0xff, 0x3f, 0xb4, 0x73,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3f, 0x76, 0x5b,
-	0xff, 0x65, 0xfc, 0x73,
+	0x00, 0x3f, 0x2e, 0x5b,
+	0xff, 0x65, 0xb4, 0x73,
 	0x20, 0x36, 0x6c, 0x00,
-	0x20, 0xa0, 0xb6, 0x6b,
+	0x20, 0xa0, 0x6e, 0x6b,
 	0xff, 0xb9, 0xa2, 0x0c,
 	0xff, 0x6a, 0xa2, 0x04,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x22, 0x5c,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xc2, 0x7b,
+	0x80, 0xeb, 0x7a, 0x7b,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x01, 0xe9, 0xa4, 0x34,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x22, 0x5c,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0xc0, 0x5c,
+	0x00, 0x65, 0x78, 0x5c,
 	0xff, 0x99, 0xa4, 0x0c,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x22, 0x5c,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x22, 0x5c,
+	0x45, 0x6a, 0xda, 0x5b,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xf2, 0x7b,
+	0x80, 0xee, 0xaa, 0x7b,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0xff, 0x65, 0x32, 0x09,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xc0, 0x44,
+	0x00, 0x65, 0x78, 0x44,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xb8, 0x5b,
+	0x00, 0x6a, 0x70, 0x5b,
 	0xff, 0x52, 0xa2, 0x0c,
-	0x01, 0x0c, 0x02, 0x7c,
-	0x04, 0x0c, 0x02, 0x6c,
+	0x01, 0x0c, 0xba, 0x7b,
+	0x04, 0x0c, 0xba, 0x6b,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7a, 0x0c,
 	0xff, 0x8c, 0x10, 0x08,
@@ -539,34 +503,34 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0xff, 0x65, 0xc8, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0x1e, 0x5c,
+	0x41, 0x6a, 0xd6, 0x5b,
 	0xff, 0x90, 0xe2, 0x09,
 	0x20, 0x6a, 0xd0, 0x01,
-	0x04, 0x35, 0x40, 0x7c,
+	0x04, 0x35, 0xf8, 0x7b,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0x3c, 0x64,
-	0x00, 0x65, 0x56, 0x44,
+	0xdc, 0xee, 0xf4, 0x63,
+	0x00, 0x65, 0x0e, 0x44,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x46, 0x7c,
+	0x80, 0xee, 0xfe, 0x7b,
 	0x11, 0x6a, 0xdc, 0x01,
-	0x50, 0xee, 0x4a, 0x64,
+	0x50, 0xee, 0x02, 0x64,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xdc, 0x01,
-	0x88, 0xee, 0x50, 0x64,
+	0x88, 0xee, 0x08, 0x64,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0x54, 0x64,
+	0xd8, 0xee, 0x0c, 0x64,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0x58, 0x6c,
+	0x18, 0xee, 0x10, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0x1e, 0x5c,
+	0x41, 0x6a, 0xd6, 0x5b,
 	0x20, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x35, 0x84, 0x6c,
+	0x04, 0x35, 0x3c, 0x6c,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
 	0xff, 0x6c, 0x32, 0x09,
@@ -577,31 +541,31 @@
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
-	0x00, 0x65, 0x6e, 0x64,
+	0x00, 0x65, 0x26, 0x64,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xc0, 0x44,
+	0x00, 0x65, 0x78, 0x44,
 	0xa0, 0x6a, 0xcc, 0x00,
 	0xe8, 0x6a, 0xc8, 0x00,
-	0x01, 0x94, 0x88, 0x6c,
-	0x10, 0x94, 0x8a, 0x6c,
-	0x08, 0x94, 0x9c, 0x6c,
-	0x08, 0x94, 0x9c, 0x6c,
-	0x08, 0x94, 0x9c, 0x6c,
-	0x00, 0x65, 0xb0, 0x5c,
+	0x01, 0x94, 0x40, 0x6c,
+	0x10, 0x94, 0x42, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
 	0x08, 0x64, 0xc8, 0x18,
 	0x00, 0x8c, 0xca, 0x18,
-	0x00, 0x65, 0x92, 0x4c,
-	0x00, 0x65, 0x88, 0x44,
+	0x00, 0x65, 0x4a, 0x4c,
+	0x00, 0x65, 0x40, 0x44,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x9e, 0x6c,
-	0x00, 0x65, 0xb0, 0x5c,
+	0x08, 0x93, 0x56, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
 	0x08, 0x64, 0xc8, 0x18,
-	0x08, 0x64, 0xa0, 0x64,
+	0x08, 0x64, 0x58, 0x64,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0xc0, 0x5c,
-	0x00, 0x65, 0xb0, 0x5c,
-	0x00, 0x65, 0xb0, 0x5c,
-	0x00, 0x65, 0xb0, 0x5c,
+	0x00, 0x65, 0x78, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
@@ -610,19 +574,19 @@
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x0c,
-	0x08, 0x94, 0xc0, 0x7c,
+	0x08, 0x94, 0x78, 0x7c,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0xc4, 0x6c,
+	0x08, 0x93, 0x7c, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0xff, 0x40, 0x74, 0x09,
 	0xff, 0x90, 0x80, 0x08,
 	0xff, 0x6a, 0x72, 0x05,
-	0xff, 0x40, 0xdc, 0x64,
-	0xff, 0x3f, 0xd4, 0x64,
+	0xff, 0x40, 0x94, 0x64,
+	0xff, 0x3f, 0x8c, 0x64,
 	0xff, 0x6a, 0xca, 0x04,
 	0xff, 0x3f, 0x20, 0x09,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x2e, 0x5c,
+	0x00, 0xb9, 0xe6, 0x5b,
 	0xff, 0xba, 0x7e, 0x0c,
 	0xff, 0x40, 0x20, 0x09,
 	0xff, 0xba, 0x80, 0x0c,
@@ -630,12 +594,20 @@
 	0xff, 0x90, 0x7e, 0x0c,
 };
 
+static int aic7xxx_patch15_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch15_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+}
+
 static int aic7xxx_patch14_func(struct aic7xxx_host *p);
 
 static int
 aic7xxx_patch14_func(struct aic7xxx_host *p)
 {
-	return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+	return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
 }
 
 static int aic7xxx_patch13_func(struct aic7xxx_host *p);
@@ -643,7 +615,7 @@
 static int
 aic7xxx_patch13_func(struct aic7xxx_host *p)
 {
-	return ((p->features & AHC_CMD_CHAN) == 0);
+	return ((p->features & AHC_WIDE) != 0);
 }
 
 static int aic7xxx_patch12_func(struct aic7xxx_host *p);
@@ -651,7 +623,7 @@
 static int
 aic7xxx_patch12_func(struct aic7xxx_host *p)
 {
-	return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
+	return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
 }
 
 static int aic7xxx_patch11_func(struct aic7xxx_host *p);
@@ -659,7 +631,7 @@
 static int
 aic7xxx_patch11_func(struct aic7xxx_host *p)
 {
-	return ((p->features & AHC_WIDE) != 0);
+	return ((p->features & AHC_ULTRA2) == 0);
 }
 
 static int aic7xxx_patch10_func(struct aic7xxx_host *p);
@@ -667,7 +639,7 @@
 static int
 aic7xxx_patch10_func(struct aic7xxx_host *p)
 {
-	return ((p->features & AHC_ULTRA2) == 0);
+	return ((p->features & AHC_CMD_CHAN) == 0);
 }
 
 static int aic7xxx_patch9_func(struct aic7xxx_host *p);
@@ -675,7 +647,7 @@
 static int
 aic7xxx_patch9_func(struct aic7xxx_host *p)
 {
-	return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
+	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
 }
 
 static int aic7xxx_patch8_func(struct aic7xxx_host *p);
@@ -772,59 +744,74 @@
 	{ aic7xxx_patch8_func, 52, 7, 1 },
 	{ aic7xxx_patch3_func, 60, 3, 1 },
 	{ aic7xxx_patch7_func, 63, 2, 1 },
-	{ aic7xxx_patch7_func, 87, 1, 2 },
-	{ aic7xxx_patch0_func, 88, 1, 1 },
-	{ aic7xxx_patch7_func, 103, 1, 2 },
-	{ aic7xxx_patch0_func, 104, 2, 1 },
-	{ aic7xxx_patch7_func, 108, 84, 15 },
-	{ aic7xxx_patch9_func, 177, 1, 1 },
-	{ aic7xxx_patch9_func, 178, 4, 1 },
-	{ aic7xxx_patch0_func, 192, 72, 12 },
-	{ aic7xxx_patch1_func, 192, 1, 2 },
-	{ aic7xxx_patch0_func, 193, 2, 1 },
-	{ aic7xxx_patch1_func, 200, 1, 1 },
-	{ aic7xxx_patch1_func, 203, 3, 2 },
-	{ aic7xxx_patch0_func, 206, 5, 1 },
-	{ aic7xxx_patch1_func, 214, 1, 2 },
-	{ aic7xxx_patch0_func, 215, 3, 1 },
-	{ aic7xxx_patch1_func, 225, 14, 2 },
-	{ aic7xxx_patch0_func, 239, 9, 1 },
-	{ aic7xxx_patch1_func, 254, 2, 2 },
-	{ aic7xxx_patch0_func, 256, 4, 1 },
-	{ aic7xxx_patch1_func, 265, 3, 3 },
-	{ aic7xxx_patch10_func, 267, 1, 1 },
-	{ aic7xxx_patch0_func, 268, 5, 1 },
-	{ aic7xxx_patch10_func, 273, 1, 2 },
-	{ aic7xxx_patch0_func, 274, 9, 1 },
-	{ aic7xxx_patch11_func, 290, 1, 2 },
-	{ aic7xxx_patch0_func, 291, 1, 1 },
-	{ aic7xxx_patch4_func, 352, 1, 2 },
-	{ aic7xxx_patch0_func, 353, 1, 1 },
-	{ aic7xxx_patch2_func, 356, 1, 1 },
-	{ aic7xxx_patch1_func, 366, 3, 2 },
-	{ aic7xxx_patch0_func, 369, 5, 1 },
-	{ aic7xxx_patch11_func, 377, 1, 2 },
-	{ aic7xxx_patch0_func, 378, 1, 1 },
-	{ aic7xxx_patch5_func, 383, 1, 1 },
-	{ aic7xxx_patch10_func, 425, 15, 2 },
-	{ aic7xxx_patch12_func, 438, 1, 1 },
-	{ aic7xxx_patch1_func, 477, 7, 2 },
-	{ aic7xxx_patch0_func, 484, 8, 1 },
-	{ aic7xxx_patch1_func, 493, 4, 2 },
-	{ aic7xxx_patch0_func, 497, 6, 1 },
-	{ aic7xxx_patch1_func, 503, 4, 2 },
-	{ aic7xxx_patch0_func, 507, 3, 1 },
-	{ aic7xxx_patch13_func, 517, 10, 1 },
-	{ aic7xxx_patch1_func, 536, 22, 8 },
-	{ aic7xxx_patch10_func, 544, 4, 4 },
-	{ aic7xxx_patch0_func, 548, 7, 3 },
-	{ aic7xxx_patch14_func, 548, 5, 2 },
-	{ aic7xxx_patch0_func, 553, 2, 1 },
-	{ aic7xxx_patch0_func, 558, 50, 3 },
-	{ aic7xxx_patch12_func, 579, 17, 2 },
-	{ aic7xxx_patch0_func, 596, 4, 1 },
-	{ aic7xxx_patch13_func, 608, 4, 1 },
-	{ aic7xxx_patch5_func, 612, 2, 1 },
-	{ aic7xxx_patch5_func, 615, 9, 1 },
+	{ aic7xxx_patch7_func, 102, 1, 2 },
+	{ aic7xxx_patch0_func, 103, 2, 1 },
+	{ aic7xxx_patch7_func, 107, 2, 1 },
+	{ aic7xxx_patch9_func, 109, 1, 1 },
+	{ aic7xxx_patch10_func, 110, 2, 1 },
+	{ aic7xxx_patch7_func, 113, 1, 2 },
+	{ aic7xxx_patch0_func, 114, 1, 1 },
+	{ aic7xxx_patch1_func, 118, 1, 1 },
+	{ aic7xxx_patch1_func, 121, 3, 3 },
+	{ aic7xxx_patch11_func, 123, 1, 1 },
+	{ aic7xxx_patch0_func, 124, 5, 1 },
+	{ aic7xxx_patch7_func, 132, 1, 1 },
+	{ aic7xxx_patch9_func, 133, 1, 1 },
+	{ aic7xxx_patch10_func, 134, 3, 1 },
+	{ aic7xxx_patch7_func, 137, 3, 2 },
+	{ aic7xxx_patch0_func, 140, 2, 1 },
+	{ aic7xxx_patch7_func, 142, 5, 2 },
+	{ aic7xxx_patch0_func, 147, 3, 1 },
+	{ aic7xxx_patch7_func, 150, 1, 2 },
+	{ aic7xxx_patch0_func, 151, 2, 1 },
+	{ aic7xxx_patch1_func, 153, 15, 4 },
+	{ aic7xxx_patch11_func, 166, 1, 2 },
+	{ aic7xxx_patch0_func, 167, 1, 1 },
+	{ aic7xxx_patch0_func, 168, 10, 1 },
+	{ aic7xxx_patch7_func, 181, 1, 2 },
+	{ aic7xxx_patch0_func, 182, 2, 1 },
+	{ aic7xxx_patch7_func, 184, 18, 1 },
+	{ aic7xxx_patch1_func, 202, 3, 3 },
+	{ aic7xxx_patch7_func, 204, 1, 1 },
+	{ aic7xxx_patch0_func, 205, 4, 1 },
+	{ aic7xxx_patch7_func, 210, 2, 1 },
+	{ aic7xxx_patch7_func, 215, 13, 3 },
+	{ aic7xxx_patch12_func, 218, 1, 1 },
+	{ aic7xxx_patch12_func, 219, 4, 1 },
+	{ aic7xxx_patch1_func, 229, 3, 3 },
+	{ aic7xxx_patch11_func, 231, 1, 1 },
+	{ aic7xxx_patch0_func, 232, 5, 1 },
+	{ aic7xxx_patch11_func, 237, 1, 2 },
+	{ aic7xxx_patch0_func, 238, 9, 1 },
+	{ aic7xxx_patch13_func, 254, 1, 2 },
+	{ aic7xxx_patch0_func, 255, 1, 1 },
+	{ aic7xxx_patch4_func, 316, 1, 2 },
+	{ aic7xxx_patch0_func, 317, 1, 1 },
+	{ aic7xxx_patch2_func, 320, 1, 1 },
+	{ aic7xxx_patch1_func, 330, 3, 2 },
+	{ aic7xxx_patch0_func, 333, 5, 1 },
+	{ aic7xxx_patch13_func, 341, 1, 2 },
+	{ aic7xxx_patch0_func, 342, 1, 1 },
+	{ aic7xxx_patch5_func, 347, 1, 1 },
+	{ aic7xxx_patch11_func, 389, 15, 2 },
+	{ aic7xxx_patch14_func, 402, 1, 1 },
+	{ aic7xxx_patch1_func, 441, 7, 2 },
+	{ aic7xxx_patch0_func, 448, 8, 1 },
+	{ aic7xxx_patch1_func, 457, 4, 2 },
+	{ aic7xxx_patch0_func, 461, 6, 1 },
+	{ aic7xxx_patch1_func, 467, 4, 2 },
+	{ aic7xxx_patch0_func, 471, 3, 1 },
+	{ aic7xxx_patch10_func, 481, 10, 1 },
+	{ aic7xxx_patch1_func, 500, 22, 5 },
+	{ aic7xxx_patch11_func, 508, 4, 1 },
+	{ aic7xxx_patch7_func, 512, 7, 3 },
+	{ aic7xxx_patch15_func, 512, 5, 2 },
+	{ aic7xxx_patch0_func, 517, 2, 1 },
+	{ aic7xxx_patch10_func, 522, 50, 3 },
+	{ aic7xxx_patch14_func, 543, 17, 2 },
+	{ aic7xxx_patch0_func, 560, 4, 1 },
+	{ aic7xxx_patch10_func, 572, 4, 1 },
+	{ aic7xxx_patch5_func, 576, 2, 1 },
+	{ aic7xxx_patch5_func, 579, 9, 1 },
 
 };
diff -urN linux-2.2.19-pre9/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- linux-2.2.19-pre9/drivers/scsi/aic7xxx.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/scsi/aic7xxx.c	Mon Dec  3 21:01:23 2001
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.32"
+#define AIC7XXX_C_VERSION  "5.1.33"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
diff -urN linux-2.2.19-pre9/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- linux-2.2.19-pre9/drivers/scsi/hosts.c	Mon Dec  3 21:00:54 2001
+++ linux/drivers/scsi/hosts.c	Mon Dec  3 21:01:23 2001
@@ -136,7 +136,7 @@
 #endif
 
 #ifdef CONFIG_SCSI_AIC7XXX
-#include "aic7xxx.h"
+#include "aic7xxx/aic7xxx.h"
 #endif
 
 #ifdef CONFIG_SCSI_IPS
diff -urN linux-2.2.19-pre9/drivers/usb/Config.in linux/drivers/usb/Config.in
--- linux-2.2.19-pre9/drivers/usb/Config.in	Mon Dec  3 21:00:54 2001
+++ linux/drivers/usb/Config.in	Mon Dec  3 21:01:23 2001
@@ -29,7 +29,7 @@
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
    dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
    dep_tristate '  USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
-   if [ "$CONFIG_USB_STORAGE" != "n" ]; then
+   if [ "$CONFIG_USB_STORAGE" = "y" -o "$CONFIG_USB_STORAGE" = "m" ]; then
       bool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
    fi
    dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
@@ -45,7 +45,7 @@
       dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB $CONFIG_USB_HID
    fi
    dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB $CONFIG_USB_HID
-   if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
+   if [ "$CONFIG_INPUT_MOUSEDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "m" ]; then
       int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
       int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
    fi
diff -urN linux-2.2.19-pre9/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- linux-2.2.19-pre9/drivers/usb/serial/Config.in	Mon Dec  3 21:00:54 2001
+++ linux/drivers/usb/serial/Config.in	Mon Dec  3 21:01:23 2001
@@ -16,7 +16,7 @@
   dep_tristate '  USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
   dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
+  if [ "$CONFIG_USB_SERIAL_KEYSPAN" = "y" -o "$CONFIG_USB_SERIAL_KEYSPAN" = "m" ]; then
      bool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
      bool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
      bool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
diff -urN linux-2.2.19-pre9/fs/dcache.c linux/fs/dcache.c
--- linux-2.2.19-pre9/fs/dcache.c	Mon Dec  3 21:00:54 2001
+++ linux/fs/dcache.c	Mon Dec  3 21:01:23 2001
@@ -573,7 +573,7 @@
 static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
 	hash += (unsigned long) parent / L1_CACHE_BYTES;
-	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
+	hash = hash ^ (hash >> D_HASHBITS);
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
 
diff -urN linux-2.2.19-pre9/fs/inode.c linux/fs/inode.c
--- linux-2.2.19-pre9/fs/inode.c	Mon Dec  3 21:00:54 2001
+++ linux/fs/inode.c	Mon Dec  3 21:01:23 2001
@@ -681,7 +681,7 @@
 static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
 {
 	unsigned long tmp = i_ino | (unsigned long) sb;
-	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+	tmp = tmp + (tmp >> HASH_BITS);
 	return tmp & HASH_MASK;
 }
 
diff -urN linux-2.2.19-pre9/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c
--- linux-2.2.19-pre9/fs/lockd/clntlock.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/clntlock.c	Mon Dec  3 21:01:23 2001
@@ -138,18 +138,15 @@
 void
 nlmclnt_recovery(struct nlm_host *host, u32 newstate)
 {
-	if (!host->h_reclaiming++) {
+	if (host->h_reclaiming++) {
 		if (host->h_nsmstate == newstate)
 			return;
 		printk(KERN_WARNING
 			"lockd: Uh-oh! Interfering reclaims for host %s",
 			host->h_name);
-		host->h_monitored = 0;
 		host->h_nsmstate = newstate;
 		host->h_state++;
-		nlm_release_host(host);
 	} else {
-		host->h_monitored = 0;
 		host->h_nsmstate = newstate;
 		host->h_state++;
 		nlm_get_host(host);
@@ -168,7 +165,11 @@
 	/* This one ensures that our parent doesn't terminate while the
 	 * reclaim is in progress */
 	lock_kernel();
+	daemonize();
+
 	lockd_up();
+
+	exit_files(current);
 
 	/* First, reclaim all locks that have been granted previously. */
 	do {
diff -urN linux-2.2.19-pre9/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c
--- linux-2.2.19-pre9/fs/lockd/clntproc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/clntproc.c	Mon Dec  3 21:01:23 2001
@@ -46,13 +46,11 @@
 {
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_lock	*lock = &argp->lock;
-	struct dentry   *dentry = fl->fl_file->f_dentry;
-	struct nfs_fh   *fh = NFS_FH(dentry);
 
 	memset(argp, 0, sizeof(*argp));
 	nlmclnt_next_cookie(&argp->cookie);
 	argp->state   = nsm_local_state;
-	memcpy(&lock->fh, fh, sizeof(*fh));
+	memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(lock->fh));
 	lock->caller  = system_utsname.nodename;
 	lock->oh.data = req->a_owner;
 	lock->oh.len  = sprintf(req->a_owner, "%d@%s",
diff -urN linux-2.2.19-pre9/fs/lockd/host.c linux/fs/lockd/host.c
--- linux-2.2.19-pre9/fs/lockd/host.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/host.c	Mon Dec  3 21:01:23 2001
@@ -26,7 +26,6 @@
 #define NLM_HOST_REBIND		(60 * HZ)
 #define NLM_HOST_EXPIRE		((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
 #define NLM_HOST_COLLECT	((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
-#define NLM_HOST_ADDR(sv)	(&(sv)->s_nlmclnt->cl_xprt->addr)
 
 static struct nlm_host *	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc = 0;
@@ -37,24 +36,6 @@
 static void			nlm_gc_hosts(void);
 
 /*
- * Find an NLM server handle in the cache. If there is none, create it.
- */
-struct nlm_host *
-nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
-{
-	return nlm_lookup_host(NULL, sin, proto, version);
-}
-
-/*
- * Find an NLM client handle in the cache. If there is none, create it.
- */
-struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp)
-{
-	return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr, 0, 0);
-}
-
-/*
  * Match the given host against client/address
  */
 static inline int
@@ -67,60 +48,33 @@
 }
 
 /*
- * Common host lookup routine for server & client
+ * Hash the host
  */
-struct nlm_host *
-nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
-					int proto, int version)
+static inline int
+nlm_hash_host(struct svc_client *clnt, struct sockaddr_in *sin)
 {
-	struct nlm_host	*host, **hp;
-	u32		addr;
-	int		hash;
-
-	if (!clnt && !sin) {
-		printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
-		return NULL;
-	}
-
-	dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
-			(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
-
 	if (clnt)
-		hash = NLM_PTRHASH(clnt);
-	else
-		hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
+		return NLM_PTRHASH(clnt);
+	return NLM_ADDRHASH(sin->sin_addr.s_addr);
+}
 
-	/* Lock hash table */
-	down(&nlm_host_sema);
+static struct nlm_host *
+nlm_create_host(struct svc_client *clnt, struct sockaddr_in *sin,
+		int proto, int version)
+{
+	struct nlm_host	*host;
+	u32		addr;
+	int		hash;
 
 	if (time_after_eq(jiffies, next_gc))
 		nlm_gc_hosts();
 
-	for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
-		if (host->h_version != version || host->h_proto != proto)
-			continue;
-
-		if (nlm_match_host(host, clnt, sin)) {
-			if (hp != nlm_hosts + hash) {
-				*hp = host->h_next;
-				host->h_next = nlm_hosts[hash];
-				nlm_hosts[hash] = host;
-			}
-			nlm_get_host(host);
-			up(&nlm_host_sema);
-			return host;
-		}
+	if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL))) {
+		dprintk("lockd: attempt to create host entry failed.\n");
+		return NULL;
 	}
 
-	/* special hack for nlmsvc_invalidate_client */
-	if (sin == NULL)
-		goto nohost;
-
-	/* Ooops, no host found, create it */
-	dprintk("lockd: creating host entry\n");
-
-	if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL)))
-		goto nohost;
+	dprintk("lockd: creating host entry.\n");
 	memset(host, 0, sizeof(*host));
 
 	addr = sin->sin_addr.s_addr;
@@ -135,22 +89,103 @@
 	host->h_version    = version;
 	host->h_proto      = proto;
 	host->h_authflavor = RPC_AUTH_UNIX;
-	host->h_rpcclnt    = NULL;
 	host->h_sema	   = MUTEX;
-	host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 	host->h_expires    = jiffies + NLM_HOST_EXPIRE;
 	host->h_count      = 1;
-	host->h_state      = 0;			/* pseudo NSM state */
-	host->h_nsmstate   = 0;			/* real NSM state */
 	host->h_exportent  = clnt;
 
+	hash = nlm_hash_host(clnt, sin);
 	host->h_next       = nlm_hosts[hash];
 	nlm_hosts[hash]    = host;
 
 	if (++nrhosts > NLM_HOST_MAX)
-		next_gc = 0;
+		next_gc = jiffies;
+
+	return host;
+}
+
+static struct nlm_host *
+__nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
+		  int proto, int version)
+{
+	struct nlm_host	*host, **hp;
+	int hash;
+
+	if (!clnt && !sin) {
+		printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
+		return NULL;
+	}
+
+	dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
+			(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
+
+	hash = nlm_hash_host(clnt, sin);
+	for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
+		if (proto && host->h_proto != proto)
+			continue;
+		if (version && host->h_version != version)
+			continue;
+
+		if (nlm_match_host(host, clnt, sin)) {
+			if (hp != nlm_hosts + hash) {
+				*hp = host->h_next;
+				host->h_next = nlm_hosts[hash];
+				nlm_hosts[hash] = host;
+			}
+			nlm_get_host(host);
+			break;
+		}
+	}
+	return host;
+}
+
+/*
+ * Common host lookup routine for server & client
+ */
+struct nlm_host *
+nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
+		int proto, int version)
+{
+	struct nlm_host *host;
 
-nohost:
+	/* Lock hash table */
+	down(&nlm_host_sema);
+	host = __nlm_lookup_host(clnt, sin, proto, version);
+	up(&nlm_host_sema);
+	return host;
+}
+
+/*
+ * Find an NLM server handle in the cache. If there is none, create it.
+ */
+struct nlm_host *
+nlmclnt_lookup_host(struct sockaddr_in *sin, int prot, int vers)
+{
+	struct nlm_host *host;
+
+	/* Lock hash table */
+	down(&nlm_host_sema);
+	if ((host = __nlm_lookup_host(NULL, sin, prot, vers)) == NULL)
+		host = nlm_create_host(NULL, sin, prot, vers);
+	up(&nlm_host_sema);
+	return host;
+}
+
+/*
+ * Find an NLM client handle in the cache. If there is none, create it.
+ */
+struct nlm_host *
+nlmsvc_lookup_host(struct svc_rqst *rqstp)
+{
+	struct nlm_host *host;
+	struct svc_client *clnt = rqstp->rq_client;
+	int prot = rqstp->rq_prot,
+	    vers = rqstp->rq_vers;
+
+	/* Lock hash table */
+	down(&nlm_host_sema);
+	if ((host = __nlm_lookup_host(clnt, NULL, prot, vers)) == NULL)
+		host = nlm_create_host(clnt, &rqstp->rq_addr, prot, vers);
 	up(&nlm_host_sema);
 	return host;
 }
@@ -206,6 +241,7 @@
 		clnt->cl_autobind = 1;	/* turn on pmap queries */
 		xprt->nocong = 1;	/* No congestion control for NLM */
 
+		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 		host->h_rpcclnt = clnt;
 	}
 
@@ -272,7 +308,7 @@
 	dprintk("lockd: nuking all hosts...\n");
 	for (i = 0; i < NLM_HOST_NRHASH; i++) {
 		for (host = nlm_hosts[i]; host; host = host->h_next)
-			host->h_expires = 0;
+			host->h_expires = jiffies;
 	}
 
 	/* Then, perform a garbage collection pass */
@@ -326,15 +362,8 @@
 			*q = host->h_next;
 			if (host->h_monitored)
 				nsm_unmonitor(host);
-			if ((clnt = host->h_rpcclnt) != NULL) {
-				if (atomic_read(&clnt->cl_users)) {
-					printk(KERN_WARNING
-						"lockd: active RPC handle\n");
-					clnt->cl_dead = 1;
-				} else {
-					rpc_destroy_client(host->h_rpcclnt);
-				}
-			}
+			if ((clnt = host->h_rpcclnt) != NULL)
+				rpc_shutdown_client(clnt);
 			kfree(host);
 			nrhosts--;
 		}
diff -urN linux-2.2.19-pre9/fs/lockd/mon.c linux/fs/lockd/mon.c
--- linux-2.2.19-pre9/fs/lockd/mon.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/mon.c	Mon Dec  3 21:01:23 2001
@@ -47,7 +47,7 @@
 
 	args.addr = host->h_addr.sin_addr.s_addr;
 	args.prog = NLM_PROGRAM;
-	args.vers = 1;
+	args.vers = host->h_version;
 	args.proc = NLMPROC_NSM_NOTIFY;
 	memset(res, 0, sizeof(*res));
 
@@ -76,8 +76,10 @@
 
 	if (status < 0 || res.status != 0)
 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
-	else
+	else {
 		host->h_monitored = 1;
+		host->h_nsmstate = res.state;
+	}
 	return status;
 }
 
diff -urN linux-2.2.19-pre9/fs/lockd/svc.c linux/fs/lockd/svc.c
--- linux-2.2.19-pre9/fs/lockd/svc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/svc.c	Mon Dec  3 21:01:23 2001
@@ -77,9 +77,7 @@
 	nlmsvc_pid = current->pid;
 	up(&lockd_start);
 
-	exit_mm(current);
-	current->session = 1;
-	current->pgrp = 1;
+	daemonize();
 	sprintf(current->comm, "lockd");
 
 	/* Process request with signals blocked.  */
@@ -105,12 +103,8 @@
 #ifdef RPC_DEBUG
 	nlmsvc_grace_period = 10 * HZ;
 #else
-	if (nlm_grace_period) {
-		nlmsvc_grace_period += (1 + nlm_grace_period / nlm_timeout)
-						* nlm_timeout * HZ;
-	} else {
-		nlmsvc_grace_period += 5 * nlm_timeout * HZ;
-	}
+	nlmsvc_grace_period = (1 + nlm_grace_period / nlm_timeout)
+				* nlm_timeout * HZ;
 #endif
 
 	grace_period_expire = nlmsvc_grace_period + jiffies;
@@ -138,8 +132,11 @@
 		 */
 		if (!nlmsvc_grace_period) {
 			timeout = nlmsvc_retry_blocked();
-		} else if (time_before(nlmsvc_grace_period, jiffies))
+		} else if (time_before(grace_period_expire, jiffies)) {
 			nlmsvc_grace_period = 0;
+			continue;
+		} else
+			timeout = nlmsvc_timeout;
 
 		/*
 		 * Find a socket with data available and call its
@@ -349,7 +346,7 @@
  * Define NLM program and procedures
  */
 static struct svc_version	nlmsvc_version1 = {
-	1, 16, nlmsvc_procedures, NULL
+	1, 17, nlmsvc_procedures, NULL
 };
 static struct svc_version	nlmsvc_version3 = {
 	3, 24, nlmsvc_procedures, NULL
diff -urN linux-2.2.19-pre9/fs/lockd/svc4proc.c linux/fs/lockd/svc4proc.c
--- linux-2.2.19-pre9/fs/lockd/svc4proc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/svc4proc.c	Mon Dec  3 21:01:23 2001
@@ -422,6 +422,8 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
+	int			vers = rqstp->rq_vers;
+	int			prot = rqstp->rq_prot;
 	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
@@ -438,7 +440,7 @@
 	 * reclaim all locks we hold on this server.
 	 */
 	saddr.sin_addr.s_addr = argp->addr;	
-	if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
 		nlmclnt_recovery(host, argp->state);
 		nlm_release_host(host);
 	}
@@ -448,7 +450,7 @@
 		struct svc_client	*clnt;
 		saddr.sin_addr.s_addr = argp->addr;	
 		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
-		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+		 && (host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
 			nlmsvc_free_host_resources(host);
 			nlm_release_host(host);
 		}
@@ -551,7 +553,8 @@
   PROC(cancel_res,	cancelres,	norep,		res,	void),
   PROC(unlock_res,	unlockres,	norep,		res,	void),
   PROC(granted_res,	grantedres,	norep,		res,	void),
-  PROC(none,		void,		void,		void,	void),
+  /* statd callback */
+  PROC(sm_notify,	reboot,		void,		reboot,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
@@ -560,6 +563,4 @@
   PROC(nm_lock,		lockargs,	res,		args,	res),
   PROC(free_all,	notify,		void,		args,	void),
 
-  /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
 };
diff -urN linux-2.2.19-pre9/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- linux-2.2.19-pre9/fs/lockd/svclock.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/svclock.c	Mon Dec  3 21:01:23 2001
@@ -53,9 +53,15 @@
 	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
 	if (block->b_queued)
 		nlmsvc_remove_block(block);
-	for (bp = &nlm_blocked; (b = *bp); bp = &b->b_next)
-		if (when < b->b_when)
-			break;
+	bp = &nlm_blocked;
+	if (when != NLM_NEVER) {
+		if ((when += jiffies) == NLM_NEVER)
+			when ++;
+		while ((b = *bp) && time_before_eq(b->b_when,when))
+			bp = &b->b_next;
+	} else
+		while ((b = *bp))
+			bp = &b->b_next;
 
 	block->b_queued = 1;
 	block->b_when = when;
@@ -159,8 +165,7 @@
 	struct nlm_rqst		*call;
 
 	/* Create host handle for callback */
-	host = nlmclnt_lookup_host(&rqstp->rq_addr,
-				rqstp->rq_prot, rqstp->rq_vers);
+	host = nlmsvc_lookup_host(rqstp);
 	if (host == NULL)
 		return NULL;
 
@@ -169,10 +174,11 @@
 		goto failed;
 	memset(block, 0, sizeof(*block));
 
-	/* Set notifier function for VFS, and init args */
-	lock->fl.fl_notify = nlmsvc_notify_blocked;
 	if (!nlmclnt_setgrantargs(&block->b_call, lock))
 		goto failed_free;
+
+	/* Set notifier function for VFS, and init args */
+	block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked;
 	block->b_call.a_args.cookie = *cookie;	/* see above */
 
 	dprintk("lockd: created block %p...\n", block);
@@ -263,12 +269,12 @@
 	down(&file->f_sema);
 	for (block = file->f_blocks; block; block = next) {
 		next = block->b_fnext;
+		if (host && block->b_host != host)
+			continue;
 		if (action == NLM_ACT_MARK)
 			block->b_host->h_inuse = 1;
-		else if (action == NLM_ACT_UNLOCK) {
-			if (host == NULL || host == block->b_host)
-				nlmsvc_delete_block(block, 1);
-		}
+		else if (action == NLM_ACT_UNLOCK)
+			nlmsvc_delete_block(block, 1);
 	}
 	up(&file->f_sema);
 	return 0;
@@ -455,8 +461,8 @@
 	posix_unblock_lock(fl);
 	for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
 		if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
-			svc_wake_up(block->b_daemon);
 			nlmsvc_insert_block(block, 0);
+			svc_wake_up(block->b_daemon);
 			return;
 		}
 	}
@@ -516,7 +522,7 @@
 	if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {
 		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
 				-error, __FUNCTION__);
-		nlmsvc_insert_block(block, jiffies + 10 * HZ);
+		nlmsvc_insert_block(block, 10 * HZ);
 		up(&file->f_sema);
 		return;
 	}
@@ -528,7 +534,7 @@
 	block->b_incall  = 1;
 
 	/* Schedule next grant callback in 30 seconds */
-	nlmsvc_insert_block(block, jiffies + 30 * HZ);
+	nlmsvc_insert_block(block, 30 * HZ);
 
 	/* Call the client */
 	nlm_get_host(block->b_call.a_host);
@@ -566,13 +572,13 @@
 	 * can be done, though. */
 	if (task->tk_status < 0) {
 		/* RPC error: Re-insert for retransmission */
-		timeout = jiffies + 10 * HZ;
+		timeout = 10 * HZ;
 	} else if (block->b_done) {
 		/* Block already removed, kill it for real */
 		timeout = 0;
 	} else {
 		/* Call was successful, now wait for client callback */
-		timeout = jiffies + 60 * HZ;
+		timeout = 60 * HZ;
 	}
 	nlmsvc_insert_block(block, timeout);
 	svc_wake_up(block->b_daemon);
@@ -600,7 +606,7 @@
 	if ((block = nlmsvc_find_block(cookie)) != NULL) {
 		if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
 			/* Try again in a couple of seconds */
-			nlmsvc_insert_block(block, jiffies + 10 * HZ);
+			nlmsvc_insert_block(block, 10 * HZ);
 			block = NULL;
 		} else {
 			/* Lock is now held by client, or has been rejected.
@@ -631,7 +637,11 @@
 	dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			nlm_blocked,
 			nlm_blocked? nlm_blocked->b_when : 0);
-	while ((block = nlm_blocked) && block->b_when <= jiffies) {
+	while ((block = nlm_blocked)) {
+		if (block->b_when == NLM_NEVER)
+			break;
+		if (time_after(block->b_when,jiffies))
+			break;
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
 			block, block->b_when, block->b_done);
 		if (block->b_done)
diff -urN linux-2.2.19-pre9/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c
--- linux-2.2.19-pre9/fs/lockd/svcproc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/svcproc.c	Mon Dec  3 21:01:23 2001
@@ -435,6 +435,8 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
+	int			vers = rqstp->rq_vers;
+	int			prot = rqstp->rq_prot;
 	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
@@ -450,8 +452,8 @@
 	/* Obtain the host pointer for this NFS server and try to
 	 * reclaim all locks we hold on this server.
 	 */
-	saddr.sin_addr.s_addr = argp->addr;	
-	if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+	saddr.sin_addr.s_addr = htonl(argp->addr);
+	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
 		nlmclnt_recovery(host, argp->state);
 		nlm_release_host(host);
 	}
@@ -461,7 +463,7 @@
 		struct svc_client	*clnt;
 		saddr.sin_addr.s_addr = argp->addr;	
 		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
-		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+		 && (host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
 			nlmsvc_free_host_resources(host);
 			nlm_release_host(host);
 		}
@@ -585,7 +587,8 @@
   PROC(cancel_res,	cancelres,	norep,		res,	void),
   PROC(unlock_res,	unlockres,	norep,		res,	void),
   PROC(granted_res,	grantedres,	norep,		res,	void),
-  PROC(none,		void,		void,		void,	void),
+  /* statd callback */
+  PROC(sm_notify,	reboot,		void,		reboot,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
@@ -594,6 +597,4 @@
   PROC(nm_lock,		lockargs,	res,		args,	res),
   PROC(free_all,	notify,		void,		args,	void),
 
-  /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
 };
diff -urN linux-2.2.19-pre9/fs/lockd/svcshare.c linux/fs/lockd/svcshare.c
--- linux-2.2.19-pre9/fs/lockd/svcshare.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/lockd/svcshare.c	Mon Dec  3 21:01:23 2001
@@ -95,14 +95,16 @@
 
 	shpp = &file->f_shares;
 	while ((share = *shpp) !=  NULL) {
+		if (host && host != share->s_host) {
+			shpp = &share->s_next;
+			continue;
+		}
 		if (action == NLM_ACT_MARK)
 			share->s_host->h_inuse = 1;
 		else if (action == NLM_ACT_UNLOCK) {
-			if (host == NULL || host == share->s_host) {
-				*shpp = share->s_next;
-				kfree(share);
-				continue;
-			}
+			*shpp = share->s_next;
+			kfree(share);
+			continue;
 		}
 		shpp = &share->s_next;
 	}
diff -urN linux-2.2.19-pre9/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c
--- linux-2.2.19-pre9/fs/lockd/svcsubs.c	Mon Dec  3 21:00:54 2001
+++ linux/fs/lockd/svcsubs.c	Mon Dec  3 21:01:23 2001
@@ -150,6 +150,7 @@
 	struct inode	 *inode = nlmsvc_file_inode(file);
 	struct file_lock *fl;
 	struct nlm_host	 *lockhost;
+	int		 status = 0;
 
 again:
 	file->f_locks = 0;
@@ -160,29 +161,27 @@
 		/* update current lock count */
 		file->f_locks++;
 		lockhost = (struct nlm_host *) fl->fl_owner;
+		if (host && lockhost != host)
+			continue;
 		if (action == NLM_ACT_MARK)
 			lockhost->h_inuse = 1;
 		else if (action == NLM_ACT_CHECK)
-			return 1;
+			status = 1;
 		else if (action == NLM_ACT_UNLOCK) {
-			struct file_lock lock = *fl;
-
-			if (host && lockhost != host)
-				continue;
+			struct file_lock lock;
 
+			lock = *fl;
 			lock.fl_type  = F_UNLCK;
-			lock.fl_start = 0;
-			lock.fl_end   = NLM_OFFSET_MAX;
 			if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
-				return 1;
-			}
-			goto again;
+				status = 1;
+			} else
+				goto again;
 		}
 	}
 
-	return 0;
+	return status;
 }
 
 /*
@@ -211,6 +210,7 @@
 {
 	struct nlm_file	*file, **fp;
 	int		i;
+	int		res = 0;
 
 	down(&nlm_file_sema);
 	for (i = 0; i < FILE_NRHASH; i++) {
@@ -218,24 +218,21 @@
 		while ((file = *fp) != NULL) {
 			/* Traverse locks, blocks and shares of this file
 			 * and update file->f_locks count */
-			if (nlm_inspect_file(host, file, action)) {
-				up(&nlm_file_sema);
-				return 1;
-			}
+			if (nlm_inspect_file(host, file, action))
+				res = 1;
 
-			/* No more references to this file. Let go of it. */
-			if (!file->f_blocks && !file->f_locks
-			 && !file->f_shares && !file->f_count) {
-				*fp = file->f_next;
-				nlmsvc_ops->fclose(&file->f_file);
-				kfree(file);
-			} else {
+			if (file->f_blocks || file->f_locks
+			    || file->f_shares || file->f_count) {
 				fp = &file->f_next;
+				continue;
 			}
+			*fp = file->f_next;
+			nlmsvc_ops->fclose(&file->f_file);
+			kfree(file);
 		}
 	}
 	up(&nlm_file_sema);
-	return 0;
+	return res;
 }
 
 /*
@@ -301,7 +298,7 @@
 	if ((host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
 		dprintk("lockd: invalidating client for %s\n", host->h_name);
 		nlmsvc_free_host_resources(host);
-		host->h_expires = 0;
+		host->h_expires = jiffies;
 		nlm_release_host(host);
 	}
 }
diff -urN linux-2.2.19-pre9/fs/locks.c linux/fs/locks.c
--- linux-2.2.19-pre9/fs/locks.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/locks.c	Mon Dec  3 21:01:23 2001
@@ -268,20 +268,22 @@
 
 	while ((waiter = blocker->fl_nextblock) != NULL) {
 		/* N.B. Is it possible for the notify function to block?? */
+		if (!wait) {
+			/* Remove waiter from the block list, because by the
+			 * time it wakes up blocker won't exist any more.
+			 */
+			locks_delete_block(blocker, waiter);
+		}
 		if (waiter->fl_notify)
 			waiter->fl_notify(waiter);
-		wake_up(&waiter->fl_wait);
+		else
+			wake_up(&waiter->fl_wait);
 		if (wait) {
 			/* Let the blocked process remove waiter from the
 			 * block list when it gets scheduled.
 			 */
 			current->policy |= SCHED_YIELD;
 			schedule();
-		} else {
-			/* Remove waiter from the block list, because by the
-			 * time it wakes up blocker won't exist any more.
-			 */
-			locks_delete_block(blocker, waiter);
 		}
 	}
 	return;
diff -urN linux-2.2.19-pre9/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux-2.2.19-pre9/fs/nfs/dir.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/dir.c	Mon Dec  3 21:01:23 2001
@@ -45,6 +45,7 @@
 static int nfs_safe_remove(struct dentry *);
 
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
+static loff_t nfs_dir_llseek(struct file *, loff_t, int);
 static int nfs_readdir(struct file *, void *, filldir_t);
 static struct dentry *nfs_lookup(struct inode *, struct dentry *);
 static int nfs_create(struct inode *, struct dentry *, int);
@@ -58,7 +59,7 @@
 		      struct inode *, struct dentry *);
 
 static struct file_operations nfs_dir_operations = {
-	NULL,			/* lseek - default */
+	nfs_dir_llseek,		/* llseek */
 	nfs_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	nfs_readdir,		/* readdir */
@@ -131,7 +132,7 @@
 	struct file	*file = desc->file;
 	struct dentry	*dir = file->f_dentry;
 	struct inode	*inode = dir->d_inode;
-	struct nfs_fattr dir_attr;
+	struct rpc_cred	*cred = nfs_file_cred(file);
 	void		*buffer = (void *)page_address(page);
 	int		plus = NFS_USE_READDIRPLUS(inode);
 	int		error;
@@ -139,11 +140,9 @@
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->offset);
 
  again:
-	error = NFS_CALL(readdir, inode, (dir, &dir_attr,
-					  nfs_file_cred(file),
+	error = NFS_PROTO(inode)->readdir(inode, cred,
 					  desc->entry->cookie, buffer,
-					  NFS_SERVER(inode)->dtsize, plus));
-	nfs_refresh_inode(inode, &dir_attr);
+					  NFS_SERVER(inode)->dtsize, plus);
 	/* We requested READDIRPLUS, but the server doesn't grok it */
 	if (desc->plus && error == -ENOTSUPP) {
 		NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
@@ -339,7 +338,7 @@
 	struct file	*file = desc->file;
 	struct dentry	*dir = file->f_dentry;
 	struct inode	*inode = dir->d_inode;
-	struct nfs_fattr dir_attr;
+	struct rpc_cred	*cred = nfs_file_cred(file);
 	struct page	*page = NULL;
 	unsigned long	cache_page;
 	u32		*p;
@@ -358,11 +357,8 @@
 	}
 	page = page_cache_entry(cache_page);
 	p = (u32 *)page_address(page);
-	status = NFS_CALL(readdir, inode, (dir, &dir_attr,
-					   nfs_file_cred(file),
-					   desc->target, p,
-					   NFS_SERVER(inode)->dtsize, 0));
-	nfs_refresh_inode(inode, &dir_attr);
+	status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p,
+					   NFS_SERVER(inode)->dtsize, 0);
 	if (status >= 0) {
 		p = desc->decode(p, desc->entry, 0);
 		if (IS_ERR(p))
@@ -452,6 +448,22 @@
 	return 0;
 }
 
+/*
+ * nfs_dir_llseek(): cater for the fact that NFS(v2|v3) readdir
+ *		     cookies take (32|64)-bit unsigned values.
+ */
+static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+	/* We disallow SEEK_CUR and SEEK_END */
+	if (origin != 0)
+		return -EINVAL;
+	if (offset != file->f_pos) {
+		file->f_pos = offset;
+		file->f_reada = 0;
+		file->f_version = ++global_event;
+	}
+	return (offset > 0) ? offset : 0;
+}
 
 /*
  * Whenever an NFS operation succeeds, we know that the dentry
@@ -521,11 +533,10 @@
  */
 static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 {
-	struct dentry		*dir = dentry->d_parent;
-	struct inode		*inode = dentry->d_inode,
-				*dir_i = dir->d_inode;
+	struct inode		*dir = dentry->d_parent->d_inode;
+	struct inode		*inode = dentry->d_inode;
 	struct nfs_fh		fhandle;
-	struct nfs_fattr	fattr, dir_attr;
+	struct nfs_fattr	fattr;
 	int error;
 
 	/*
@@ -541,7 +552,7 @@
 
 	if (is_bad_inode(inode)) {
 		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
-			dir->d_name.name, dentry->d_name.name);
+			dentry->d_parent->d_name.name, dentry->d_name.name);
 		goto out_bad;
 	}
 
@@ -549,7 +560,7 @@
 		goto out_valid;
 
 	if (IS_ROOT(dentry)) {
-		__nfs_revalidate_inode(dentry);
+		__nfs_revalidate_inode(NFS_SERVER(inode), inode);
 		goto out_valid_renew;
 	}
 
@@ -559,8 +570,7 @@
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
-	error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
-				  &dentry->d_name, &fhandle, &fattr));
+	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
 	if (error < 0)
 		goto out_bad;
 
@@ -570,18 +580,12 @@
 	    NFS_FILEID(inode) != fattr.fileid)
 		goto out_bad;
 
-	/* Filehandle matches? */
-	if (NFS_FH(dentry)->size == 0)
-		goto out_bad;
+	/* Ok, remember that we successfully checked it.. */
+	nfs_refresh_inode(inode, &fattr);
 
-	if (NFS_FH(dentry)->size != fhandle.size ||
-	    memcmp(NFS_FH(dentry)->data, fhandle.data, fhandle.size))
+	if (nfs_inode_is_stale(inode, &fhandle, &fattr))
 		goto out_bad;
 
-	/* Ok, remeber that we successfully checked it.. */
-	nfs_refresh_inode(inode, &fattr);
-	nfs_refresh_inode(dir_i, &dir_attr);
-
  out_valid_renew:
 	nfs_renew_times(dentry);
  out_valid:
@@ -593,10 +597,9 @@
 	if (have_submounts(dentry))
 		goto out_valid;
 	d_drop(dentry);
-	if (dentry->d_parent->d_inode)
-		NFS_CACHEINV(dentry->d_parent->d_inode);
+	nfs_zap_caches(dir);
 	if (inode && S_ISDIR(inode->i_mode))
-		NFS_CACHEINV(inode);
+		nfs_zap_caches(inode);
 	return 0;
 }
 
@@ -611,33 +614,6 @@
 	}
 }
 
-__inline__ struct nfs_fh *nfs_fh_alloc(void)
-{
-	struct nfs_fh *p;
-
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return NULL;
-	memset(p, 0, sizeof(*p));
-	return p;
-}
-
-__inline__ void nfs_fh_free(struct nfs_fh *p)
-{
-	kfree(p);
-}
-
-/*
- * Called when the dentry is being freed to release private memory.
- */
-static void nfs_dentry_release(struct dentry *dentry)
-{
-	if (dentry->d_fsdata) {
-		nfs_fh_free(dentry->d_fsdata);
-		dentry->d_fsdata = NULL;
-	}
-}
-
 /*
  * Called when the dentry loses inode.
  * We use it to clean up silly-renamed files.
@@ -654,44 +630,33 @@
 	NULL,			/* d_hash */
 	NULL,			/* d_compare */
 	nfs_dentry_delete,	/* d_delete(struct dentry *) */
-	nfs_dentry_release,	/* d_release(struct dentry *) */
+	NULL,			/* d_release(struct dentry *) */
 	nfs_dentry_iput		/* d_iput */
 };
 
-static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
-	struct dentry *dir = dentry->d_parent;
 	struct inode *inode;
 	int error;
 	struct nfs_fh fhandle;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 
 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
-	if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
+	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
 		goto out;
 
 	dentry->d_op = &nfs_dentry_operations;
 
-	if (!dentry->d_fsdata) {
-		dentry->d_fsdata = nfs_fh_alloc();
-		if (!dentry->d_fsdata) {
-			error = -ENOMEM;
-			goto out;
-		}
-	}
-
 #if NFS_FIXME
 	inode = nfs_dircache_lookup(dir_i, dentry);
 	if (inode)
 		goto no_entry;
 #endif
 
-	error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
-				 &dentry->d_name, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
 	inode = NULL;
 	if (error == -ENOENT)
 		goto no_entry;
@@ -734,16 +699,15 @@
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
-	struct dentry	*dir = dentry->d_parent;
 	struct iattr	 attr;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 	struct nfs_fh	 fhandle;
 	int		 error;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 #ifdef NFSD_BROKEN_UID
 	/* We set uid/gid in the request because IBM's broken nfsd
@@ -767,10 +731,9 @@
 	 * select the appropriate create strategy. Currently open_namei
 	 * does not pass the create flags.
 	 */
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(create, dir_i, (dir, &dir_attr, &dentry->d_name,
-			&attr, 0, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
+					&attr, 0, &fhandle, &fattr);
 	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (error || fhandle.size == 0)
@@ -781,16 +744,15 @@
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
-	struct dentry	*dir = dentry->d_parent;
 	struct iattr	 attr;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 	struct nfs_fh	 fhandle;
 	int		 error;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 #ifdef NFSD_BROKEN_UID
 	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
@@ -803,10 +765,9 @@
 #endif
 
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(mknod, dir_i, (dir, &dir_attr, &dentry->d_name,
-				&attr, rdev, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name,
+				&attr, rdev, &fhandle, &fattr);
 	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (error || fhandle.size == 0)
@@ -817,16 +778,15 @@
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-	struct dentry   *dir = dentry->d_parent;
 	struct iattr	 attr;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 	struct nfs_fh	 fhandle;
 	int		 error;
 
 	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s)\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 #ifdef NFSD_BROKEN_UID
 	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
@@ -838,10 +798,8 @@
 	attr.ia_mode = mode | S_IFDIR;
 #endif
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(mkdir, dir_i, (dir, &dir_attr,
-				&dentry->d_name, &attr, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, &fattr);
 	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 
@@ -850,18 +808,15 @@
 	return error;
 }
 
-static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	struct dentry	*dir = dentry->d_parent;
-	struct nfs_fattr dir_attr;
 	int		 error;
 
 	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(rmdir, dir_i, (dir, &dir_attr, &dentry->d_name));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
 
 	/* Free the inode */
 	if (!error)
@@ -925,12 +880,10 @@
 	return sdentry;
 }
 
-static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 {
-	struct dentry	*dir = dentry->d_parent;
 	static unsigned int sillycounter = 0;
-	struct nfs_fattr dir_attr;
-	const int        i_inosize  = sizeof(dir_i->i_ino)*2;
+	const int        i_inosize  = sizeof(dir->i_ino)*2;
 	const int        countersize = sizeof(sillycounter)*2;
 	const int        slen       = strlen(".nfs") + i_inosize + countersize;
 	struct qstr      qsilly;
@@ -985,12 +938,10 @@
 			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
-	nfs_zap_caches(dir_i);
+	nfs_zap_caches(dir);
 	qsilly.name = silly;
 	qsilly.len  = strlen(silly);
-	error = NFS_CALL(rename, dir_i, (dir, &dir_attr, &dentry->d_name,
-				  dir, &dir_attr, &qsilly));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
 	if (!error) {
 		nfs_renew_times(dentry);
 		d_move(dentry, sdentry);
@@ -1011,9 +962,7 @@
  */
 static int nfs_safe_remove(struct dentry *dentry)
 {
-	struct nfs_fattr dir_attr;
-	struct dentry	*dir = dentry->d_parent;
-	struct inode	*dir_i = dir->d_inode,   
+	struct inode	*dir = dentry->d_parent->d_inode,
 			*inode = dentry->d_inode;
 	int		 error = 0, rehash = 0;
 		
@@ -1049,11 +998,10 @@
 		goto out;
 	}
 
-	nfs_zap_caches(dir_i);
+	nfs_zap_caches(dir);
 	if (inode)
 		NFS_CACHEINV(inode);
-	error = NFS_CALL(remove, dir_i, (dir, &dir_attr, &dentry->d_name));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
 	if (error < 0)
 		goto out;
 
@@ -1096,20 +1044,19 @@
 }
 
 static int
-nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
-	struct dentry	*dir = dentry->d_parent;
-	struct nfs_fattr dir_attr, sym_attr;
+	struct nfs_fattr sym_attr;
 	struct nfs_fh    sym_fh;
 	struct iattr     attr;
 	struct qstr      qsymname;
 	int              error, mode, maxlen;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
+		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
-	maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+	maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
 	if (strlen(symname) > maxlen)
 		goto out;
 
@@ -1137,11 +1084,9 @@
 	qsymname.name = symname;
 	qsymname.len  = strlen(symname);
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(symlink, dir_i, (dir, &dir_attr,
-				&dentry->d_name, &qsymname, &attr,
-				&sym_fh, &sym_attr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
+					&attr, &sym_fh, &sym_attr);
 	if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
 		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
 	} else {
@@ -1157,11 +1102,9 @@
 }
 
 static int 
-nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
-	struct dentry	*dir = dentry->d_parent;
 	struct inode	*inode = old_dentry->d_inode;
-	struct nfs_fattr old_attr, dir_attr;
 	int		 error;
 
 	dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
@@ -1174,12 +1117,9 @@
 	 * we can't use the existing dentry.
 	 */
 	d_drop(dentry);
-	nfs_zap_caches(dir_i);
+	nfs_zap_caches(dir);
 	NFS_CACHEINV(inode);
-	error = NFS_CALL(link, inode, (old_dentry, &old_attr,
-				       dir, &dir_attr, &dentry->d_name));
-	nfs_refresh_inode(inode, &old_attr);
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
 	return error;
 }
 
@@ -1214,7 +1154,6 @@
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		      struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct nfs_fattr old_attr, new_attr;
 	struct inode *   old_inode = old_dentry->d_inode;
 	struct inode *   new_inode = new_dentry->d_inode;
 	struct dentry *  dentry = NULL, *rehash = NULL;
@@ -1296,12 +1235,8 @@
 
 	nfs_zap_caches(new_dir);
 	nfs_zap_caches(old_dir);
-	error = NFS_CALL(rename, old_dir,
-			 (old_dentry->d_parent, &old_attr, &old_dentry->d_name,
-			  new_dentry->d_parent, &new_attr, &new_dentry->d_name));
-	nfs_refresh_inode(old_dir, &old_attr);
-	nfs_refresh_inode(new_dir, &new_attr);
-
+	error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
+			  		   new_dir, &new_dentry->d_name);
 out:
 	/* Update the dcache if needed */
 	if (rehash)
@@ -1315,14 +1250,11 @@
 }
 
 int
-nfs_permission(struct inode *i, int msk)
+nfs_permission(struct inode *inode, int mask)
 {
-	struct nfs_fattr	fattr;
-	struct dentry		*de = NULL;
-	int			err = vfs_permission(i, msk);
-	struct list_head	*start, *tmp;
+	int			error = vfs_permission(inode, mask);
 
-	if (!NFS_PROTO(i)->access)
+	if (!NFS_PROTO(inode)->access)
 		goto out;
 	/*
 	 * Trust UNIX mode bits except:
@@ -1332,28 +1264,18 @@
 	 * 3) When ACLs may overturn a negative answer */
 	if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH)
 	    && (current->fsuid != 0) && (current->fsgid != 0)
-	    && err != -EACCES)
+	    && error != -EACCES)
 		goto out;
 
-	tmp = start = &i->i_dentry;
-	while ((tmp = tmp->next) != start) {
-		de = list_entry(tmp, struct dentry, d_alias);
-		if (de->d_inode == i)
-			break;
-	}
-	if (!de || de->d_inode != i)
-		return 0;
+	error = NFS_PROTO(inode)->access(inode, mask, 0);
 
-	err = NFS_CALL(access, i, (de, msk, &fattr, 0));
-
-	if (err == -EACCES && NFS_CLIENT(i)->cl_droppriv &&
+	if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv &&
 	    current->uid != 0 && current->gid != 0 &&
 	    (current->fsuid != current->uid || current->fsgid != current->gid))
-		err = NFS_CALL(access, i, (de, msk, &fattr, 1));
+		error = NFS_PROTO(inode)->access(inode, mask, 1);
 
-	nfs_refresh_inode(i, &fattr);
  out:
-	return err;
+	return error;
 }
 
 /*
diff -urN linux-2.2.19-pre9/fs/nfs/file.c linux/fs/nfs/file.c
--- linux-2.2.19-pre9/fs/nfs/file.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/file.c	Mon Dec  3 21:01:23 2001
@@ -111,13 +111,14 @@
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
 	struct dentry * dentry = file->f_dentry;
+	struct inode  * inode = dentry->d_inode;
 	ssize_t result;
 
 	dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long) *ppos);
 
-	result = nfs_revalidate_inode(dentry);
+	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!result)
 		result = generic_file_read(file, buf, count, ppos);
 	return result;
@@ -127,12 +128,13 @@
 nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
 	int	status;
 
 	dfprintk(VFS, "nfs: mmap(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
-	status = nfs_revalidate_inode(dentry);
+	status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!status)
 		status = generic_file_mmap(file, vma);
 	return status;
@@ -182,10 +184,8 @@
 	rpages = NFS_SERVER(inode)->rpages;
 	result = nfs_pagein_inode(inode, index, rpages);
 	if (result < 0)
-		goto out_bad;
+		return result;
 	return 0;
- out_bad:
-	return result;
 }
 
 /* 
@@ -205,7 +205,7 @@
 	result = -EBUSY;
 	if (IS_SWAPFILE(inode))
 		goto out_swapfile;
-	result = nfs_revalidate_inode(dentry);
+	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (result)
 		goto out;
 
@@ -265,7 +265,9 @@
 	 * Flush all pending writes before doing anything
 	 * with locks..
 	 */
+	down(&inode->i_sem);
 	status = nfs_wb_all(inode);
+	up(&inode->i_sem);
 	if (status < 0)
 		goto out_unlock;
 
@@ -280,8 +282,10 @@
  out_unlock:
  out_ok:
 	if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) {
+		down(&inode->i_sem);
 		nfs_wb_all(inode);	/* we may have slept */
 		nfs_zap_caches(inode);
+		up(&inode->i_sem);
 	}
 	return status;
 }
diff -urN linux-2.2.19-pre9/fs/nfs/inode.c linux/fs/nfs/inode.c
--- linux-2.2.19-pre9/fs/nfs/inode.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/inode.c	Mon Dec  3 21:01:23 2001
@@ -40,11 +40,10 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define CONFIG_NFS_SNAPSHOT 1
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
-static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *);
 
 static void nfs_read_inode(struct inode *);
 static void nfs_put_inode(struct inode *);
@@ -53,8 +52,6 @@
 static void nfs_put_super(struct super_block *);
 static int  nfs_statfs(struct super_block *, struct statfs *, int);
 static void nfs_umount_begin(struct super_block *);
-static struct nfs_file *nfs_file_alloc(void);
-static void nfs_file_free(struct nfs_file *p);
 
 static struct super_operations nfs_sops = { 
 	nfs_read_inode,		/* read inode */
@@ -256,7 +253,7 @@
 		return NULL;
 	}
 
-	inode = __nfs_fhget(sb, &fattr);
+	inode = __nfs_fhget(sb, rootfh, &fattr);
 	return inode;
 }
 
@@ -273,9 +270,7 @@
 	struct nfs_server	*server;
 	struct rpc_xprt		*xprt = 0;
 	struct rpc_clnt		*clnt = 0;
-	struct nfs_fh		*root_fh = NULL,
-				*root = &data->root,
-				fh;
+	struct nfs_fh		fh;
 	struct inode		*root_inode = NULL;
 	unsigned int		authflavor;
 	struct sockaddr_in	srvaddr;
@@ -290,7 +285,6 @@
 		goto failure;
 	}
 
-	memset(&fh, 0, sizeof(fh));
 	if (data->version != NFS_MOUNT_VERSION) {
 		printk(KERN_WARNING "nfs warning: mount version %s than kernel\n",
 			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
@@ -298,12 +292,21 @@
 			data->namlen = 0;
 		if (data->version < 3)
 			data->bsize  = 0;
-		if (data->version < 4) {
+		if (data->version < 4)
 			data->flags &= ~NFS_MOUNT_VER3;
-			root = &fh;
-			root->size = NFS2_FHSIZE;
-			memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+	}
+
+	memset(&fh, 0, sizeof(fh));
+	if (data->version < 4) {
+		fh.size = NFS2_FHSIZE;
+		memcpy(fh.data, data->old_root.data, NFS2_FHSIZE);
+	} else {
+		fh.size = (data->flags & NFS_MOUNT_VER3) ? data->root.size : NFS2_FHSIZE;
+		if (fh.size > sizeof(fh.data)) {
+			printk(KERN_WARNING "NFS: mount program passes invalid filehandle!\n");
+			goto failure;
 		}
+		memcpy(fh.data, data->root.data, fh.size);
 	}
 
 	/* We now require that the mount process passes the remote address */
@@ -351,19 +354,15 @@
 	if (data->flags & NFS_MOUNT_VER3) {
 #ifdef CONFIG_NFS_V3
 		server->rpc_ops = &nfs_v3_clientops;
-		NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS3_FHSIZE;
+		NFS_SB_FHSIZE(sb) = NFS3_FHSIZE;
 		version = 3;
-		if (data->version < 4) {
-			printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
-			goto failure_unlock;
-		}
 #else
 		printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
 		goto failure_unlock;
 #endif
 	} else {
 		server->rpc_ops = &nfs_v2_clientops;
-		NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS2_FHSIZE;
+		NFS_SB_FHSIZE(sb) = NFS2_FHSIZE;
 		version = 2;
 	}
 
@@ -419,17 +418,12 @@
 	 * Keep the super block locked while we try to get 
 	 * the root fh attributes.
 	 */
-	root_fh = nfs_fh_alloc();
-	if (!root_fh)
-		goto out_no_fh;
-	memcpy((u8*)root_fh, (u8*)root, sizeof(*root_fh));
-
 	/* Did getting the root inode fail? */
-	if ((root->size > NFS_SB_FHSIZE(sb)
-	     || ! (root_inode = nfs_get_root(sb, root)))
+	if ((fh.size > NFS_SB_FHSIZE(sb)
+	     || ! (root_inode = nfs_get_root(sb, &fh)))
 	    && (data->flags & NFS_MOUNT_VER3)) {
 		data->flags &= ~NFS_MOUNT_VER3;
-		nfs_fh_free(root_fh);
+		fh.size = NFS2_FHSIZE;
 		rpciod_down();
 		rpc_shutdown_client(server->client);
 		goto nfsv3_try_again;
@@ -441,11 +435,9 @@
 		goto failure_put_root;
 
 	sb->s_root->d_op = &nfs_dentry_operations;
-	sb->s_root->d_fsdata = root_fh;
-	sb->u.nfs_sb.s_root = root_fh;
 
 	/* Get some general file system info */
-	if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
+	if (server->rpc_ops->statfs(server, &fh, &fsinfo) >= 0) {
 		if (server->namelen == 0)
 			server->namelen = fsinfo.namelen;
 	} else {
@@ -518,9 +510,6 @@
  failure_put_root:
 	if (root_inode)
 		iput(root_inode);
-	if (root_fh)
-		nfs_fh_free(root_fh);
- out_no_fh:
 	rpciod_down();
 
  failure_unlock:
@@ -552,7 +541,7 @@
 	struct nfs_fsinfo	res;
 	struct statfs		tmp;
 
-	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
+	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
 	if (error) {
 		printk(KERN_NOTICE "nfs_statfs: statfs error = %d\n", -error);
 		memset(&res, 0, sizeof(res));
@@ -590,46 +579,6 @@
 #endif
 
 /*
- * Free all unused dentries in an inode's alias list.
- *
- * Subtle note: we have to be very careful not to cause
- * any IO operations with the stale dentries, as this
- * could cause file corruption. But since the dentry
- * count is 0 and all pending IO for a dentry has been
- * flushed when the count went to 0, we're safe here.
- * Also returns the number of unhashed dentries
- */
-static int
-nfs_free_dentries(struct inode *inode)
-{
-	struct list_head *tmp, *head = &inode->i_dentry;
-	int unhashed;
-
-restart:
-	tmp = head->next;
-	unhashed = 0;
-	while (tmp != head) {
-		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-		dget(dentry);
-		if (!list_empty(&dentry->d_subdirs))
-			shrink_dcache_parent(dentry);
-		dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name,
-			dentry->d_count, !list_empty(&dentry->d_hash));
-		if (dentry->d_count == 1) {
-			d_drop(dentry);
-			dput(dentry);
-			goto restart;
-		}
-		if (list_empty(&dentry->d_hash))
-			unhashed++;
-		tmp = tmp->next;
-		dput(dentry);
-	}
-	return unhashed;
-}
-
-/*
  * Zap the caches.
  */
 void nfs_zap_caches(struct inode *inode)
@@ -657,7 +606,7 @@
  * Fill in inode information from the fattr.
  */
 static void
-nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
+nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
 	/*
 	 * Check whether the mode has been set, as we only want to
@@ -697,25 +646,15 @@
 		NFS_CACHE_ISIZE(inode) = fattr->size;
 		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+		memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
 	}
 	nfs_refresh_inode(inode, fattr);
 }
 
-static struct inode *
-nfs_make_new_inode(struct super_block *sb, struct nfs_fattr *fattr)
-{
-	struct inode *inode = get_empty_inode();
-
-	if (!inode)
-		return NULL;	
-	inode->i_sb = sb;
-	inode->i_dev = sb->s_dev;
-	inode->i_flags = 0;
-	inode->i_ino = nfs_fattr_to_ino_t(fattr);
-	nfs_read_inode(inode);
-	nfs_fill_inode(inode, fattr);
-	return inode;
-}
+struct nfs_find_desc {
+	struct nfs_fh		*fh;
+	struct nfs_fattr	*fattr;
+};
 
 /*
  * In NFSv3 we can have 64bit inode numbers. In order to support
@@ -726,50 +665,39 @@
 static int
 nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
 {
-	struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
+	struct nfs_fh		*fh = desc->fh;
+	struct nfs_fattr	*fattr = desc->fattr;
+
 	if (NFS_FSID(inode) != fattr->fsid)
 		return 0;
 	if (NFS_FILEID(inode) != fattr->fileid)
 		return 0;
-	if (inode->i_mode &&
-	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		return 0;
-	if (is_bad_inode(inode))
-		return 0;
-	if (NFS_FLAGS(inode) & NFS_INO_STALE)
+	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
 		return 0;
 	return 1;
 }
 
-static int
-nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
-	int unhashed;
-	int is_stale = 0;
 
-	if (inode->i_mode &&
-	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		is_stale = 1;
+	/* Empty inodes are not stale */
+	if (!inode->i_mode)
+		return 0;
 
-	if (is_bad_inode(inode))
-		is_stale = 1;
+	if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		return 1;
 
-	/*
-	 * If the inode seems stale, free up cached dentries.
-	 */
-	unhashed = nfs_free_dentries(inode);
+	if (is_bad_inode(inode))
+		return 1;
 
-	/* Assume we're holding an i_count
-	 *
-	 * NB: sockets sometimes have volatile file handles
-	 *     don't invalidate their inodes even if all dentries are
-	 *     unhashed.
-	 */
-	if (unhashed && inode->i_count == unhashed + 1
-	    && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
-		is_stale = 1;
+	/* Has the filehandle changed? If so is the old one stale? */
+	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
+	    __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
+		return 1;
 
-	return is_stale;
+	return 0;
 }
 
 /*
@@ -778,8 +706,6 @@
  * the vfs read_inode function because there is no way to pass the
  * file handle or current attributes into the read_inode function.
  *
- * We provide a special check for NetApp .snapshot directories to avoid
- * inode aliasing problems. All snapshot inodes are anonymous (unhashed).
  */
 struct inode *
 nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
@@ -791,40 +717,16 @@
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(long long) fattr->fileid);
 
-	/* Install the file handle in the dentry */
-	memcpy(NFS_FH(dentry), (u8*)fhandle, sizeof(*fhandle));
-
-#ifdef CONFIG_NFS_SNAPSHOT
-	/*
-	 * Check for NetApp snapshot dentries, and get an 
-	 * unhashed inode to avoid aliasing problems.
-	 */
-	if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
-	    (dentry->d_name.len == 9 &&
-	     memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
-		struct inode *inode = nfs_make_new_inode(sb, fattr);
-		if (!inode)
-			goto out;
-		inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
-		dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
-	out:
-		return inode;
-	}
-#endif
-	return __nfs_fhget(sb, fattr);
+	return __nfs_fhget(sb, fhandle, fattr);
 }
 
 /*
  * Look up the inode by super block and fattr->fileid.
- *
- * Note carefully the special handling of busy inodes (i_count > 1).
- * With the kernel 2.1.xx dcache all inodes except hard links must
- * have i_count == 1 after iget(). Otherwise, it indicates that the
- * server has reused a fileid (i_ino) and we have a stale inode.
  */
 static struct inode *
-__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
+__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+	struct nfs_find_desc desc = { fh, fattr };
 	struct inode	*inode = NULL;
 	unsigned long	ino;
 
@@ -833,34 +735,12 @@
 
 	ino = nfs_fattr_to_ino_t(fattr);
 
-	while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
-
-		/*
-		 * Check for busy inodes, and attempt to get rid of any
-		 * unused local references. If successful, we release the
-		 * inode and try again.
-		 *
-		 * Note that the busy test uses the values in the fattr,
-		 * as the inode may have become a different object.
-		 * (We can probably handle modes changes here, too.)
-		 */
-		if (!nfs_inode_is_stale(inode,fattr))
-			break;
-
-		dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-		       inode->i_ino, inode->i_count);
-		/* Mark the inode as being stale */
-		NFS_FLAGS(inode) |= NFS_INO_STALE;
-		nfs_zap_caches(inode);
-		iput(inode);
-	}
-
-	if (!inode)
+	if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
 		goto out_no_inode;
 
-	nfs_fill_inode(inode, fattr);
-	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
-		inode->i_dev, inode->i_ino, inode->i_count);
+	nfs_fill_inode(inode, fh, fattr);
+	dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode), inode->i_count);
 
 out:
 	return inode;
@@ -896,7 +776,7 @@
 		goto out;
 
 	/* Now perform the setattr call */
-	error = NFS_CALL(setattr, inode, (dentry, &fattr, attr));
+	error = NFS_PROTO(inode)->setattr(inode, &fattr, attr);
 	if (error || !(fattr.valid & NFS_ATTR_FATTR)) {
 		nfs_zap_caches(inode);
 		goto out;
@@ -954,52 +834,27 @@
 int
 nfs_revalidate(struct dentry *dentry)
 {
-	return nfs_revalidate_inode(dentry);
-}
-
-static __inline__ struct nfs_file *nfs_file_alloc(void)
-{
-	struct nfs_file	*p;
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
-	if (p) {
-		memset(p, 0, sizeof(*p));
-		p->magic = NFS_FILE_MAGIC;
-	}
-	return p;
-}
-
-static __inline__ void nfs_file_free(struct nfs_file *p)
-{
-	if (p->magic == NFS_FILE_MAGIC) {
-		p->magic = 0;
-		kfree(p);
-	} else
-		printk(KERN_ERR "NFS: extra file info corrupted!\n");
+	struct inode *inode = dentry->d_inode;
+	return nfs_revalidate_inode(NFS_SERVER(inode), inode);
 }
 
 int nfs_open(struct inode *inode, struct file *filp)
 {
 	struct rpc_auth	*auth = NFS_CLIENT(inode)->cl_auth;
-	struct nfs_file	*data;
+	struct rpc_cred	*cred = rpcauth_lookupcred(auth, 0);
 
-	data = nfs_file_alloc();
-	if (!data)
-		return -ENOMEM;
-	data->cred = rpcauth_lookupcred(auth, 0);
-	filp->private_data = data;
+	filp->private_data = cred;
 	return 0;
 }
 
 int nfs_release(struct inode *inode, struct file *filp)
 {
-	struct nfs_file	*data = NFS_FILE(filp);
 	struct rpc_auth	*auth = NFS_CLIENT(inode)->cl_auth;
 	struct rpc_cred	*cred;
 
 	cred = nfs_file_cred(filp);
 	if (cred)
 		rpcauth_releasecred(auth, cred);
-	nfs_file_free(data);
 	return 0;
 }
 
@@ -1008,17 +863,15 @@
  * the cached attributes have to be refreshed.
  */
 int
-__nfs_revalidate_inode(struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	struct inode	*inode = dentry->d_inode;
 	struct nfs_fattr fattr;
 	int		 status = 0;
 
-	dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
-		inode->i_ino);
+	dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode));
 
-	if (!inode || is_bad_inode(inode))
+	if (!inode || is_bad_inode(inode) || NFS_STALE(inode))
 		return -ESTALE;
 
 	while (NFS_REVALIDATING(inode)) {
@@ -1026,58 +879,30 @@
 		if (status < 0)
 			return status;
 		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-			return 0;
+			return NFS_STALE(inode) ? -ESTALE : 0;
 	}
 	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
-	status = NFS_CALL(getattr, inode, (dentry, &fattr));
+	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
-		int error;
-		u32 *fh;
-		struct dentry *dir = dentry->d_parent;
-		struct nfs_fh fhandle;
-		struct nfs_fattr dir_attr;
-
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-		       dentry->d_parent->d_name.name, dentry->d_name.name,
-		       inode->i_ino, status);
-		nfs_zap_caches(inode);
-
-		if (status != -ESTALE)
-			goto out;
-
-		/*
-		 * A "stale filehandle" error ... show the current fh
-		 * and find out what the filehandle should be.
-		 */
-		fh = (u32 *) NFS_FH(dentry);
-		dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
-			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		error = NFS_CALL(lookup, dir->d_inode, (dir, &dir_attr, 
-					&dentry->d_name, &fhandle, &fattr));
-		nfs_refresh_inode(dir->d_inode, &dir_attr);
-		if (error) {
-			dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
-			goto out;
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
+			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		if (status == -ESTALE) {
+			NFS_FLAGS(inode) |= NFS_INO_STALE;
+			remove_inode_hash(inode);
 		}
-		fh = (u32 *) &fhandle;
-		dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
-			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		if (!IS_ROOT(dentry) && !have_submounts(dentry))
-			d_drop(dentry);
 		goto out;
 	}
 
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-			 dentry->d_parent->d_name.name, dentry->d_name.name,
-			 inode->i_ino, status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
+			 inode->i_dev, (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
+	dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
+		 inode->i_dev, (long long)NFS_FILEID(inode));
 
-	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
 out:
 	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
 	wake_up(&inode->i_wait);
diff -urN linux-2.2.19-pre9/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c
--- linux-2.2.19-pre9/fs/nfs/mount_clnt.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/mount_clnt.c	Mon Dec  3 21:01:23 2001
@@ -33,23 +33,23 @@
  */
 
 static int			nfs_gen_mount(struct sockaddr_in *, char *,
-					      struct nfs_fh *, int);
+					      struct nfs3_fh *, int);
 static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *, int);
 extern struct rpc_program	mnt_program;
 
 struct mnt_fhstatus {
 	unsigned int		status;
-	struct nfs_fh *		fh;
+	struct nfs3_fh *	fh;
 };
 
 int
-nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+nfs_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh)
 {
 	return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
 }
 
 int
-nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh)
 {
 	return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
 }
@@ -58,7 +58,7 @@
  * Obtain an NFS file handle for the given host and path
  */
 static int
-nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
+nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh, int version)
 {
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = { 0, fh };
@@ -122,7 +122,7 @@
 static int
 xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	struct nfs_fh *fh = res->fh;
+	struct nfs3_fh	*fh = res->fh;
 
 	memset((void *)fh, 0, sizeof(*fh));
 	if ((res->status = ntohl(*p++)) == 0) {
@@ -135,7 +135,7 @@
 static int
 xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	struct nfs_fh *fh = res->fh;
+	struct nfs3_fh	*fh = res->fh;
 
 	memset((void *)fh, 0, sizeof(*fh));
 	if ((res->status = ntohl(*p++)) == 0) {
diff -urN linux-2.2.19-pre9/fs/nfs/nfs3proc.c linux/fs/nfs/nfs3proc.c
--- linux-2.2.19-pre9/fs/nfs/nfs3proc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/nfs3proc.c	Mon Dec  3 21:01:23 2001
@@ -46,65 +46,67 @@
  * One function for each procedure in the NFS protocol.
  */
 static int
-nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+nfs3_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
 {
 	int	status;
 
 	dprintk("NFS call  getattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR,
-			  NFS_FH(dentry), fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_GETATTR,
+			  NFS_FH(inode), fattr, 0);
 	dprintk("NFS reply getattr\n");
 	return status;
 }
 
 static int
-nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+nfs3_proc_setattr(struct inode *inode, struct nfs_fattr *fattr,
 			struct iattr *sattr)
 {
-	struct nfs3_sattrargs	arg = { NFS_FH(dentry), sattr, 0, 0 };
+	struct nfs3_sattrargs	arg = { NFS_FH(inode), sattr, 0, 0 };
 	int	status;
 
 	dprintk("NFS call  setattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0);
 	dprintk("NFS reply setattr\n");
 	return status;
 }
 
 static int
-nfs3_proc_lookup(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name,
+nfs3_proc_lookup(struct inode *dir, struct qstr *name,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  lookup %s\n", name->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0);
 	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
-		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR,
+		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR,
 			 fhandle, fattr, 0);
 	dprintk("NFS reply lookup: %d\n", status);
+	nfs_refresh_inode(dir, &dir_attr);
 	return status;
 }
 
 static int
-nfs3_proc_access(struct dentry *dentry, int mode, struct nfs_fattr *fattr, int ruid)
+nfs3_proc_access(struct inode *inode, int mode, int ruid)
 {
-	struct nfs3_accessargs	arg = { NFS_FH(dentry), 0 };
-	struct nfs3_accessres	res = { fattr, 0 };
+	struct nfs_fattr	fattr;
+	struct nfs3_accessargs	arg = { NFS_FH(inode), 0 };
+	struct nfs3_accessres	res = { &fattr, 0 };
 	int	status, flags;
 
 	dprintk("NFS call  access\n");
-	fattr->valid = 0;
+	fattr.valid = 0;
 
 	if (mode & MAY_READ)
 		arg.access |= NFS3_ACCESS_READ;
-	if (S_ISDIR(dentry->d_inode->i_mode)) {
+	if (S_ISDIR(inode->i_mode)) {
 		if (mode & MAY_WRITE)
 			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
 		if (mode & MAY_EXEC)
@@ -116,7 +118,7 @@
 			arg.access |= NFS3_ACCESS_EXECUTE;
 	}
 	flags = (ruid) ? RPC_CALL_REALUID : 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags);
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags);
 	dprintk("NFS reply access\n");
 
 	if (status == 0 && (arg.access & res.access) != arg.access)
@@ -125,28 +127,28 @@
 }
 
 static int
-nfs3_proc_readlink(struct dentry *dentry, struct nfs_fattr *fattr,
-			void *buffer, unsigned int buflen)
+nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen)
 {
-	struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen };
-	struct nfs3_readlinkres	res = { fattr, buffer, buflen };
+	struct nfs_fattr	fattr;
+	struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen };
+	struct nfs3_readlinkres	res = { &fattr, buffer, buflen };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK,
+	fattr.valid = 0;
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
 					&args, &res, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr,
-	       struct rpc_cred *cred, int flags,
+nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
+	       struct nfs_fattr *fattr, int flags,
 	       unsigned long offset, unsigned int count,
 	       void *buffer, int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
 					{{buffer, count}, {0,0}, {0,0}, {0,0},
 					 {0,0}, {0,0}, {0,0}, {0,0}} };
 	struct nfs_readres	res = { fattr, count, 0 };
@@ -155,19 +157,19 @@
 
 	dprintk("NFS call  read %d @ %ld\n", count, offset);
 	fattr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 	dprintk("NFS reply read: %d\n", status);
 	*eofp = res.eof;
 	return status;
 }
 
 static int
-nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr,
-		struct rpc_cred *cred, int flags,
+nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
+		struct nfs_fattr *fattr, int flags,
 		unsigned long offset, unsigned int count,
 		void *buffer, struct nfs_writeverf *verf)
 {
-	struct nfs_writeargs	arg = { NFS_FH(dentry), offset, count,
+	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count,
 					NFS_FILE_SYNC, 1,
 					{{buffer, count}, {0,0}, {0,0}, {0,0},
 					 {0,0}, {0,0}, {0,0}, {0,0}} };
@@ -181,7 +183,7 @@
 		rpcflags |= NFS_RPC_SWAPFLAGS;
 	arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
 
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
 
 	dprintk("NFS reply read: %d\n", status);
 	return status < 0? status : res.count;
@@ -192,17 +194,17 @@
  * For now, we don't implement O_EXCL.
  */
 static int
-nfs3_proc_create(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct iattr *sattr, int flags,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs3_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
+		 int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
 					sattr, 0, { 0, 0 } };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  create %s\n", name->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
 
 	arg.createmode = NFS3_CREATE_UNCHECKED;
@@ -213,7 +215,8 @@
 	}
 
 again:
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 
 	/* If the server doesn't support the exclusive creation semantics,
 	 * try again with simple 'guarded' mode. */
@@ -246,7 +249,7 @@
 		 * not sure this buys us anything (and I'd have
 		 * to revamp the NFSv3 XDR code) */
 		fattr->valid = 0;
-		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR,
+		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR,
 						&arg, fattr, 0);
 		dprintk("NFS reply setattr (post-create): %d\n", status);
 	}
@@ -255,16 +258,17 @@
 }
 
 static int
-nfs3_proc_remove(struct dentry *dir, struct nfs_fattr *dir_attr,
-				struct qstr *name)
+nfs3_proc_remove(struct inode *dir, struct qstr *name)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
-	struct rpc_message	msg = {NFS3PROC_REMOVE, &arg, dir_attr, NULL };
+	struct rpc_message	msg = {NFS3PROC_REMOVE, &arg, &dir_attr, NULL };
 	int			status;
 
 	dprintk("NFS call  remove %s\n", name->name);
-	dir_attr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	dir_attr.valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
 }
@@ -281,7 +285,7 @@
 		return -ENOMEM;
 	memset(arg, 0, size);
 	res = (struct nfs_fattr*)(arg + 1);
-	arg->fh = NFS_FH(dir);
+	arg->fh = NFS_FH(dir->d_inode);
 	arg->name = name->name;
 	arg->len = name->len;
 	msg->rpc_proc = NFS3PROC_REMOVE;
@@ -303,91 +307,96 @@
 
 
 static int
-nfs3_proc_rename(struct dentry *old_dir, struct nfs_fattr *old_attr,
-			struct qstr *old_name,
-			struct dentry *new_dir, struct nfs_fattr *new_attr,
-			struct qstr *new_name)
+nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
+			struct inode *new_dir, struct qstr *new_name)
 {
+	struct nfs_fattr	old_dir_attr, new_dir_attr;
 	struct nfs3_renameargs	arg = { NFS_FH(old_dir),
 					old_name->name, old_name->len,
 					NFS_FH(new_dir),
 					new_name->name, new_name->len };
-	struct nfs3_renameres	res = { old_attr, new_attr };
+	struct nfs3_renameres	res = { &old_dir_attr, &new_dir_attr };
 	int			status;
 
 	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
-	old_attr->valid = 0;
-	new_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0);
+	old_dir_attr.valid = 0;
+	new_dir_attr.valid = 0;
+	status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0);
+	nfs_refresh_inode(old_dir, &old_dir_attr);
+	nfs_refresh_inode(new_dir, &new_dir_attr);
 	dprintk("NFS reply rename: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_link(struct dentry *dentry, struct nfs_fattr *fattr,
-			struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name)
+nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
-	struct nfs3_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+	struct nfs_fattr	dir_attr, fattr;
+	struct nfs3_linkargs	arg = { NFS_FH(inode), NFS_FH(dir),
 					name->name, name->len };
-	struct nfs3_linkres	res = { dir_attr, fattr };
+	struct nfs3_linkres	res = { &dir_attr, &fattr };
 	int			status;
 
 	dprintk("NFS call  link %s\n", name->name);
-	dir_attr->valid = 0;
-	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0);
+	dir_attr.valid = 0;
+	fattr.valid = 0;
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
+	nfs_refresh_inode(inode, &fattr);
 	dprintk("NFS reply link: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_symlink(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct qstr *path,
-			struct iattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
+			struct iattr *sattr, struct nfs_fh *fhandle,
+			struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
 					path->name, path->len, sattr };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_mkdir(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct iattr *sattr,
+nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
 					sattr, 0, { 0, 0 } };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  mkdir %s\n", name->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_rmdir(struct dentry *dir, struct nfs_fattr *dir_attr,
-				struct qstr *name)
+nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	int			status;
 
 	dprintk("NFS call  rmdir %s\n", name->name);
-	dir_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, dir_attr, 0);
+	dir_attr.valid = 0;
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply rmdir: %d\n", status);
 	return status;
 }
@@ -402,14 +411,14 @@
  * readdirplus.
  */
 static int
-nfs3_proc_readdir(struct dentry *dir, struct nfs_fattr *dir_attr,
-		  struct rpc_cred *cred,
+nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
 		  u64 cookie, void *entry, unsigned int size, int plus)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
-	struct nfs3_readdirres	res = { dir_attr, 0, 0, 0, 0 };
+	struct nfs3_readdirres	res = { &dir_attr, 0, 0, 0, 0 };
 	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
-	u32			*verf = NFS_COOKIEVERF(dir->d_inode);
+	u32			*verf = NFS_COOKIEVERF(dir);
 	int			status;
 
 	arg.buffer  = entry;
@@ -428,20 +437,21 @@
 	dprintk("NFS call  readdir%s %d\n",
 			plus? "plus" : "", (unsigned int) cookie);
 
-	dir_attr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	dir_attr.valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply readdir: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_mknod(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct iattr *sattr,
+nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
 			dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_mknodargs	arg = { NFS_FH(dir), name->name, name->len, 0,
 					sattr, rdev };
-	struct nfs3_diropres	res = { dir_attr, fh, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fh, fattr };
 	int			status;
 
 	switch (sattr->ia_mode & S_IFMT) {
@@ -453,9 +463,10 @@
 	}
 
 	dprintk("NFS call  mknod %s %x\n", name->name, rdev);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
diff -urN linux-2.2.19-pre9/fs/nfs/proc.c linux/fs/nfs/proc.c
--- linux-2.2.19-pre9/fs/nfs/proc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/proc.c	Mon Dec  3 21:01:23 2001
@@ -77,34 +77,34 @@
  * One function for each procedure in the NFS protocol.
  */
 static int
-nfs_proc_getattr(struct dentry *dentry, fattr *fattr)
+nfs_proc_getattr(struct inode *inode, fattr *fattr)
 {
 	int	status;
 
 	dprintk("NFS call  getattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR,
-				NFS_FH(dentry), fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_GETATTR,
+				NFS_FH(inode), fattr, 0);
 	dprintk("NFS reply getattr\n");
 	return status;
 }
 
 static int
-nfs_proc_setattr(struct dentry *dentry, fattr *fattr,
+nfs_proc_setattr(struct inode *inode, fattr *fattr,
 				struct iattr *sattr)
 {
-	struct nfs_sattrargs	arg = { NFS_FH(dentry), sattr };
+	struct nfs_sattrargs	arg = { NFS_FH(inode), sattr };
 	int	status;
 
 	dprintk("NFS call  setattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0);
 	dprintk("NFS reply setattr\n");
 	return status;
 }
 
 static int
-nfs_proc_lookup(struct dentry *dir, fattr *dir_attr, qstr *name,
+nfs_proc_lookup(struct inode *dir, qstr *name,
 		struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
@@ -112,36 +112,32 @@
 	int			status;
 
 	dprintk("NFS call  lookup %s\n", name->name);
-	dir_attr->valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0);
 	dprintk("NFS reply lookup: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_readlink(struct dentry *dentry, fattr *fattr,
-			void *buffer, unsigned int bufsiz)
+nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz)
 {
-	struct nfs_readlinkargs	args = { NFS_FH(dentry), buffer, bufsiz };
+	struct nfs_readlinkargs	args = { NFS_FH(inode), buffer, bufsiz };
 	struct nfs_readlinkres	res = { buffer, bufsiz };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
 					&args, &res, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_read(struct dentry *dentry, fattr *fattr,
-	      struct rpc_cred *cred, int flags,
-	      unsigned long offset, unsigned int count,
+nfs_proc_read(struct inode *inode, struct rpc_cred *cred, fattr *fattr,
+	      int flags, unsigned long offset, unsigned int count,
 	      void *buffer, int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
 				       {{ buffer, count }, {0,0}, {0,0}, {0,0},
 					{0,0}, {0,0}, {0,0}, {0,0}} };
 	struct nfs_readres	res = { fattr, count, 0};
@@ -150,7 +146,7 @@
 
 	dprintk("NFS call  read %d @ %ld\n", count, offset);
 	fattr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 
 	dprintk("NFS reply read: %d\n", status);
 	*eofp = res.eof;
@@ -158,12 +154,11 @@
 }
 
 static int
-nfs_proc_write(struct dentry *dentry, fattr *fattr,
-	       struct rpc_cred *cred, int how,
-	       unsigned long offset, unsigned int count,
+nfs_proc_write(struct inode *inode, struct rpc_cred *cred, fattr *fattr,
+	       int how, unsigned long offset, unsigned int count,
 	       void *buffer, struct nfs_writeverf *verf)
 {
-	struct nfs_writeargs	arg = {NFS_FH(dentry), offset, count,
+	struct nfs_writeargs	arg = {NFS_FH(inode), offset, count,
 					NFS_FILE_SYNC, 1,
 					{{buffer, count}, {0,0}, {0,0}, {0,0},
 					 {0,0}, {0,0}, {0,0}, {0,0}}};
@@ -175,7 +170,7 @@
 	fattr->valid = 0;
 	if (how & NFS_RW_SWAP)
 		flags |= NFS_RPC_SWAPFLAGS;
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 
 	dprintk("NFS reply write: %d\n", status);
 	verf->committed = NFS_FILE_SYNC;      /* NFSv2 always syncs data */
@@ -183,8 +178,7 @@
 }
 
 static int
-nfs_proc_create(struct dentry *dir, fattr *dir_attr,
-		qstr *name, struct iattr *sattr, int flags,
+nfs_proc_create(struct inode *dir, qstr *name, struct iattr *sattr, int flags,
 		struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
@@ -192,10 +186,9 @@
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dir_attr->valid = 0;
 	fattr->valid = 0;
 	dprintk("NFS call  create %s\n", name->name);
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 	dprintk("NFS reply create: %d\n", status);
 	return status;
 }
@@ -204,8 +197,7 @@
  * In NFSv2, mknod is grafted onto the create call.
  */
 static int
-nfs_proc_mknod(struct dentry *dir, fattr *dir_attr,
-			qstr *name, struct iattr *sattr, dev_t rdev,
+nfs_proc_mknod(struct inode *dir, qstr *name, struct iattr *sattr, dev_t rdev,
 			struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
@@ -224,30 +216,27 @@
 		sattr->ia_size   = rdev;	/* get out your barf bag */
 	}
 
-	dir_attr->valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 
 	if (status == -EINVAL && S_ISFIFO(mode)) {
 		sattr->ia_mode = mode;
-		dir_attr->valid = 0;
 		fattr->valid = 0;
-		status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+		status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 	}
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
   
 static int
-nfs_proc_remove(struct dentry *dir, fattr *dir_attr, qstr *name)
+nfs_proc_remove(struct inode *dir, qstr *name)
 {
 	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	struct rpc_message	msg = { NFSPROC_REMOVE, &arg, NULL, NULL };
 	int			status;
 
-	dir_attr->valid = 0;
 	dprintk("NFS call  remove %s\n", name->name);
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
@@ -262,7 +251,7 @@
 	if (!arg)
 		return -ENOMEM;
 	memset(arg, 0, sizeof(*arg));
-	arg->fh = NFS_FH(dir);
+	arg->fh = NFS_FH(dir->d_inode);
 	arg->name = name->name;
 	arg->len = name->len;
 	msg->rpc_proc = NFSPROC_REMOVE;
@@ -280,8 +269,8 @@
 }
 
 static int
-nfs_proc_rename(struct dentry *old_dir, fattr *old_attr, qstr *old_name,
-		struct dentry *new_dir, fattr *new_attr, qstr *new_name)
+nfs_proc_rename(struct inode *old_dir, qstr *old_name,
+		struct inode *new_dir, qstr *new_name)
 {
 	struct nfs_renameargs	arg = { NFS_FH(old_dir), old_name->name,
 					old_name->len,
@@ -290,32 +279,26 @@
 	int			status;
 
 	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
-	old_attr->valid = 0;
-	new_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0);
 	dprintk("NFS reply rename: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_link(struct dentry *dentry, fattr *attr,
-	      struct dentry *dir, fattr *dir_attr, qstr *name)
+nfs_proc_link(struct inode *inode, struct inode *dir, qstr *name)
 {
-	struct nfs_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+	struct nfs_linkargs	arg = { NFS_FH(inode), NFS_FH(dir),
 					name->name, name->len };
 	int			status;
 
 	dprintk("NFS call  link %s\n", name->name);
-	dir_attr->valid = 0;
-	attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0);
 	dprintk("NFS reply link: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_symlink(struct dentry *dir, fattr *dir_attr, qstr *name,
-		 qstr *path, struct iattr *sattr,
+nfs_proc_symlink(struct inode *dir, qstr *name, qstr *path, struct iattr *sattr,
 		 struct nfs_fh *sym_fh, fattr *sym_attr)
 {
 	struct nfs_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
@@ -323,16 +306,14 @@
 	int			status;
 
 	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
-	dir_attr->valid = 0;
 	sym_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_mkdir(struct dentry *dir, fattr *dir_attr, qstr *name,
-	       struct iattr *sattr,
+nfs_proc_mkdir(struct inode *dir, qstr *name, struct iattr *sattr,
 	       struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_createargs	arg = { NFS_FH(dir), name->name, name->len,
@@ -341,22 +322,20 @@
 	int			status;
 
 	dprintk("NFS call  mkdir %s\n", name->name);
-	dir_attr->valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_rmdir(struct dentry *dir, fattr *dir_attr, qstr *name)
+nfs_proc_rmdir(struct inode *dir, qstr *name)
 {
 	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	int			status;
 
 	dprintk("NFS call  rmdir %s\n", name->name);
-	dir_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0);
 	dprintk("NFS reply rmdir: %d\n", status);
 	return status;
 }
@@ -369,8 +348,7 @@
  * from nfs_readdir by calling the decode_entry function directly.
  */
 static int
-nfs_proc_readdir(struct dentry *dir, fattr *dir_attr,
-		 struct rpc_cred *cred,
+nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
 		 __u64 cookie, void *entry, unsigned int size, int plus)
 {
 	struct nfs_readdirargs	arg;
@@ -378,7 +356,6 @@
 	struct rpc_message	msg = { NFSPROC_READDIR, &arg, &res, cred };
 	int			status;
 
-	dir_attr->valid = 0;
 	arg.fh = NFS_FH(dir);
 	arg.cookie = cookie;
 	arg.buffer = entry;
@@ -386,9 +363,8 @@
 	res.buffer = entry;
 	res.bufsiz = size;
 
-	dir_attr->valid = 0;
 	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
 	dprintk("NFS reply readdir: %d\n", status);
 	return status;
diff -urN linux-2.2.19-pre9/fs/nfs/read.c linux/fs/nfs/read.c
--- linux-2.2.19-pre9/fs/nfs/read.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/read.c	Mon Dec  3 21:01:23 2001
@@ -42,7 +42,7 @@
 
 struct nfs_read_data {
 	struct rpc_task		task;
-	struct dentry		*dentry;
+	struct inode		*inode;
 	struct rpc_cred		*cred;
 	struct nfs_readargs	args;	/* XDR argument struct */
 	struct nfs_readres	res;	/* ... and result struct */
@@ -87,11 +87,9 @@
  * Read a page synchronously.
  */
 static int
-nfs_readpage_sync(struct file *file, struct page *page)
+nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-	struct rpc_cred	*cred = nfs_file_cred(file);
+	struct rpc_cred	*cred = NULL;
 	struct nfs_fattr fattr;
 	unsigned long	offset = nfs_page_offset(page);
 	char		*buffer = (char *) page_address(page);
@@ -104,19 +102,23 @@
 		flags |= NFS_RPC_SWAPFLAGS;
 
 	dprintk("NFS: nfs_readpage_sync(%p)\n", page);
+
+	if (file)
+		cred = nfs_file_cred(file);
+
 	clear_bit(PG_error, &page->flags);
 
 	do {
 		if ((chunk = rsize) > count)
 			chunk = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %ld, %d, %p)\n",
 			NFS_SERVER(inode)->hostname,
-			dentry->d_parent->d_name.name, dentry->d_name.name,
+			inode->i_dev, (long long)NFS_FILEID(inode),
 			offset, chunk, buffer);
 
-		result = NFS_CALL(read, inode, (dentry, &fattr, cred, flags,
-						offset, chunk, buffer, &eof));
+		result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
+						offset, chunk, buffer, &eof);
 		nfs_refresh_inode(inode, &fattr);
 
 		/*
@@ -180,7 +182,7 @@
 static inline void
 nfs_mark_request_read(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	if (list_empty(&req->wb_list)) {
 		nfs_list_add_request(req, &inode->u.nfs_i.read);
@@ -190,9 +192,8 @@
 }
 
 static int
-nfs_readpage_async(struct file *file, struct page *page)
+nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
 {
-	struct inode	*inode = file->f_dentry->d_inode;
 	struct nfs_page	*req, *new = NULL;
 	int		result;
 
@@ -222,7 +223,7 @@
 		}
 
 		result = -ENOMEM;
-		new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE);
+		new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
 		if (!new)
 			break;
 	}
@@ -258,9 +259,9 @@
 		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->dentry	  = req->wb_dentry;
+	data->inode	  = req->wb_inode;
 	data->cred	  = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_dentry);
+	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = nfs_page_offset(req->wb_page) + req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
@@ -286,9 +287,8 @@
 }
 
 static int
-nfs_pagein_one(struct list_head *head, struct dentry *dentry)
+nfs_pagein_one(struct list_head *head, struct inode *inode)
 {
-	struct inode		*inode = dentry->d_inode;
 	struct rpc_task		*task;
 	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
 	struct nfs_read_data	*data;
@@ -322,9 +322,9 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
 		task->tk_pid,
-		dentry->d_parent->d_name.name, dentry->d_name.name,
+		inode->i_dev, (long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -349,7 +349,7 @@
 	while (!list_empty(head)) {
 		pages += nfs_coalesce_requests(head, &one_request, rpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_pagein_one(&one_request, req->wb_dentry);
+		error = nfs_pagein_one(&one_request, req->wb_inode);
 		if (error < 0)
 			break;
 	}
@@ -419,8 +419,7 @@
 nfs_readpage_result(struct rpc_task *task)
 {
 	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 	int			count = data->res.count;
 
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
@@ -440,9 +439,9 @@
 			set_bit(PG_error, &page->flags);
 		nfs_unlock_page(page);
 
-		dprintk("NFS: read (%s/%s %d@%ld)\n",
-                        req->wb_dentry->d_parent->d_name.name,
-                        req->wb_dentry->d_name.name,
+		dprintk("NFS: read (%x/%Ld %d@%ld)\n",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
                         req->wb_bytes,
                         (nfs_page_offset(page) + req->wb_offset));
 		nfs_unlock_request(req);
@@ -465,16 +464,19 @@
 int
 nfs_readpage(struct file *file, struct page *page)
 {
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	int		error = 0,
-			rsize = NFS_SERVER(inode)->rsize;
+	struct inode *inode;
+	int		error = 0;
 
 	while (!nfs_lock_page(page))
 		wait_on_page(page);
 
-	dprintk("NFS: nfs_readpage (%p %d@%ld)\n",
-		page, rsize, page->offset);
+	if (!file)
+		inode = page->inode;
+	else
+		inode = file->f_dentry->d_inode;
+
+	dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
+		page, PAGE_CACHE_SIZE, page->offset);
 
 	/*
 	 * Try to flush any pending writes to the file
@@ -484,13 +486,13 @@
 		goto out_unlock;
 
 	error = -1;
-	if (!IS_SWAPFILE(inode) && !PageError(page) && rsize >= PAGE_CACHE_SIZE)
-		error = nfs_readpage_async(file, page);
+	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
+		error = nfs_readpage_async(file, inode, page);
 
 	if (error >= 0)
 		goto out;
 
-	error = nfs_readpage_sync(file, page);
+	error = nfs_readpage_sync(file, inode, page);
 	if (error < 0 && IS_SWAPFILE(inode))
 		printk(KERN_ERR "Aiee.. nfs swap-in of page failed!\n");
 
diff -urN linux-2.2.19-pre9/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- linux-2.2.19-pre9/fs/nfs/symlink.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/symlink.c	Mon Dec  3 21:01:23 2001
@@ -57,19 +57,16 @@
 /* Symlink caching in the page cache is even more simplistic
  * and straight-forward than readdir caching.
  */
-static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
+static int nfs_symlink_filler(struct inode *inode, struct page *page)
 {
-	struct inode *inode = dentry->d_inode;
-	struct nfs_fattr fattr;
 	void * buffer = (void *)page_address(page);
 	unsigned int error;
 
 	/* We place the length at the beginning of the page,
 	 * in client byte order, followed by the string.
 	 */
-	error = NFS_CALL(readlink, inode, (dentry, &fattr, buffer,
-					   PAGE_CACHE_SIZE-sizeof(u32)-4));
-	nfs_refresh_inode(inode, &fattr);
+	error = NFS_PROTO(inode)->readlink(inode, buffer,
+					   PAGE_CACHE_SIZE-sizeof(u32)-4);
 	if (error < 0)
 		goto error;
 	flush_dcache_page(page_address(page)); /* Is this correct? */
@@ -90,7 +87,7 @@
 
 	/* Caller revalidated the directory inode already. */
 	page = read_cache_page(inode, 0,
-				(filler_t *)nfs_symlink_filler, dentry);
+				(filler_t *)nfs_symlink_filler, inode);
 	if (IS_ERR(page))
 		goto read_failed;
 
@@ -115,7 +112,7 @@
 
 	/* Caller revalidated the directory inode already. */
 	page = read_cache_page(inode, 0,
-				(filler_t *)nfs_symlink_filler, dentry);
+				(filler_t *)nfs_symlink_filler, inode);
 	if (IS_ERR(page))
 		goto read_failed;
 
diff -urN linux-2.2.19-pre9/fs/nfs/write.c linux/fs/nfs/write.c
--- linux-2.2.19-pre9/fs/nfs/write.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/nfs/write.c	Mon Dec  3 21:01:23 2001
@@ -66,7 +66,7 @@
  */
 struct nfs_write_data {
 	struct rpc_task		task;
-	struct dentry		*dentry;
+	struct inode		*inode;
 	struct rpc_cred		*cred;
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeres	res;		/* result struct */
@@ -143,20 +143,21 @@
  * Offset is the data offset within the page.
  */
 static int
-nfs_writepage_sync(struct file *file, struct page *page,
+nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
 		   unsigned long offset, unsigned int count)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-	struct rpc_cred	*cred = nfs_file_cred(file);
+	struct rpc_cred	*cred = NULL;
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
 	int		result, refresh = 0, written = 0, flags;
 	u8		*buffer;
 	struct nfs_fattr fattr;
 	struct nfs_writeverf verifier;
 
-	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%ld)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
+	if (file)
+		cred = nfs_file_cred(file);
+
+	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode),
 		count, nfs_page_offset(page) + offset);
 
 	buffer = (u8 *) page_address(page) + offset;
@@ -168,7 +169,7 @@
 		if (count < wsize && !IS_SWAPFILE(inode))
 			wsize = count;
 
-		result = NFS_PROTO(inode)->write(dentry, &fattr, cred, flags,
+		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
 						 offset, wsize, buffer,
 						 &verifier);
 		nfs_write_attributes(inode, &fattr);
@@ -205,14 +206,18 @@
 int
 nfs_writepage(struct file * file, struct page *page)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode;
 	unsigned offset = PAGE_CACHE_SIZE;
 
+	if (!file)
+		inode = page->inode;
+	else
+		inode = file->f_dentry->d_inode;
 	if (page->offset >= inode->i_size)
 		return -EIO;
 	if (page->offset + offset > inode->i_size)
 		offset = inode->i_size & (PAGE_CACHE_SIZE-1);
-	return nfs_writepage_sync(file, page, 0, offset);
+	return nfs_writepage_sync(file, inode, page, 0, offset);
 }
 
 /*
@@ -252,6 +257,8 @@
 		return;
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
+	if (list_empty(&inode->u.nfs_i.writeback))
+		inode->i_count++;
 	inode->u.nfs_i.npages++;
 	list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
 	req->wb_count++;
@@ -269,12 +276,14 @@
 
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
-	inode = req->wb_dentry->d_inode;
+	inode = req->wb_inode;
 	list_del(&req->wb_hash);
 	INIT_LIST_HEAD(&req->wb_hash);
 	inode->u.nfs_i.npages--;
 	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
+	if (list_empty(&inode->u.nfs_i.writeback))
+		iput(inode);
 	if (!nfs_have_writebacks(inode) && !nfs_have_read(inode))
 		inode_remove_flushd(inode);
 	nfs_release_request(req);
@@ -354,7 +363,7 @@
 static inline void
 nfs_mark_request_dirty(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	if (list_empty(&req->wb_list)) {
 		nfs_list_add_request(req, &inode->u.nfs_i.dirty);
@@ -369,7 +378,7 @@
 static inline int
 nfs_dirty_request(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
 }
 
@@ -380,7 +389,7 @@
 static inline void
 nfs_mark_request_commit(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	if (list_empty(&req->wb_list)) {
 		nfs_list_add_request(req, &inode->u.nfs_i.commit);
@@ -396,11 +405,10 @@
  * two different requests for the same page, and avoids possible deadlock
  * when we reach the hard limit on the number of dirty pages.
  */
-struct nfs_page *nfs_create_request(struct file *file, struct page *page,
+struct nfs_page *nfs_create_request(struct file *file, struct inode *inode,
+				    struct page *page,
 				    unsigned int offset, unsigned int count)
 {
-	struct dentry		*dentry = file->f_dentry;
-	struct inode		*inode = dentry->d_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct nfs_page		*req = NULL;
 	long			timeout;
@@ -452,9 +460,12 @@
 	req->wb_offset  = offset;
 	req->wb_bytes   = count;
 	req->wb_file    = file;
-	file->f_count++;
-	req->wb_dentry	= dentry;
-	req->wb_cred	= nfs_file_cred(file);
+	if (file) {
+		file->f_count++;
+		req->wb_cred	= nfs_file_cred(file);
+	} else
+		req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	req->wb_inode	= inode;
 	req->wb_count   = 1;
 
 	/* register request's existence */
@@ -471,7 +482,7 @@
 void
 nfs_release_request(struct nfs_page *req)
 {
-	struct inode		*inode = req->wb_dentry->d_inode;
+	struct inode		*inode = req->wb_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct page		*page = req->wb_page;
 
@@ -489,7 +500,10 @@
 	if (NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: Request released while still locked!\n");
 
-	fput(req->wb_file);
+	if (req->wb_file)
+		fput(req->wb_file);
+	else
+		rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
 	page_cache_release(page);
 	nfs_page_free(req);
 	/* wake up anyone waiting to allocate a request */
@@ -506,7 +520,7 @@
 static int
 nfs_wait_on_request(struct nfs_page *req)
 {
-	struct inode	*inode = req->wb_dentry->d_inode;
+	struct inode	*inode = req->wb_inode;
         struct rpc_clnt	*clnt = NFS_CLIENT(inode);
         int retval;
 
@@ -716,10 +730,9 @@
  * Note: Should always be called with the Page Lock held!
  */
 static struct nfs_page *
-nfs_update_request(struct file* file, struct page *page,
+nfs_update_request(struct file* file, struct inode *inode, struct page *page,
 		   unsigned int offset, unsigned int bytes)
 {
-	struct inode		*inode = file->f_dentry->d_inode;
 	struct nfs_page		*req, *new = NULL;
 	unsigned long		rqend, end;
 
@@ -754,7 +767,7 @@
 		 */
 		if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT)
 			nfs_wb_file(inode, file);
-		new = nfs_create_request(file, page, offset, bytes);
+		new = nfs_create_request(file, inode, page, offset, bytes);
 		if (!new)
 			return ERR_PTR(-ENOMEM);
 		/* If the region is locked, adjust the timeout */
@@ -891,7 +904,7 @@
 	 * page synchronously.
 	 */
 	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
-		return nfs_writepage_sync(file, page, offset, count);
+		return nfs_writepage_sync(file, inode, page, offset, count);
 
         /*
          * Try to find an NFS request corresponding to this page
@@ -900,7 +913,7 @@
 	 * it out now.
          */
 	do {
-		req = nfs_update_request(file, page, offset, count);
+		req = nfs_update_request(file, inode, page, offset, count);
 		if (IS_ERR(req))
 			status = PTR_ERR(req);
 		if (status != -EBUSY)
@@ -967,9 +980,9 @@
 		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->dentry = req->wb_dentry;
+	data->inode = req->wb_inode;
 	data->cred = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_dentry);
+	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = nfs_page_offset(req->wb_page) + req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
@@ -987,9 +1000,8 @@
  * that has been written but not committed.
  */
 static int
-nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
+nfs_flush_one(struct list_head *head, struct inode *inode, int how)
 {
-	struct inode            *inode = dentry->d_inode;
 	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
 	struct nfs_write_data	*data;
 	struct rpc_task		*task;
@@ -1033,10 +1045,10 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
 		task->tk_pid, 
-		dentry->d_parent->d_name.name,
-		dentry->d_name.name,
+		inode->i_dev,
+		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -1066,7 +1078,7 @@
 	while (!list_empty(head)) {
 		pages += nfs_coalesce_requests(head, &one_request, wpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_flush_one(&one_request, req->wb_dentry, how);
+		error = nfs_flush_one(&one_request, req->wb_inode, how);
 		if (error < 0)
 			break;
 	}
@@ -1092,8 +1104,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
 	struct nfs_writeargs	*argp = &data->args;
 	struct nfs_writeres	*resp = &data->res;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 	struct nfs_page		*req;
 	struct page		*page;
 
@@ -1138,9 +1149,9 @@
 		nfs_list_remove_request(req);
 		page = req->wb_page;
 
-		dprintk("NFS: write (%s/%s %d@%Ld)",
-			req->wb_dentry->d_parent->d_name.name,
-			req->wb_dentry->d_name.name,
+		dprintk("NFS: write (%x/%Ld %d@%Ld)",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(nfs_page_offset(page) + req->wb_offset));
 
@@ -1181,7 +1192,6 @@
 nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
 	struct nfs_page		*req;
-	struct dentry		*dentry;
 	struct inode		*inode;
 	unsigned long		start, end, len;
 
@@ -1191,10 +1201,7 @@
 	end = 0;
 	start = ~0;
 	req = nfs_list_entry(head->next);
-	dentry = req->wb_dentry;
-	data->dentry = dentry;
-	data->cred = req->wb_cred;
-	inode = dentry->d_inode;
+	inode = req->wb_inode;
 	while (!list_empty(head)) {
 		struct nfs_page	*req;
 		unsigned long	rqstart, rqend;
@@ -1208,7 +1215,9 @@
 		if (rqend > end)
 			end = rqend;
 	}
-	data->args.fh     = NFS_FH(dentry);
+	data->inode = inode;
+	data->cred = req->wb_cred;
+	data->args.fh     = NFS_FH(inode);
 	data->args.offset = start;
 	len = end - start;
 	if (end >= inode->i_size || len > (~((u32)0) >> 1))
@@ -1243,7 +1252,7 @@
 	/* Set up the argument struct */
 	nfs_commit_rpcsetup(head, data);
 	req = nfs_list_entry(data->pages.next);
-	clnt = NFS_CLIENT(req->wb_dentry->d_inode);
+	clnt = NFS_CLIENT(req->wb_inode);
 
 	rpc_init_task(task, clnt, nfs_commit_done, flags);
 	task->tk_calldata = data;
@@ -1279,8 +1288,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
 	struct nfs_writeres	*resp = &data->res;
 	struct nfs_page		*req;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
@@ -1290,9 +1298,9 @@
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 
-		dprintk("NFS: commit (%s/%s %d@%ld)",
-			req->wb_dentry->d_parent->d_name.name,
-			req->wb_dentry->d_name.name,
+		dprintk("NFS: commit (%x/%Ld %d@%ld)",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			nfs_page_offset(req->wb_page) + req->wb_offset);
 		if (task->tk_status < 0) {
diff -urN linux-2.2.19-pre9/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- linux-2.2.19-pre9/fs/nfsd/nfsfh.c	Mon Dec  3 21:00:54 2001
+++ linux/fs/nfsd/nfsfh.c	Mon Dec  3 21:01:23 2001
@@ -679,7 +679,7 @@
 	fhp->fh_handle.fh_dev    = kdev_t_to_u32(parent->d_inode->i_dev);
 	fhp->fh_handle.fh_xdev   = kdev_t_to_u32(exp->ex_dev);
 	fhp->fh_handle.fh_xino   = ino_t_to_u32(exp->ex_ino);
-	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+	fhp->fh_handle.fh_dcookie = 0xfeebbaca;
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 		fhp->fh_handle.fh_generation = inode->i_generation;
diff -urN linux-2.2.19-pre9/include/linux/lockd/nlm.h linux/include/linux/lockd/nlm.h
--- linux-2.2.19-pre9/include/linux/lockd/nlm.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/lockd/nlm.h	Mon Dec  3 21:01:23 2001
@@ -45,10 +45,10 @@
 #define NLMPROC_CANCEL_RES	13
 #define NLMPROC_UNLOCK_RES	14
 #define NLMPROC_GRANTED_RES	15
+#define NLMPROC_NSM_NOTIFY	16		/* statd callback */
 #define NLMPROC_SHARE		20
 #define NLMPROC_UNSHARE		21
 #define NLMPROC_NM_LOCK		22
 #define NLMPROC_FREE_ALL	23
-#define NLMPROC_NSM_NOTIFY	24		/* statd callback */
 
 #endif /* LINUX_LOCKD_NLM_H */
diff -urN linux-2.2.19-pre9/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- linux-2.2.19-pre9/include/linux/nfs_fs.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/nfs_fs.h	Mon Dec  3 21:01:23 2001
@@ -54,8 +54,7 @@
 /*
  * Convenience macros
  */
-#define NFS_FH(dentry)			((struct nfs_fh *) ((dentry)->d_fsdata))
-#define NFS_DSERVER(dentry)		(&(dentry)->d_sb->u.nfs_sb.s_server)
+#define NFS_FH(inode)			(&(inode)->u.nfs_i.fh)
 #define NFS_SERVER(inode)		(&(inode)->i_sb->u.nfs_sb.s_server)
 #define NFS_CLIENT(inode)		(NFS_SERVER(inode)->client)
 #define NFS_PROTO(inode)		(NFS_SERVER(inode)->rpc_ops)
@@ -84,12 +83,11 @@
 
 #define NFS_FLAGS(inode)		((inode)->u.nfs_i.flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
+#define NFS_STALE(inode)		(NFS_FLAGS(inode) & NFS_INO_STALE)
 
 #define NFS_FILEID(inode)	((inode)->u.nfs_i.fileid)
 #define NFS_FSID(inode)		((inode)->u.nfs_i.fsid)
 
-#define NFS_FILE(file)		((struct nfs_file *)(file)->private_data)
-
 /* Inode Flags */
 #define NFS_USE_READDIRPLUS(inode)	((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
 
@@ -114,24 +112,6 @@
 #define FLUSH_STABLE		4	/* commit to stable storage */
 
 
-/*
- * Structure for file->private_data;
- */
-struct nfs_file {
-	unsigned long		magic;		/* Magic number */
-	struct rpc_cred*	cred;		/* RPC Credentials */
-};
-
-static inline int
-nfs_check_file(struct file *file)
-{
-	if (NFS_FILE(file)->magic != NFS_FILE_MAGIC) {
-		printk(KERN_ERR "NFS: corrupt file structure!\n");
-		return 0;
-	}
-	return 1;
-}
-
 static inline
 unsigned long nfs_page_offset(struct page *page)
 {
@@ -147,6 +127,8 @@
 /*
  * linux/fs/nfs/inode.c
  */
+extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
+			       struct nfs_fattr *);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
 			       struct nfs_fattr *);
 extern struct super_block *nfs_read_super(struct super_block *, void *, int);
@@ -155,7 +137,7 @@
 extern int	nfs_revalidate(struct dentry *);
 extern int	nfs_open(struct inode *, struct file *);
 extern int	nfs_release(struct inode *, struct file *);
-extern int	__nfs_revalidate_inode(struct dentry *);
+extern int	__nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int	nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int	nfs_wait_on_inode(struct inode *, int flag);
 extern void	nfs_unlock_inode(struct inode *);
@@ -286,19 +268,18 @@
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
  */
-extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
-extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs3_fh *);
+extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs3_fh *);
 
 /*
  * inline functions
  */
 static inline int
-nfs_revalidate_inode(struct dentry *dentry)
+nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	struct inode *inode = dentry->d_inode;
 	if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
 		return 0;
-	return __nfs_revalidate_inode(dentry);
+	return __nfs_revalidate_inode(server, inode);
 }
 
 static inline off_t
@@ -325,11 +306,7 @@
 static __inline__ struct rpc_cred *
 nfs_file_cred(struct file *file)
 {
-	if (!NFS_FILE(file) || !nfs_check_file(file)) {
-		printk("nfs_file_cred: invalid file!\n");
-		return NULL;
-	}
-	return NFS_FILE(file)->cred;
+	return (struct rpc_cred *)(file->private_data);
 }
 
 /* NFS root */
diff -urN linux-2.2.19-pre9/include/linux/nfs_fs_i.h linux/include/linux/nfs_fs_i.h
--- linux-2.2.19-pre9/include/linux/nfs_fs_i.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/nfs_fs_i.h	Mon Dec  3 21:01:23 2001
@@ -1,6 +1,7 @@
 #ifndef _NFS_FS_i
 #define _NFS_FS_I
 
+#include <linux/list.h>
 #include <linux/nfs.h>
 #include <linux/pipe_fs_i.h>
 
@@ -22,6 +23,11 @@
 	__u64 fileid;
 
 	/*
+	 * NFS file handle
+	 */
+	struct nfs_fh		fh;
+
+	/*
 	 * Various flags
 	 */
 	unsigned short		flags;
@@ -79,12 +85,10 @@
 /*
  * Legal inode flag values
  */
-#define NFS_INO_LOCKED          0x0001          /* locked for revalidation */
+#define NFS_INO_STALE		0x0001		/* We suspect inode is stale */
 #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
 #define NFS_INO_REVALIDATING    0x0004          /* in nfs_revalidate() */
-#define NFS_INO_INVALIDATE      0x0008          /* zap cache on next occasion */
 #define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
-#define NFS_INO_STALE		0x0020		/* We suspect inode is stale */
 #define NFS_INO_FLUSH		0x0040		/* inode is due for flushing */
 
 /*
diff -urN linux-2.2.19-pre9/include/linux/nfs_page.h linux/include/linux/nfs_page.h
--- linux-2.2.19-pre9/include/linux/nfs_page.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/nfs_page.h	Mon Dec  3 21:01:23 2001
@@ -26,7 +26,7 @@
 				wb_list,	/* Defines state of page: */
 				*wb_list_head;	/*      read/write/commit */
 	struct file		*wb_file;
-	struct dentry		*wb_dentry;
+	struct inode		*wb_inode;
 	struct rpc_cred		*wb_cred;
 	struct page		*wb_page;	/* page to read in/write out */
 	struct wait_queue	*wb_wait;	/* wait queue */
@@ -41,6 +41,7 @@
 #define NFS_WBACK_BUSY(req)	((req)->wb_flags & PG_BUSY)
 
 extern	struct nfs_page *nfs_create_request(struct file *file,
+					    struct inode *inode,
 					    struct page *page,
 					    unsigned int offset,
 					    unsigned int count);
diff -urN linux-2.2.19-pre9/include/linux/nfs_xdr.h linux/include/linux/nfs_xdr.h
--- linux-2.2.19-pre9/include/linux/nfs_xdr.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/nfs_xdr.h	Mon Dec  3 21:01:23 2001
@@ -321,48 +321,43 @@
 
 	int	(*getroot)(struct nfs_server *,
 			struct nfs_fh *, struct nfs_fattr *);
-	int	(*getattr)(struct dentry *, struct nfs_fattr *);
-	int	(*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *);
-	int	(*lookup)(struct dentry *, struct nfs_fattr *, struct qstr *,
+	int	(*getattr)(struct inode *, struct nfs_fattr *);
+	int	(*setattr)(struct inode *, struct nfs_fattr *, struct iattr *);
+	int	(*lookup)(struct inode *, struct qstr *,
 			struct nfs_fh *, struct nfs_fattr *);
-	int	(*access)(struct dentry *, int fmode, struct nfs_fattr *, int);
-	int	(*readlink)(struct dentry *, struct nfs_fattr *,
-			void *buffer, unsigned int buflen);
-	int	(*read)(struct dentry *, struct nfs_fattr *,
-			struct rpc_cred *,
+	int	(*access)(struct inode *, int, int);
+	int	(*readlink)(struct inode *, void *buffer, unsigned int buflen);
+	int	(*read)(struct inode *, struct rpc_cred *,
+			struct nfs_fattr *,
 			int flags, unsigned long offset,
 			unsigned int count, void *buffer, int *eofp);
-	int	(*write)(struct dentry *, struct nfs_fattr *,
-			struct rpc_cred *,
+	int	(*write)(struct inode *, struct rpc_cred *,
+			struct nfs_fattr *,
 			int flags, unsigned long offset,
 			unsigned int count, void *buffer,
 			struct nfs_writeverf *verfp);
-	int	(*commit)(struct dentry *, struct nfs_fattr *,
+	int	(*commit)(struct inode *, struct nfs_fattr *,
 			struct rpc_cred *,
 			unsigned long, unsigned int);
-	int	(*create)(struct dentry *, struct nfs_fattr *,
-			struct qstr *, struct iattr *, int flags,
-			struct nfs_fh *, struct nfs_fattr *);
-	int	(*remove)(struct dentry *, struct nfs_fattr *, struct qstr *);
+	int	(*create)(struct inode *, struct qstr *, struct iattr *,
+			  int, struct nfs_fh *, struct nfs_fattr *);
+	int	(*remove)(struct inode *, struct qstr *);
 	int	(*unlink_setup)	(struct rpc_message *,
 			struct dentry *, struct qstr *);
 	void	(*unlink_done)	(struct dentry *, struct rpc_message *);
-	int	(*rename)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct dentry *, struct nfs_fattr *, struct qstr *);
-	int	(*link)(struct dentry *, struct nfs_fattr *,
-			struct dentry *, struct nfs_fattr *, struct qstr *);
-	int	(*symlink)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct qstr *, struct iattr *,
-			struct nfs_fh *, struct nfs_fattr *);
-	int	(*mkdir)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct iattr *, struct nfs_fh *, struct nfs_fattr *);
-	int	(*rmdir)(struct dentry *, struct nfs_fattr *, struct qstr *);
-	int	(*readdir)(struct dentry *, struct nfs_fattr *,
-			struct rpc_cred *,
-			__u64 cookie, void *, unsigned int size, int plus);
-	int	(*mknod)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct iattr *, dev_t,
-			struct nfs_fh *, struct nfs_fattr *);
+	int	(*rename)(struct inode *, struct qstr *,
+			struct inode *, struct qstr *);
+	int	(*link)(struct inode *, struct inode *, struct qstr *);
+	int	(*symlink)(struct inode *, struct qstr *, struct qstr *,
+			   struct iattr *, struct nfs_fh *,
+			   struct nfs_fattr *);
+	int	(*mkdir)(struct inode *, struct qstr *,	struct iattr *,
+			 struct nfs_fh *, struct nfs_fattr *);
+	int	(*rmdir)(struct inode *, struct qstr *);
+	int	(*readdir)(struct inode *, struct rpc_cred *,
+			__u64, void *, unsigned int, int);
+	int	(*mknod)(struct inode *, struct qstr *,	struct iattr *,
+			 dev_t,	struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)(struct nfs_server *, struct nfs_fh *,
 			struct nfs_fsinfo *);
 	__u32 *	(*decode_dirent)(__u32 *, struct nfs_entry *, int plus);
diff -urN linux-2.2.19-pre9/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- linux-2.2.19-pre9/include/linux/nfsd/nfsfh.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/nfsd/nfsfh.h	Mon Dec  3 21:01:23 2001
@@ -30,7 +30,7 @@
  * ino/dev of the exported inode.
  */
 struct nfs_fhbase {
-	struct dentry *	fb_dentry;	/* dentry cookie */
+	__u32		fb_dcookie;	/* dentry cookie */
 	__u32		fb_ino;		/* our inode number */
 	__u32		fb_dirino;	/* dir inode number */
 	__u32		fb_dev;		/* our device */
@@ -45,7 +45,7 @@
 	__u8			fh_cookie[NFS_FH_PADDING];
 };
 
-#define fh_dcookie		fh_base.fb_dentry
+#define fh_dcookie		fh_base.fb_dcookie
 #define fh_ino			fh_base.fb_ino
 #define fh_dirino		fh_base.fb_dirino
 #define fh_dev			fh_base.fb_dev
diff -urN linux-2.2.19-pre9/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h
--- linux-2.2.19-pre9/include/linux/sunrpc/clnt.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/sunrpc/clnt.h	Mon Dec  3 21:01:23 2001
@@ -111,6 +111,8 @@
 void		rpc_release_client(struct rpc_clnt *);
 void		rpc_getport(struct rpc_task *, struct rpc_clnt *);
 int		rpc_register(u32, u32, int, unsigned short, int *);
+u32 *		rpc_call_header(struct rpc_task *task);
+u32 *		rpc_call_verify(struct rpc_task *task);
 
 void		rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
 
@@ -143,6 +145,11 @@
  * Helper function for NFSroot support
  */
 int		rpc_getport_external(struct sockaddr_in *, __u32, __u32, int);
+
+/*
+ * Ping function
+ */
+void		rpc_ping(struct rpc_task *task);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
diff -urN linux-2.2.19-pre9/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h
--- linux-2.2.19-pre9/include/linux/sunrpc/sched.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/sunrpc/sched.h	Mon Dec  3 21:01:23 2001
@@ -45,7 +45,7 @@
 	struct rpc_task *	tk_parent;	/* parent task */
 	struct rpc_clnt *	tk_client;	/* RPC client */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
-	volatile int		tk_status;	/* result of last operation */
+	int			tk_status;	/* result of last operation */
 	struct rpc_wait_queue *	tk_rpcwait;	/* RPC wait queue we're on */
 
 	/*
@@ -81,8 +81,7 @@
 	unsigned int		tk_lock;	/* Task lock counter */
 	unsigned char		tk_active   : 1,/* Task has been activated */
 				tk_wakeup   : 1;/* Task waiting to wake up */
-	volatile unsigned char	tk_running  : 1,/* Task is running */
-				tk_sleeping : 1;/* Task is truly asleep */
+	unsigned int		tk_runstate;	/* Task run status */
 #ifdef RPC_DEBUG
 	unsigned int		tk_pid;		/* debugging aid */
 #endif
@@ -112,10 +111,20 @@
 #define RPC_IS_SWAPPER(t)	((t)->tk_flags & RPC_TASK_SWAPPER)
 #define RPC_DO_ROOTOVERRIDE(t)	((t)->tk_flags & RPC_TASK_ROOTCREDS)
 #define RPC_ASSASSINATED(t)	((t)->tk_flags & RPC_TASK_KILLED)
-#define RPC_IS_RUNNING(t)	((t)->tk_running)
-#define RPC_IS_SLEEPING(t)	((t)->tk_sleeping)
 #define RPC_IS_ACTIVATED(t)	((t)->tk_active)
 #define RPC_DO_CALLBACK(t)	((t)->tk_callback != NULL)
+
+#define RPC_TASK_SLEEPING	0
+#define RPC_TASK_RUNNING	1
+#define RPC_IS_SLEEPING(t)	(test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
+#define RPC_IS_RUNNING(t)	(test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+
+#define rpc_set_running(t)	(set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+#define rpc_clear_running(t)	(clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+
+#define rpc_set_sleeping(t)	(set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
+
+#define rpc_clear_sleeping(t)	(clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
 
 /*
  * RPC synchronization objects
diff -urN linux-2.2.19-pre9/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h
--- linux-2.2.19-pre9/include/linux/sunrpc/xprt.h	Sun Dec 10 16:49:44 2000
+++ linux/include/linux/sunrpc/xprt.h	Mon Dec  3 21:01:23 2001
@@ -41,12 +41,14 @@
  * Come Linux 2.3, we'll handle fragments directly.
  */
 #define RPC_MAXCONG		16
-#define RPC_MAXREQS		(RPC_MAXCONG + 1)
+#define RPC_MAXREQS		(RPC_MAXCONG + 2)
 #define RPC_CWNDSCALE		256
 #define RPC_MAXCWND		(RPC_MAXCONG * RPC_CWNDSCALE)
 #define RPC_INITCWND		RPC_CWNDSCALE
 #define RPCXPRT_CONGESTED(xprt) \
 	((xprt)->cong >= (xprt)->cwnd)
+#define RPCXPRT_SUPERCONGESTED(xprt) \
+				((xprt)->cwnd < 2*RPC_CWNDSCALE)
 
 /* Default timeout values */
 #define RPC_MAX_UDP_TIMEOUT	(60*HZ)
@@ -98,7 +100,7 @@
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
 	struct rpc_rqst *	rq_next;	/* free list */
-	volatile unsigned char	rq_received : 1;/* receive completed */
+	unsigned char		rq_received : 1;/* receive completed */
 
 	/*
 	 * For authentication (e.g. auth_des)
@@ -138,10 +140,10 @@
 	struct rpc_wait_queue	pending;	/* requests in flight */
 	struct rpc_wait_queue	backlog;	/* waiting for slot */
 	struct rpc_wait_queue	reconn;		/* waiting for reconnect */
+	struct rpc_wait_queue	pingwait;	/* waiting on ping() */
 	struct rpc_rqst *	free;		/* free slots */
 	struct rpc_rqst		slot[RPC_MAXREQS];
-	volatile unsigned char	connected   : 1,/* TCP: connected */
-				write_space : 1;/* TCP: can send */
+	unsigned int		sockstate;	/* Socket state */
 	unsigned char		nocong	    : 1,/* no congestion control */
 				stream      : 1,/* TCP */
 				shutdown    : 1,/* being shut down */
@@ -185,12 +187,14 @@
 					unsigned long);
 
 int			xprt_reserve(struct rpc_task *);
+int			xprt_ping_reserve(struct rpc_task *);
 int			xprt_down_transmit(struct rpc_task *);
 void			xprt_transmit(struct rpc_task *);
 void			xprt_up_transmit(struct rpc_task *);
 void			xprt_receive(struct rpc_task *);
 int			xprt_adjust_timeout(struct rpc_timeout *);
 void			xprt_release(struct rpc_task *);
+void			xprt_ping_release(struct rpc_task *);
 void			xprt_reconnect(struct rpc_task *);
 void			__rpciod_tcp_dispatcher(void);
 
@@ -209,23 +213,30 @@
 		__rpciod_tcp_dispatcher();
 }
 
-static inline
-int xprt_connected(struct rpc_xprt *xprt)
-{
-	return xprt->connected;
-}
+#define	XPRT_WSPACE	0
+#define XPRT_CONNECT	1
+#define XPRT_PING	2
+#define XPRT_NORESPOND	3
+
+#define xprt_wspace(xp)			(test_bit(XPRT_WSPACE, &(xp)->sockstate))
+#define xprt_test_and_set_wspace(xp)	(test_and_set_bit(XPRT_WSPACE, &(xp)->sockstate))
+#define xprt_clear_wspace(xp)		(clear_bit(XPRT_WSPACE, &(xp)->sockstate))
+
+#define xprt_connected(xp)		(!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_set_connected(xp)		(set_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_test_and_set_connected(xp)	(test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_clear_connected(xp)	(clear_bit(XPRT_CONNECT, &(xp)->sockstate))
+
+#define xprt_pinging(xp)		(test_bit(XPRT_PING, &(xp)->sockstate))
+#define xprt_set_pinging(xp)		(set_bit(XPRT_PING, &(xp)->sockstate))
+#define xprt_test_and_set_pinging(xp)	(test_and_set_bit(XPRT_PING, &(xp)->sockstate))
+#define xprt_clear_pinging(xp)		(clear_bit(XPRT_PING, &(xp)->sockstate))
+
+#define xprt_norespond(xp)		(test_bit(XPRT_NORESPOND, &(xp)->sockstate))
+#define xprt_test_and_set_norespond(xp)	(test_and_set_bit(XPRT_NORESPOND, &(xp)->sockstate))
+#define xprt_clear_norespond(xp)	(clear_bit(XPRT_NORESPOND, &(xp)->sockstate))
 
-static inline
-void xprt_set_connected(struct rpc_xprt *xprt)
-{
-	xprt->connected = 1;
-}
 
-static inline
-void xprt_clear_connected(struct rpc_xprt *xprt)
-{
-	xprt->connected = 0;
-}
 
 #endif /* __KERNEL__*/
 
diff -urN linux-2.2.19-pre9/ipc/shm.c linux/ipc/shm.c
--- linux-2.2.19-pre9/ipc/shm.c	Mon Dec  3 21:00:55 2001
+++ linux/ipc/shm.c	Mon Dec  3 21:01:23 2001
@@ -340,8 +340,6 @@
 			shp->u.shm_perm.mode |= SHM_DEST;
 			if (shp->u.shm_nattch <= 0)
 				killseg (id);
-			/* Do not find it any more */
-			shp->u.shm_perm.key = IPC_PRIVATE;
 			break;
 		}
 		err = -EPERM;
diff -urN linux-2.2.19-pre9/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- linux-2.2.19-pre9/net/ax25/ax25_in.c	Tue Jan  4 10:12:26 2000
+++ linux/net/ax25/ax25_in.c	Mon Dec  3 21:01:24 2001
@@ -36,6 +36,7 @@
  *	AX.25 036	Jonathan(G4KLX)	Move DAMA code into own file.
  *			Joerg(DL1BKE)	Fixed DAMA Slave.
  *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ *			Thomas(DL9SAU)  Fixed missing initialization of skb->protocol.
  */
 
 #include <linux/config.h>
@@ -159,6 +160,7 @@
 		skb->nh.raw   = skb->data;
 		skb->dev      = ax25->ax25_dev->dev;
 		skb->pkt_type = PACKET_HOST;
+		skb->protocol = htons(ETH_P_IP);
 		ip_rcv(skb, skb->dev, NULL);	/* Wrong ptype */
 		return 1;
 	}
@@ -293,6 +295,7 @@
 				skb->nh.raw   = skb->data;
 				skb->dev      = dev;
 				skb->pkt_type = PACKET_HOST;
+				skb->protocol = htons(ETH_P_IP);
 				ip_rcv(skb, dev, ptype);	/* Note ptype here is the wrong one, fix me later */
 				break;
 
@@ -302,6 +305,7 @@
 				skb->nh.raw   = skb->data;
 				skb->dev      = dev;
 				skb->pkt_type = PACKET_HOST;
+				skb->protocol = htons(ETH_P_ARP);
 				arp_rcv(skb, dev, ptype);	/* Note ptype here is wrong... */
 				break;
 #endif
diff -urN linux-2.2.19-pre9/net/sunrpc/Makefile linux/net/sunrpc/Makefile
--- linux-2.2.19-pre9/net/sunrpc/Makefile	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/Makefile	Mon Dec  3 21:01:24 2001
@@ -11,7 +11,7 @@
 O_OBJS   := clnt.o xprt.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o \
-	    pmap_clnt.o xdr.o sysctl.o
+	    pmap_clnt.o ping.o xdr.o sysctl.o
 OX_OBJS  := sunrpc_syms.o
 
 ifeq ($(CONFIG_PROC_FS),y)
diff -urN linux-2.2.19-pre9/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- linux-2.2.19-pre9/net/sunrpc/clnt.c	Sun Dec 10 16:49:44 2000
+++ linux/net/sunrpc/clnt.c	Mon Dec  3 21:01:24 2001
@@ -55,8 +55,8 @@
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(struct rpc_task *task);
 static void	call_reconnect(struct rpc_task *task);
-static u32 *	call_header(struct rpc_task *task);
-static u32 *	call_verify(struct rpc_task *task);
+static void	call_ping(struct rpc_task *task);
+static void	call_pingresult(struct rpc_task *task);
 
 
 /*
@@ -487,7 +487,7 @@
 
 	/* Encode header and provided arguments */
 	encode = rpcproc_encode(clnt, task->tk_msg.rpc_proc);
-	if (!(p = call_header(task))) {
+	if (!(p = rpc_call_header(task))) {
 		printk(KERN_INFO "RPC: call_header failed, exit EIO\n");
 		rpc_exit(task, -EIO);
 	} else
@@ -592,11 +592,10 @@
 			task->tk_action = call_reconnect;
 			break;
 		}
-		/*
-		 * Sleep and dream of an open connection
-		 */
-		task->tk_timeout = 5 * HZ;
-		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+		if (RPCXPRT_SUPERCONGESTED(clnt->cl_xprt)) {
+			task->tk_action = call_ping;
+			break;
+		}
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
@@ -620,6 +619,7 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	int major = 0;
 
 	if (req) {
 		struct rpc_timeout *to = &req->rq_timeout;
@@ -644,16 +644,7 @@
 		rpc_exit(task, -EIO);
 		return;
 	}
-
-	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
-		task->tk_flags |= RPC_CALL_MAJORSEEN;
-		printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
-		       clnt->cl_protname, clnt->cl_server);
-	} else if (clnt->cl_chatty) {
-		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-		       clnt->cl_protname, clnt->cl_server);
-	}
-
+	major = 1;
 	if (clnt->cl_autobind)
 		clnt->cl_port = 0;
 
@@ -666,6 +657,8 @@
 	} else if (clnt->cl_xprt->stream && !xprt_connected(clnt->cl_xprt)) {
 		task->tk_action = call_reconnect;
 		clnt->cl_stats->rpcretrans++;
+	} else if (major && RPCXPRT_SUPERCONGESTED(clnt->cl_xprt)) {
+		task->tk_action = call_ping;
 	} else {
 		task->tk_action = call_transmit;
 		clnt->cl_stats->rpcretrans++;
@@ -687,21 +680,20 @@
 	dprintk("RPC: %4d call_decode (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
-	if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) {
-		printk(KERN_NOTICE "%s: server %s OK\n",
-			clnt->cl_protname, clnt->cl_server);
-		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
-	}
-
 	if (task->tk_status < 12) {
-		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
-			clnt->cl_protname, task->tk_status);
-		rpc_exit(task, -EIO);
+		if (!clnt->cl_softrtry) {
+			task->tk_action = call_transmit;
+			clnt->cl_stats->rpcretrans++;
+		} else {
+			printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
+				clnt->cl_protname, task->tk_status);
+			rpc_exit(task, -EIO);
+		}
 		return;
 	}
 
 	/* Verify the RPC header */
-	if (!(p = call_verify(task)))
+	if (!(p = rpc_call_verify(task)))
 		return;
 
 	/*
@@ -760,8 +752,8 @@
 /*
  * Call header serialization
  */
-static u32 *
-call_header(struct rpc_task *task)
+u32 *
+rpc_call_header(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
 	struct rpc_xprt *xprt = clnt->cl_xprt;
@@ -781,10 +773,61 @@
 }
 
 /*
+ * Ping a non-responding server
+ */
+static void
+call_ping(struct rpc_task *task)
+{
+	task->tk_action = call_pingresult;
+	rpc_ping(task);
+}
+
+/*
+ * Interpret the result from ping
+ */
+static void
+call_pingresult(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
+	int		status = task->tk_status;
+
+	task->tk_status = 0;
+	if (status >= 0) {
+		task->tk_action = call_transmit;
+		return;
+	}
+	switch(status) {
+	case -ECONNREFUSED:
+	case -ENOTCONN:
+		if (clnt->cl_autobind || !clnt->cl_port) {
+			clnt->cl_port = 0;
+			task->tk_action = call_bind;
+			break;
+		}
+		if (xprt->stream) {
+			task->tk_action = call_reconnect;
+			break;
+		}
+	case -ENOMEM:
+	case -ENOBUFS:
+		rpc_delay(task, HZ >> 4);
+	case -ETIMEDOUT:
+		task->tk_action = call_ping;
+		break;
+	default:
+		if (clnt->cl_chatty)
+			printk("%s: RPC call returned error %d\n",
+			       clnt->cl_protname, -status);
+		rpc_exit(task,status);
+	}
+}
+
+/*
  * Reply header verification
  */
-static u32 *
-call_verify(struct rpc_task *task)
+u32 *
+rpc_call_verify(struct rpc_task *task)
 {
 	u32	*p = task->tk_rqstp->rq_rvec[0].iov_base, n;
 
diff -urN linux-2.2.19-pre9/net/sunrpc/ping.c linux/net/sunrpc/ping.c
--- linux-2.2.19-pre9/net/sunrpc/ping.c	Wed Dec 31 16:00:00 1969
+++ linux/net/sunrpc/ping.c	Mon Dec  3 21:01:24 2001
@@ -0,0 +1,218 @@
+/*
+ * linux/net/sunrpc/ping.c
+ *
+ * Ping routing.
+ *
+ * Copyright (C) 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/uio.h>
+#include <linux/in.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/sched.h>
+
+
+#define RPC_SLACK_SPACE		512	/* total overkill */
+#define RPC_PING_DELAY		(15*HZ)
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_XPRT
+#endif
+
+static void ping_call_reserve(struct rpc_task *);
+static void ping_call_allocate(struct rpc_task *);
+static void ping_call_encode(struct rpc_task *);
+static void ping_call_transmit(struct rpc_task *);
+static void ping_call_receive(struct rpc_task *);
+static void ping_call_exit(struct rpc_task *);
+
+
+static void
+ping_call_reserve(struct rpc_task *task)
+{
+	dprintk("RPC: %4d, ping_call_reserve\n", task->tk_pid);
+	task->tk_status = 0;
+	task->tk_action  = ping_call_allocate;
+	task->tk_timeout = task->tk_client->cl_timeout.to_resrvval;
+	xprt_ping_reserve(task);
+}
+
+static void
+ping_call_allocate(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_rqst	*req = task->tk_rqstp;
+	unsigned int	bufsiz;
+
+	dprintk("RPC: %4d, ping_call_allocate (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	task->tk_action = ping_call_exit;
+	if (task->tk_status < 0)
+		return;
+
+	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE;
+	if (!(task->tk_buffer = rpc_malloc(task, bufsiz << 1))) {
+		task->tk_status = -ENOMEM;
+		return;
+	}
+	req->rq_svec[0].iov_base = (void *)task->tk_buffer;
+	req->rq_svec[0].iov_len	 = bufsiz;
+	req->rq_slen		 = 0;
+	req->rq_snr		 = 1;
+	req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
+	req->rq_rvec[0].iov_len	 = bufsiz;
+	req->rq_rlen		 = bufsiz;
+	req->rq_rnr		 = 1;
+	task->tk_action		 = ping_call_encode;
+}
+
+static void
+ping_call_encode(struct rpc_task *task)
+{
+	struct rpc_rqst	*req = task->tk_rqstp;
+	u32		*p;
+
+	dprintk("RPC: %4d, ping_call_encode (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	if (task->tk_status < 0) {
+		task->tk_action = ping_call_exit;
+		return;
+	}
+	p = rpc_call_header(task);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	task->tk_action = ping_call_transmit;
+}
+
+static void
+ping_call_transmit(struct rpc_task *task)
+{
+	dprintk("RPC: %4d, ping_call_transmit\n", task->tk_pid);
+	task->tk_action = ping_call_receive;
+	xprt_transmit(task);
+}
+
+static void
+ping_call_receive(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
+	struct rpc_rqst *req = task->tk_rqstp;
+	struct rpc_timeout *to = &req->rq_timeout;
+	u32 *p;
+
+	dprintk("RPC: %4d, ping_call_receive (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	if (task->tk_status >= 0)
+		p = rpc_call_verify(task);
+
+	task->tk_action = ping_call_exit;
+
+	if (task->tk_status >= 0 || task->tk_status == -EACCES) {
+		task->tk_status = 0;
+		if (xprt_norespond(xprt)) {
+			if (clnt->cl_chatty)
+				printk(KERN_NOTICE "%s: server %s OK\n",
+				       clnt->cl_protname, clnt->cl_server);
+			xprt_clear_norespond(xprt);
+		}
+		return;
+	}
+
+	switch (task->tk_status) {
+	case -ENOTCONN:
+		break;
+	case -ENOMEM:
+	case -EAGAIN:
+	case -ECONNREFUSED:
+	case -ETIMEDOUT:
+		if (!xprt_adjust_timeout(to)) {
+			task->tk_status = 0;
+			task->tk_action = ping_call_transmit;
+			break;
+		}
+	default:
+		if (clnt->cl_softrtry) {
+			task->tk_status = -EIO;
+			break;
+		}
+		if (clnt->cl_chatty) {
+			if (!xprt_test_and_set_norespond(xprt)) {
+				printk(KERN_NOTICE
+				       "%s: server %s is not responding\n",
+				       clnt->cl_protname, clnt->cl_server);
+			} else {
+				printk(KERN_NOTICE
+				       "%s: server %s still not responding\n",
+				       clnt->cl_protname, clnt->cl_server);
+			}
+		}
+		rpc_delay(task, RPC_PING_DELAY);
+	}
+}
+
+static void
+ping_call_exit(struct rpc_task *task)
+{
+	struct rpc_xprt	*xprt = task->tk_xprt;
+
+	dprintk("RPC: %4d, ping_call_exit (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	task->tk_action = NULL;
+	xprt_ping_release(task);
+
+	/* Sigh. rpc_delay() clears task->tk_status */
+	if (task->tk_status == 0 && xprt_norespond(xprt))
+		task->tk_status = -ETIMEDOUT;
+
+	xprt_clear_pinging(xprt);
+	rpc_wake_up_status(&xprt->pingwait, task->tk_status);
+}
+
+void
+rpc_ping(struct rpc_task *task)
+{
+	struct rpc_clnt *clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
+	struct rpc_task	*child;
+	struct rpc_message msg = {0, NULL, NULL, NULL};
+
+	dprintk("RPC: %4d, rpc_ping\n", task->tk_pid);
+
+ again:
+	if (xprt_test_and_set_pinging(xprt)) {
+		rpc_sleep_on(&xprt->pingwait, task, NULL, 0);
+		if (!xprt_pinging(xprt)) {
+			rpc_wake_up_task(task);
+			goto again;
+		}
+		dprintk("RPC: %4d, rpc_ping, waiting on completion\n",
+			task->tk_pid);
+		return;
+	}
+
+	child = rpc_new_child(clnt, task);
+	if (!child) {
+		dprintk("RPC: %4d, rpc_ping, failed to create child process\n",
+			task->tk_pid);
+		xprt_clear_pinging(xprt);
+		rpc_wake_up_status(&xprt->pingwait, -ENOMEM);
+		task->tk_status = -ENOMEM;
+		return;
+	}
+	rpc_call_setup(child, &msg, 0);
+	child->tk_action = ping_call_reserve;
+
+	dprintk("RPC: %4d, rpc_ping, running child process %4d\n",
+		task->tk_pid, child->tk_pid);
+	rpc_run_child(task, child, NULL);
+}
diff -urN linux-2.2.19-pre9/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- linux-2.2.19-pre9/net/sunrpc/sched.c	Sun Dec 10 16:49:44 2000
+++ linux/net/sunrpc/sched.c	Mon Dec  3 21:01:24 2001
@@ -259,7 +259,7 @@
 		printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n");
 		return;
 	}
-	task->tk_running = 1;
+	rpc_set_running(task);
 	if (RPC_IS_ASYNC(task)) {
 		if (RPC_IS_SLEEPING(task)) {
 			int status;
@@ -267,12 +267,13 @@
 			if (status < 0) {
 				printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
 				task->tk_status = status;
-			} else
-				task->tk_sleeping = 0;
+				return;
+			}
+			rpc_clear_sleeping(task);
+			wake_up(&rpciod_idle);
 		}
-		wake_up(&rpciod_idle);
 	} else {
-		task->tk_sleeping = 0;
+		rpc_clear_sleeping(task);
 		wake_up(&task->tk_wait);
 	}
 }
@@ -287,7 +288,7 @@
 	if (RPC_IS_ACTIVATED(task))
 		return;
 	task->tk_active = 1;
-	task->tk_sleeping = 1;
+	rpc_set_sleeping(task);
 	__rpc_make_runnable(task);
 }
 
@@ -327,7 +328,7 @@
 	/* Mark the task as being activated if so needed */
 	if (!RPC_IS_ACTIVATED(task)) {
 		task->tk_active = 1;
-		task->tk_sleeping = 1;
+		rpc_set_sleeping(task);
 	}
 
 	status = __rpc_add_wait_queue(q, task);
@@ -335,7 +336,7 @@
 		printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
 		task->tk_status = status;
 	} else {
-		task->tk_running = 0;
+		rpc_clear_running(task);
 		task->tk_callback = action;
 		__rpc_add_timer(task, timer);
 	}
@@ -609,21 +610,15 @@
 
 		/*
 		 * Check whether task is sleeping.
-		 * Note that if the task goes to sleep in tk_action,
-		 * and the RPC reply arrives before we get here, it will
-		 * have state RUNNING, but will still be on schedq.
-		 * 27/9/99: The above has been attempted fixed by
-		 *          introduction of task->tk_sleeping.
 		 */
 		spin_lock_irqsave(&rpc_queue_lock, oldflags);
 		if (!RPC_IS_RUNNING(task)) {
-			task->tk_sleeping = 1;
+			rpc_set_sleeping(task);
 			if (RPC_IS_ASYNC(task)) {
 				spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 				return 0;
 			}
-		} else
-			task->tk_sleeping = 0;
+		}
 		spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 
 		while (RPC_IS_SLEEPING(task)) {
@@ -689,18 +684,23 @@
 int
 rpc_execute(struct rpc_task *task)
 {
+	int status = -EIO;
 	if (rpc_inhibit) {
 		printk(KERN_INFO "RPC: execution inhibited!\n");
-		return -EIO;
+		goto out_release;
 	}
-	task->tk_running = 1;
 	if (task->tk_active) {
 		printk(KERN_ERR "RPC: active task was run twice!\n");
-		return -EWOULDBLOCK;
+		goto out_err;
 	}
 	task->tk_active = 1;
+	rpc_set_running(task);
 	
 	return __rpc_execute(task);
+ out_release:
+	rpc_release_task(task);
+ out_err:
+	return status;
 }
 
 /*
diff -urN linux-2.2.19-pre9/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- linux-2.2.19-pre9/net/sunrpc/svcsock.c	Sun Dec 10 16:49:44 2000
+++ linux/net/sunrpc/svcsock.c	Mon Dec  3 21:01:24 2001
@@ -773,7 +773,6 @@
 			"svc_recv: service %p, wait queue active!\n",
 			 rqstp);
 
-again:
 	/* Initialize the buffers */
 	rqstp->rq_argbuf = rqstp->rq_defbuf;
 	rqstp->rq_resbuf = rqstp->rq_defbuf;
@@ -818,7 +817,7 @@
 	/* No data, incomplete (TCP) read, or accept() */
 	if (len == 0 || len == -EAGAIN) {
 		svc_sock_release(rqstp);
-		goto again;
+		return -EAGAIN;
 	}
 
 	rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
diff -urN linux-2.2.19-pre9/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- linux-2.2.19-pre9/net/sunrpc/xprt.c	Sun Dec 10 16:49:45 2000
+++ linux/net/sunrpc/xprt.c	Mon Dec  3 21:01:24 2001
@@ -1010,7 +1010,8 @@
 
 	switch (sk->state) {
 	case TCP_ESTABLISHED:
-		xprt_set_connected(xprt);
+		if (xprt_test_and_set_connected(xprt))
+			break;
 		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
 			rpc_wake_up_task(xprt->snd_task);
 		rpc_wake_up(&xprt->reconn);
@@ -1045,16 +1046,14 @@
 	if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
 		return;
 
-	spin_lock_irqsave(&xprt_sock_lock, oldflags);
-	if (xprt->write_space)
-		goto out_unlock;
-
-	xprt->write_space = 1;
+	if (xprt_test_and_set_wspace(xprt))
+		goto out;
 
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
 	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
 		rpc_wake_up_task(xprt->snd_task);
- out_unlock:
 	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
+ out:
 	wake_up_interruptible(sk->sleep);
 }
 
@@ -1073,16 +1072,14 @@
 	if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
 		return;
 
-	spin_lock_irqsave(&xprt_sock_lock, oldflags);
-	if (xprt->write_space)
-		goto out_unlock;
-
-	xprt->write_space = 1;
+	if (xprt_test_and_set_wspace(xprt))
+		goto out;
 
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
 	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
 		rpc_wake_up_task(xprt->snd_task);
- out_unlock:
 	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
+ out:
 	wake_up_interruptible(sk->sleep);
 }
 
@@ -1115,8 +1112,10 @@
 {
 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	unsigned long	oldflags;
 
 	xprt_delete_tcp_timer(xprt);
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
 	if (xprt->snd_task && xprt->snd_task != task) {
 		dprintk("RPC: %4d TCP write queue full (task %d)\n",
 			task->tk_pid, xprt->snd_task->tk_pid);
@@ -1130,6 +1129,7 @@
 #endif
 		req->rq_bytes_sent = 0;
 	}
+	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 	return xprt->snd_task == task;
 }
 
@@ -1142,9 +1142,12 @@
 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 
 	if (xprt->snd_task && xprt->snd_task == task) {
+		unsigned long	oldflags;
+		spin_lock_irqsave(&xprt_sock_lock, oldflags);
 		xprt->snd_task = NULL;
 		if (!rpc_wake_up_next(&xprt->sending) && xprt->stream)
 			xprt_add_tcp_timer(xprt, RPCXPRT_TIMEOUT);
+		spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 	}
 }
 
@@ -1209,7 +1212,7 @@
 		if (!xprt->inet)
 			break;
 
-		xprt->write_space = 0;
+		xprt_clear_wspace(xprt);
 		status = -ENOMEM;
 		if (sock_wspace(xprt->inet) < req->rq_slen + MIN_WRITE_SPACE)
 			break;
@@ -1256,20 +1259,12 @@
 	case -ENOMEM:
 		/* Protect against (udp|tcp)_write_space */
 		spin_lock_irqsave(&xprt_sock_lock, oldflags);
-		if (!xprt->write_space) {
+		if (!xprt_wspace(xprt)) {
 			task->tk_timeout = req->rq_timeout.to_current;
 			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 		}
 		spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 		return;
-	case -EAGAIN:
-	case -ECONNREFUSED:
-	case -ENOTCONN:
-		/* Keep holding the socket if it is blocked */
-		if (!xprt->stream) {
-			rpc_delay(task, HZ>>4);
-			return;
-		}
 	default:
 		goto out_release;
 	}
@@ -1297,7 +1292,7 @@
 
 	dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
 
-	req->rq_received= 0;
+	req->rq_received = 0;
 	task->tk_timeout = 0;
 	rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
 }
@@ -1420,6 +1415,62 @@
 }
 
 /*
+ * Reserve a ping RPC call slot.
+ */
+int
+xprt_ping_reserve(struct rpc_task *task)
+{
+	struct rpc_xprt	*xprt = task->tk_xprt;
+	struct rpc_rqst	*req;
+
+	/* We already have an initialized request. */
+	if (task->tk_rqstp)
+		return 0;
+	if (xprt->shutdown)
+		task->tk_status = -EIO;
+
+	dprintk("RPC: %4d xprt_ping_reserve cong = %ld cwnd = %ld\n",
+				task->tk_pid, xprt->cong, xprt->cwnd);
+	start_bh_atomic();
+	if ((req = xprt->free) != NULL) {
+		xprt->free = req->rq_next;
+		req->rq_next = NULL;
+		task->tk_rqstp = req;
+		xprt_request_init(task, xprt);
+	} else
+		task->tk_status = -ENOBUFS;
+	end_bh_atomic();
+	dprintk("RPC: %4d xprt_ping_reserve returns %d\n",
+				task->tk_pid, task->tk_status);
+	if (!req)
+		BUG();
+	return task->tk_status;
+}
+
+/*
+ * Release an RPC call slot
+ */
+void
+xprt_ping_release(struct rpc_task *task)
+{
+	struct rpc_xprt	*xprt = task->tk_xprt;
+	struct rpc_rqst	*req;
+
+	xprt_up_transmit(task);
+	if (!(req = task->tk_rqstp))
+		return;
+	task->tk_rqstp = NULL;
+	memset(req, 0, sizeof(*req));	/* mark unused */
+
+	dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
+
+	start_bh_atomic();
+	req->rq_next = xprt->free;
+	xprt->free   = req;
+	end_bh_atomic();
+}
+
+/*
  * Set default timeout parameters
  */
 void
@@ -1490,6 +1541,7 @@
 	xprt->sending = RPC_INIT_WAITQ("xprt_sending");
 	xprt->backlog = RPC_INIT_WAITQ("xprt_backlog");
 	xprt->reconn  = RPC_INIT_WAITQ("xprt_reconn");
+	xprt->pingwait  = RPC_INIT_WAITQ("xprt_pingwait");
 
 	/* initialize free list */
 	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
