]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.19pre10 2.2.19pre10
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:16 +0000 (15:23 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:16 +0000 (15:23 -0500)
o Update aic7xxx driver to 5.1.33 (Doug Ledford)
o Revert shm change - its unsafe (Richard Nelson)
o Update sunrpc code, add rpc ping congestion (Trond Myklebust)
checks
o Fix wrong kfree in cosa driver (Jan Kasprzak)
o NFS client fixes (Trond Myklebust)
o Better dcache/inode hashes (Dave Miller)
o Fix missing skb->protocol init in AX.25 (Thomas Osterried)
o EEpro100 reporting fix as per 2.4 (Ion Badulescu)
o Starfire ethernet driver (Don Becker,
 Ion Badulescu,
 Jeff Garzik, ...)
o Memory handling fixes for ISDN core code (Kai Germaschewski)
o ISDN module locking fixes (Kai Germaschewski)
o Fix ISDN modem profile reading  (Kai Germaschewski)
o Fix missing mark_bh calls in isdn (Kai Germaschewski)
o Fix problems make xconfig has with config  (Andrzej Krzysztofowicz)
o Clean up isdn to user new __init etc (Kai Germaschewski)

111 files changed:
Documentation/Configure.help
MAINTAINERS
Makefile
aic7xxx-5.1.32.patch [new file with mode: 0644]
arch/ppc/config.in
drivers/isdn/divert/divert_procfs.c
drivers/isdn/divert/isdn_divert.c
drivers/isdn/hisax/amd7930.c
drivers/isdn/hisax/arcofi.c
drivers/isdn/hisax/asuscom.c
drivers/isdn/hisax/avm_a1.c
drivers/isdn/hisax/avm_a1p.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/bkm_a4t.c
drivers/isdn/hisax/bkm_a8.c
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/fsm.c
drivers/isdn/hisax/gazel.c
drivers/isdn/hisax/hfc_2bds0.c
drivers/isdn/hisax/hfc_2bs0.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/hisax/hfcscard.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hscx.c
drivers/isdn/hisax/icc.c
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isar.c
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/isdnl2.c
drivers/isdn/hisax/isdnl3.c
drivers/isdn/hisax/isurf.c
drivers/isdn/hisax/ix1_micro.c
drivers/isdn/hisax/jade.c
drivers/isdn/hisax/mic.c
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/netjet.h
drivers/isdn/hisax/niccy.c
drivers/isdn/hisax/nj_s.c
drivers/isdn/hisax/nj_u.c
drivers/isdn/hisax/s0box.c
drivers/isdn/hisax/saphir.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/sportster.c
drivers/isdn/hisax/tei.c
drivers/isdn/hisax/teleint.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/hisax/telespci.c
drivers/isdn/hisax/w6692.c
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_net.c
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_tty.c
drivers/isdn/isdn_v110.c
drivers/net/Config.in
drivers/net/Makefile
drivers/net/cosa.c
drivers/net/eepro100.c
drivers/net/starfire.c [new file with mode: 0644]
drivers/net/starfire_firmware.pl [new file with mode: 0644]
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/aic7xxx/aic7xxx_seq.c
drivers/scsi/hosts.c
drivers/usb/Config.in
drivers/usb/serial/Config.in
fs/dcache.c
fs/inode.c
fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/lockd/host.c
fs/lockd/mon.c
fs/lockd/svc.c
fs/lockd/svc4proc.c
fs/lockd/svclock.c
fs/lockd/svcproc.c
fs/lockd/svcshare.c
fs/lockd/svcsubs.c
fs/locks.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/mount_clnt.c
fs/nfs/nfs3proc.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/symlink.c
fs/nfs/write.c
fs/nfsd/nfsfh.c
include/linux/lockd/nlm.h
include/linux/nfs_fs.h
include/linux/nfs_fs_i.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nfsd/nfsfh.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/xprt.h
ipc/shm.c
net/ax25/ax25_in.c
net/sunrpc/Makefile
net/sunrpc/clnt.c
net/sunrpc/ping.c [new file with mode: 0644]
net/sunrpc/sched.c
net/sunrpc/svcsock.c
net/sunrpc/xprt.c

index e3024aa48e7beddfbac333a17724ddb4179f5af2..d274f7cf15dca95312ff3b8cdf42d07d229a3002 100644 (file)
@@ -6314,6 +6314,18 @@ CONFIG_NET_SB1000
 
   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
index 3f01576d8ddb9b8464625656dfc199ecc2e23875..3d584b77623cac0d79f4e0bd19d42fa31cf8d330 100644 (file)
@@ -938,6 +938,11 @@ M: support@stallion.oz.au
 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 ?
index 7b714e14c6c1aae6a702a6a2163c3796ee8a7063..d5dbbf6a54610409490d201a9cad281ff56954a3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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 --git a/aic7xxx-5.1.32.patch b/aic7xxx-5.1.32.patch
new file mode 100644 (file)
index 0000000..f68d002
--- /dev/null
@@ -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 },
+-
+-};
index f5756a6bab66aa69952bcddf825797c7b490cf79..5802f045b30a9683cbc256c7b2c67c02fad27d56 100644 (file)
@@ -179,8 +179,8 @@ comment 'Mac device drivers'
 
 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
index e860e070c585e0dde16adb4cc5d97bd4586ef51b..65738a2f4d6ec62ffc65763330576be0992b56da 100644 (file)
@@ -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 @@ int
 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);
index f5b6b8773753f30c46b62fd18d3d902b10105207..1970652637f386f0604ed857a6460f0f42daed83 100644 (file)
@@ -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 @@ int cf_command(int drvid, int mode,
   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 ",
index fba32ba4c97c1af061400cd822155aa87f5ba26f..1a8c75ace33e6882b98326478cb644b71174edcd 100644 (file)
@@ -734,8 +734,8 @@ amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init
+setup_amd7930(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 8a46a06359ea006b6fbff786121568cefa55f94e..4ff4d7a4fd9538c0e0383d8ad0fc3d0433ca2c1b 100644 (file)
@@ -128,5 +128,6 @@ init_arcofi(struct IsdnCardState *cs) {
        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);
 }
index 208f1176fa357b6642598c1dfff37389fc2f3d3f..01b668d8ef307e909f6d42f66ce743299d95bdc2 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -306,8 +307,8 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init
+setup_asuscom(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index f02510a795b4c86d4c0f5dd1e260768e30045fce..e2765970ec63bb79d8e04147ccf65d62937185ba 100644 (file)
@@ -8,6 +8,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -171,8 +172,8 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index a6db4fd8ddff0618d823ec87c976b9d89b535919..adbf433376af277a04c4a71d34bf889d0643f924 100644 (file)
@@ -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 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index b214184bfd0c7f018d15d6e61899f4ca4d670dfe..4f107052d9637e27d41c4bbe07fa99d6d6416de3 100644 (file)
@@ -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 @@ setstack_hdlc(struct PStack *st, struct BCState *bcs)
        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 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs))
        }
 }
 
-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 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index 65cee2fd47e321e5f12180910a51133b45be47a2..b9cb063c4f8a0212ccfe81ba145a2f45f14a10a9 100644 (file)
@@ -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 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 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];
index c663fb7e0d2b9060e0fba7445702e103e1e9862b..9d13c31cca8ef156957ae8e68e5cf21b34da1fc0 100644 (file)
@@ -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 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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 @@ static u_char pci_irq __initdata = 0;
 
 #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 @@ setup_sct_quadro(struct IsdnCard *card))
        return (1);
 #else
        printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-       return (0);
 #endif /* CONFIG_PCI */
 }
index b8779b20544ee7758dc45fe8aee1cf51b2874fe0..f632f47d53fcefe37c611a7bc8f917bf9eef325f 100644 (file)
@@ -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 @@ lli_failure_a(struct FsmInst *fi, int event, void *arg)
 }
 
 /* *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 @@ static struct FsmNode fnlist[] HISAX_INITDATA =
 
 #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;
index d8dd323de0d7e6241e037b0dc5b08b9eccb4ae8e..21ddd9182865888debc8baa964afaacea4f85804 100644 (file)
@@ -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 *l3_revision;
 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 @@ HiSax_getrev(const char *revision))
        return rev;
 }
 
-HISAX_INITFUNC(void
-HiSaxVersion(void))
+void __init
+HiSaxVersion(void)
 {
        char tmp[64];
 
@@ -849,7 +850,8 @@ closecard(int cardnr)
        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 @@ HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
        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 @@ checkcard(int cardnr, char *id, int *busy_flag))
        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 @@ checkcard(int cardnr, char *id, int *busy_flag))
        return (1);
 }
 
-HISAX_INITFUNC(void
-HiSax_shiftcards(int idx))
+void 
+HiSax_shiftcards(int idx)
 {
        int i;
 
@@ -1203,8 +1204,8 @@ HiSax_shiftcards(int idx))
                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;
index 8b004b573a8460930f21accd1760ee3851a17ac3..deb981074a3c7c1474bfe387d14435b6dfa9976b 100644 (file)
@@ -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 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index 4efdcbb94b364f9d15c0c4c77bb960c11d7d8bc2..a9ef249433e00069309ebce6f54832f5726926c5 100644 (file)
@@ -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 @@ probe_elsa(struct IsdnCardState *cs)
 static         struct pci_dev *dev_qs1000  = NULL;
 static         struct pci_dev *dev_qs3000  = NULL;
 
-int
+int 
 setup_elsa(struct IsdnCard *card)
 {
        long flags;
index ef43bdb5cd03ddbf61f23cb350cfb4cd8604b020..28a7592309acb2393086bd872cde99a8ce8bb1b9 100644 (file)
  *
  */
 #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;
 
index dcd49dab5771b187e95f17238d7cc83ee397acf2..e64dc28d9ea0babcbf466c6976e0d6a00feffd7e 100644 (file)
@@ -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 @@ setup_gazelpci(struct IsdnCardState *cs)
        return (0);
 }
 
-__initfunc(int
-          setup_gazel(struct IsdnCard *card))
+int __init
+setup_gazel(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index d653dd89d0632dec4930dd3215ec44d9c2c3a9b9..16e7af44844d10d24da85be901f3c36e0ef52c8a 100644 (file)
@@ -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 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
 {
 }
 
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int __init
+*init_send_hfcd(int cnt)
 {
        int i, *send;
 
@@ -1119,8 +1120,8 @@ __initfunc(unsigned int
        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;
index 7792fb4836d7061f446594714346d529f6fc1969..5e76a216fa1b3c148cf0cac294bfb4ebb6f5d35e 100644 (file)
@@ -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 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
        return (0);
 }
 
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init
+init_send(struct BCState *bcs)
 {
        int i;
 
@@ -584,8 +585,8 @@ init_send(struct BCState *bcs))
                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]);
index 1a7824fae2aae09b11a276825286eb29aac84e5c..c673fd881b32391271b82b2da3ed030ce25b3a76 100644 (file)
@@ -24,6 +24,7 @@
  *
  */
 
+#include <linux/init.h>
 #include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
@@ -1571,8 +1572,8 @@ hfcpci_bh(struct IsdnCardState *cs)
 /********************************/
 /* 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 @@ static struct pci_dev *dev_hfcpci __initdata = NULL;
 
 #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;
index 4cabafc1c5e99613318710b069ca07a8602dd9b1..16f6fa72461e364f18a871d250df37329a6046be 100644 (file)
@@ -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 @@ hfcsx_bh(struct IsdnCardState *cs)
 /********************************/
 /* 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 @@ hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 
 
-__initfunc(int
-          setup_hfcsx(struct IsdnCard *card))
+int 
+setup_hfcsx(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 65db2606518e77b7c534f529677243c12ee6fff2..6c06186ae74a296aa05560a0a3f1249e52f35d34 100644 (file)
@@ -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 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_hfcs(struct IsdnCard *card))
+int __init
+setup_hfcs(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index a1b00cb3a7717586948e66e8487ef94ae1ace696..0cb4bd66675264c88ec28909bcd79fa36d56bd04 100644 (file)
@@ -787,8 +787,8 @@ struct te_hw {
        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 @@ struct isac_chip {
        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 @@ struct icc_chip {
        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 @@ struct IsdnCardState {
 #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 @@ struct IsdnCardState {
 #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
index 63acc736a66e486f01fb8cf5ac54e6ebc9f008e0..bb147c088e70408a28140ceacdbbdd64c6633552 100644 (file)
@@ -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 @@ setstack_hscx(struct PStack *st, struct BCState *bcs)
        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 @@ clear_pending_hscx_ints(struct IsdnCardState *cs))
        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 @@ inithscx(struct IsdnCardState *cs))
        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);
index 5360705349f1e409bb89b4b0ccef8bbcd6ed150d..ba0c22cc91c43e3c16ef4cba691dd2ba2cdd4822 100644 (file)
@@ -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 @@ dbusy_timer_handler(struct IsdnCardState *cs)
        }
 }
 
-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 @@ initicc(struct IsdnCardState *cs))
        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;
 
index 7da3503290a73956cea5eb0e434c38794440ca51..e908f948c8f2c65932f5784c2cb005a24798b108 100644 (file)
 #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 @@ dbusy_timer_handler(struct IsdnCardState *cs)
        }
 }
 
-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 @@ initisac(struct IsdnCardState *cs))
        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;
 
index e8de0fd37dea54ae0796a79ec65bfc07ef8131d5..fc16afcda07ad374172117a6ce2073c83f79125c 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isar.h"
 #include "isdnl1.h"
@@ -1782,8 +1783,8 @@ isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
        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;
index 381aa33f5925ea474667bf3bac7f4f367c2c5777..5506b956f8acdf97a2bcb144c0f094bfd46bfa39 100644 (file)
@@ -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 @@ init_bcstate(struct IsdnCardState *cs,
 
        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 @@ l1_activate_no(struct FsmInst *fi, int event, void *arg)
        }
 }
 
-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 @@ l1_activate_u(struct FsmInst *fi, int event, void *arg)
        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 @@ l1b_timer_deact(struct FsmInst *fi, int event, void *arg)
        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 @@ static struct FsmNode L1BFnList[] HISAX_INITDATA =
 
 #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;
index fb46458a9fba0b81238f55e9daaf37e6fa82127a..59d461c0b16c85c0404cce1a49720453a0504c9b 100644 (file)
@@ -12,6 +12,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl2.h"
 
@@ -1533,7 +1534,7 @@ l2_frame_error_reest(struct FsmInst *fi, int event, void *arg)
        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 @@ releasestack_transl2(struct PStack *st)
 {
 }
 
-HISAX_INITFUNC(void
-Isdnl2New(void))
+void __init
+Isdnl2New(void)
 {
        l2fsm.state_count = L2_STATE_COUNT;
        l2fsm.event_count = L2_EVENT_COUNT;
index 8c077fd10c33c60e0d569f624ba2d28f5d6d36be..63636d3d1f48a3305eb53ec65c1769aeb2056189 100644 (file)
  */
 
 #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 @@ lc_release_cnf(struct FsmInst *fi, int event, void *arg)
 
 
 /* *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 @@ l3_msg(struct PStack *st, int pr, void *arg)
        }
 }
 
-HISAX_INITFUNC(void
-Isdnl3New(void))
+void __init
+Isdnl3New(void)
 {
        l3fsm.state_count = L3_STATE_COUNT;
        l3fsm.event_count = L3_EVENT_COUNT;
index da1312aec8695e2c96c8c36d9787caef83356c81..8480f7b74d130dafbd44d44540849a89ae95208c 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "isar.h"
@@ -188,8 +189,8 @@ isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
        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;
index b6186c65618deb0054bd81cf29ebdcf39ce42c36..11e5bd316cbb10f4bb33647ef313d7f3f63af4b1 100644 (file)
@@ -43,6 +43,7 @@
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -243,8 +244,8 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init
+setup_ix1micro(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 99537cd25ffc217eb2453e5d022a5dfa57a438be..47f8c254b62126382e083587ac6d2bdbba1b1f7f 100644 (file)
@@ -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 @@ setstack_jade(struct PStack *st, struct BCState *bcs)
        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 @@ clear_pending_jade_ints(struct IsdnCardState *cs))
        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;
index e24b4868cce5f5a032582aef01a1859d9ad99a8b..abb544866d45b22d9a2d5f37bfa55a14df030106 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -198,8 +199,8 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init
+setup_mic(struct IsdnCard *card)
 {
        int bytecnt;
        struct IsdnCardState *cs = card->cs;
index ac259f9d846ddd160e4af1205545f31e5dca94cd..2904bb3851dcb1d1425b80af8fac8cb2ea002716 100644 (file)
@@ -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 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
 }
 
  
-__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))) {
index 9e8cb26767c6f8905f1ba51cfb9bff43ec7b4ab0..120a98d27edd920b4fa4daaa0f2ae2c4c18f586a 100644 (file)
@@ -65,6 +65,6 @@ void write_tiger(struct IsdnCardState *cs);
 
 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);
 
index 69af57400b86a74117bd59fd525f92ee7d94ce95..6924c3325c722d42604af72fd7b3da4e2ec527da 100644 (file)
@@ -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 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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];
index 2986f8e5ca2b738e97db6a7f5a865b493630597a..bc640a6c503f32b4f5f02c268128ab22b50cedf9 100644 (file)
@@ -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 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index ee02e3c99ac6329c788629882c6b0085b68ff558..67c18a35cc1a2602505691395f26c9106e8bf3db 100644 (file)
@@ -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 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index d0f06c3a50f7f32786261a4cc9e40ba15a6849b6..c29e765e6fa993d46068a4c84bac910a3f3e6a73 100644 (file)
@@ -8,6 +8,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -213,8 +214,8 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 83a52ed37eb03b4899f5d803f90ed69b32e825fa..8f4b7c4736142b51e9e40cac80a74717dc894178 100644 (file)
@@ -12,6 +12,7 @@
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -253,8 +254,8 @@ saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 }
 
 
-__initfunc(int
-setup_saphir(struct IsdnCard *card))
+int __init
+setup_saphir(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index 71df775107e21c07e83264a4697d9325e51d25ca..791405f2709072374c710cc125ce89dc33ea9720 100644 (file)
@@ -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 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        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;
index 6bcec5d1fe4813fda7f87a8a333b60e7132f6e80..2e4e10ff35fdd900c04cfb32e029732a4941930c 100644 (file)
@@ -10,6 +10,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -181,8 +182,8 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+static int __init
+get_io_range(struct IsdnCardState *cs)
 {
        int i, j, adr;
        
index 94e9f4f4375a93834554c8218e1bcb6c15a810cd..a85e54bb67b1dee99448a3909a0033044ceb8d38 100644 (file)
@@ -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 @@ release_tei(struct IsdnCardState *cs)
        }
 }
 
-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 @@ static struct FsmNode TeiFnList[] HISAX_INITDATA =
 
 #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;
index 7caf745134abc59de01c0631dcfb6109aa1914e5..eb65d3c8512c7bc6cc6bc98d2e97bf1f995f380e 100644 (file)
@@ -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 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init
+setup_TeleInt(struct IsdnCard *card)
 {
        struct IsdnCardState *cs = card->cs;
        char tmp[64];
index db0ec5e7b97805f6211c8d2327bfbc6564eb811e..ee2e9e791020ac223c50d5822633c407315da9ab 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl1.h"
 #include "isac.h"
@@ -258,8 +259,8 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init
+setup_teles0(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 1ce7304ba901d7df3faf9c3ee68388acb0fbba3b..04c5a13bda1f4740c7a216dcb33462963d93e622 100644 (file)
@@ -14,6 +14,7 @@
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -253,8 +254,8 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
        return(0);
 }
 
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int 
+setup_teles3(struct IsdnCard *card)
 {
        u_char val;
        struct IsdnCardState *cs = card->cs;
index 0ace09ecb11edda328193c057b8aee356124b199..dda87c51e9d6a603fde844d3284c59628e309219 100644 (file)
@@ -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 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 
 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];
index 081af20f38db3d47017ffa2c7176d76294264e73..6a0012b37315378c22cdad4d43f5b023ecfd146c 100644 (file)
@@ -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 @@ setstack_w6692(struct PStack *st, struct BCState *bcs)
        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;
index e201eb781b050f7cbad6e8d0c549198af4e9b99a..08e4bf0cc9fde71d569848b84a4875e5ce52ce12 100644 (file)
@@ -64,7 +64,7 @@ static char *isdn_audio_revision = ": none $";
 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 void set_global_features(void);
 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 @@ isdn_MOD_INC_USE_COUNT(void)
 }
 
 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 @@ isdn_MOD_DEC_USE_COUNT(void)
                }
 }
 
+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 @@ isdn_getnum(char **p)
  * 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 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                        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_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
                                                     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 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 
 /*
  * 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 @@ isdn_open(struct inode *ino, struct file *filep)
        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 @@ isdn_close(struct inode *ino, struct file *filep)
                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 @@ isdn_close(struct inode *ino, struct file *filep)
                                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 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
        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 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
 
        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 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
                }
                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 @@ set_global_features(void)
 }
 
 #ifdef CONFIG_ISDN_DIVERSION
-extern isdn_divert_if *divert_if;
 
 static char *map_drvname(int di)
 {
@@ -2253,12 +2268,15 @@ isdn_init(void)
        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");
index a9e7bc0289736b9215bb252ea0cd370def9023b0..3ee69282447ba9c3ce4ec488a9728f88e7bb7047 100644 (file)
@@ -46,7 +46,7 @@ extern char *isdn_map_eaz2msn(char *msn, int di);
 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);
index 1d38111ae4119eb9c2c851e855e47beb26a7516c..86bc1d65d0504a79f660d3bb4f67f89184f2d733 100644 (file)
@@ -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 @@ static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
        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 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
 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 @@ void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
                // 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 @@ isdn_net_close(struct device *dev)
 /*
  * 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 @@ isdn_net_new(char *name, struct device *master)
        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 @@ isdn_net_new(char *name, struct device *master)
        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);
index 70d8b3f0e9a115c65b6d25bd4b5c4dc6ee69a28f..92dfc580817e67c0a2725194d9d1e00f4b2835ed 100644 (file)
@@ -233,8 +233,7 @@ isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 
        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 @@ isdn_ppp_closewait(int slot)
                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 @@ isdn_ppp_open(int min, struct file *file)
        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 @@ isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
        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 @@ isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev)
                        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;
        }
 
index e4c8497c9efad7a4f6c151b4db3069a1d2d0cc92..ccf9ecf351e3d8b1b67a692be5435faeb86ad81d 100644 (file)
@@ -1633,8 +1633,7 @@ isdn_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
 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 @@ isdn_tty_modem_init(void)
                        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 @@ isdn_tty_modem_init(void)
                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;
index 08c54a8660228940322e8b08d765bd539334a6e5..4272b69b2ef9e4e208f2d98c41c1dd5633900960 100644 (file)
@@ -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 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
        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 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
        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;
        }
index 979b8d23a38ba2a852f3a74802e625798f2a2984..e1a0d9aaa32f266e367c80254f7f9276d69457cd 100644 (file)
@@ -136,6 +136,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   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
index 1f55e8df8f50ed218814b9c019ebed2754076bed..299c77eb922c7a9fedc0fad5deeb36afb2fbc1fd 100644 (file)
@@ -742,6 +742,14 @@ else
   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
index fa08a9907cc0c39050a36ca7cf5af0b9ee5afba7..0ca0e9b973dc75397eaaf3db4d75c3bf22cb8ee5 100644 (file)
@@ -817,7 +817,7 @@ static ssize_t cosa_read(struct file *file,
        up(&chan->rsem);
 
        if (copy_to_user(buf, kbuf, count)) {
-               kfree(buf);
+               kfree(kbuf);
                return -EFAULT;
        }
        kfree(kbuf);
index 6110d8e3582ee97bac0f8af5d57f6a473bce1083..a630988ae195138379ee64d3c2bb3a8ef69d3de0 100644 (file)
@@ -778,7 +778,7 @@ static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus,
                /* 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 --git a/drivers/net/starfire.c b/drivers/net/starfire.c
new file mode 100644 (file)
index 0000000..b0b0a0e
--- /dev/null
@@ -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
+
+*/
+
+\f
+
+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);
+
+\f
+
+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;
+}
+
+\f
+/* 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;
+}
+
+\f
+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 --git a/drivers/net/starfire_firmware.pl b/drivers/net/starfire_firmware.pl
new file mode 100644 (file)
index 0000000..0c82b80
--- /dev/null
@@ -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);
index 2414ff1bf7106dc4ffb8076eeeaec323260fc178..7cfb497ebb20a5be135ad8975161a11f691aac83 100644 (file)
@@ -270,7 +270,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     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))
index 7f23fd939a15bc46fe663a4c4bbeb1ef2c371cd4..059aecc232efd95e49424e548cf304a5bd7ac983 100644 (file)
@@ -291,11 +291,7 @@ ITloop:
 
        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_state:
        /* 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 @@ u2_sg_advance:
                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 @@ u2_prefetch_avail:
  * 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 @@ u2_phasemis_loop:
                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 @@ u2_phasemis_end:
  * 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 @@ ultra2_dmahalt:
                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 @@ dma_scb_tohost:
                        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;
index 2a161c3c4efa3de7d81894011206904ade3faba8..e1bc140e97350c792d3cb90d61369d9c59a04569 100644 (file)
@@ -7,7 +7,7 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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 @@ static unsigned char seqprog[] = {
        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);
 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);
 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);
 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);
 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);
 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 @@ struct sequencer_patch {
        { 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 },
 
 };
index 2f0d88462dfd9b3e432314c082204803ed62ea4e..0a35483ec90c53c524cb241f771be86793378faf 100644 (file)
 #endif
 
 #ifdef CONFIG_SCSI_AIC7XXX
-#include "aic7xxx.h"
+#include "aic7xxx/aic7xxx.h"
 #endif
 
 #ifdef CONFIG_SCSI_IPS
index 5a5fcab55ac778e87e18c93d10c1ca2d08ec9a23..b8489d13ca6442ea1d81ff9a28585fed50c0b10d 100644 (file)
@@ -29,7 +29,7 @@ comment 'USB Controllers'
    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 @@ comment 'USB Controllers'
       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
index db77957a97820802ca0fd8615cf72cc254da7487..626df43c4d644af81c381daf83402bc06508ebe1 100644 (file)
@@ -16,7 +16,7 @@ if [ "$CONFIG_USB_SERIAL" != "n" ]; then
   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
index e32f5b711cde40948b4d287472483a08e0c99f40..f55eb8be74214823f3c6dcb62e52afccf713c17a 100644 (file)
@@ -573,7 +573,7 @@ struct dentry * d_alloc_root(struct inode * root_inode, struct dentry *old_root)
 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);
 }
 
index d6c141bd8cc5f5579148763495026013beb91b34..cca2311a1918007d9a59f3fbea4c2a0c2a329b23 100644 (file)
@@ -681,7 +681,7 @@ add_new_inode:
 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;
 }
 
index 626eff773ccc248bc53ff0d002f27c4af63d5bce..5a9cce29272daee436a4be448cf74f8ece79f7e8 100644 (file)
@@ -138,18 +138,15 @@ nlmclnt_grant(struct nlm_lock *lock)
 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,8 +165,12 @@ reclaimer(void *ptr)
        /* 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 {
                for (fl = file_lock_table; fl; fl = fl->fl_nextlink) {
index 714bf760547b8ac2bdec9c201d7bc9be1c4629d7..8151c5b638ca7f963d145a51770c05fb68bbf33f 100644 (file)
@@ -46,13 +46,11 @@ nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
 {
        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",
index 82d2e1d390f078d48f98a0469e27694e959c2a90..09ccdb2277d16d434c3cadf30c3d6b8a8e62865e 100644 (file)
@@ -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;
@@ -36,24 +35,6 @@ static struct semaphore              nlm_host_sema = MUTEX;
 
 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
  */
@@ -67,60 +48,33 @@ nlm_match_host(struct nlm_host *host, struct svc_client *clnt,
 }
 
 /*
- * 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 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
        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 @@ nlm_bind_host(struct nlm_host *host)
                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 @@ nlm_shutdown_hosts(void)
        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 @@ nlm_gc_hosts(void)
                        *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--;
                }
index 5fb4e68dc3a026873db5db4de2ff2f2e9bb95dd9..b0d2b387a1ec6000d8ea09e454cbb92056d666c4 100644 (file)
@@ -47,7 +47,7 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
 
        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 @@ nsm_monitor(struct nlm_host *host)
 
        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;
 }
 
index d15062e363e2f6a3f0b6b0623e42ba052978729c..2cc9c1d90bad6b2464b2414ee2a93bc002a1d456 100644 (file)
@@ -77,9 +77,7 @@ lockd(struct svc_rqst *rqstp)
        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 @@ lockd(struct svc_rqst *rqstp)
 #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 @@ lockd(struct svc_rqst *rqstp)
                 */
                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 @@ cleanup_module(void)
  * 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
index f8f6dc62c5b34472f686cf1fdb94dd2f0d980cbe..0aa2f0e3c9082e5ea2e414176ae04fdfbf3f90b2 100644 (file)
@@ -422,6 +422,8 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
                                              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 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
         * 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 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
                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 @@ struct svc_procedure                nlmsvc_procedures4[] = {
   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 @@ struct svc_procedure                nlmsvc_procedures4[] = {
   PROC(nm_lock,                lockargs,       res,            args,   res),
   PROC(free_all,       notify,         void,           args,   void),
 
-  /* statd callback */
-  PROC(sm_notify,      reboot,         void,           reboot, void),
 };
index d5e7f33c9b6c6a9537dc7087753b9e5a7459c4ca..6b2f31cf8ee4abe13b46cf2a66dbd3ca2b99d072 100644 (file)
@@ -53,9 +53,15 @@ nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
        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 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
        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 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
                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 @@ nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
        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 @@ nlmsvc_notify_blocked(struct file_lock *fl)
        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 @@ nlmsvc_grant_blocked(struct nlm_block *block)
        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 @@ callback:
        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 @@ nlmsvc_grant_callback(struct rpc_task *task)
         * 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 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
        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 @@ nlmsvc_retry_blocked(void)
        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)
index eef85a00196364bea43a41619fb01339a0c97520..af01ccf275f9e577b7c4e4064f5451cf1ad870c8 100644 (file)
@@ -435,6 +435,8 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
                                              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 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
        /* 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 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
                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 @@ struct svc_procedure                nlmsvc_procedures[] = {
   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 @@ struct svc_procedure                nlmsvc_procedures[] = {
   PROC(nm_lock,                lockargs,       res,            args,   res),
   PROC(free_all,       notify,         void,           args,   void),
 
-  /* statd callback */
-  PROC(sm_notify,      reboot,         void,           reboot, void),
 };
index 62ee9f2991fae978eb1d4ce0506d3eebcca7674a..80ac81ca8736fa4cd9e7ab962c5bda83f388adfc 100644 (file)
@@ -95,14 +95,16 @@ nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
 
        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;
        }
index f9604bf4ccf5b40f605896bbc576844b5a56a431..633699051a87c10248b3c5cc98a67f763cb29df4 100644 (file)
@@ -150,6 +150,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
        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 @@ again:
                /* 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 @@ nlm_traverse_files(struct nlm_host *host, int action)
 {
        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 @@ nlm_traverse_files(struct nlm_host *host, int action)
                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 @@ nlmsvc_invalidate_client(struct svc_client *clnt)
        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);
        }
 }
index 1444b39fb15cbca1cfb63f97bcf4b8bac5042460..e8a2f78df708c21910c8446c3597df45138a93c7 100644 (file)
@@ -268,20 +268,22 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
 
        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;
index 848a5f3959ab7d9d8c1cc623dd0e9423d74f1bce..b8f748d0f256d1513bdb605652be64e26df13929 100644 (file)
@@ -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 @@ static int nfs_rename(struct inode *, struct dentry *,
                      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 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        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 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
        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 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        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 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
        }
        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 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        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 inline int nfs_neg_need_reval(struct dentry *dentry)
  */
 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 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 
        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 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
                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 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
        /*
         * 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 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
            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 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
        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 @@ static void nfs_dentry_delete(struct dentry *dentry)
        }
 }
 
-__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 @@ struct dentry_operations nfs_dentry_operations = {
        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 @@ static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
  * 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 @@ static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
         * 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 @@ static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
 /*
  * 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 @@ static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int r
 #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 @@ static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int r
 /*
  * 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 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
        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 @@ static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
        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 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
        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 @@ static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
                        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 @@ out:
  */
 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 @@ static int nfs_safe_remove(struct dentry *dentry)
                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_unlink(struct inode *dir, struct dentry *dentry)
 }
 
 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 @@ nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
        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 @@ out:
 }
 
 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 @@ nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
         * 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 @@ nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
 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 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        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 @@ out:
 }
 
 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 @@ nfs_permission(struct inode *i, int msk)
         * 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;
 }
 
 /*
index 40e53d3fe6683d3b265cef856802b233ccdb5e52..4b83a99ca830ea2bfd617f340ebbdcf74c0bbf5d 100644 (file)
@@ -111,13 +111,14 @@ static ssize_t
 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 @@ static int
 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 @@ static int nfs_sync_page(struct page *page)
        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 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
        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 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
         * 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 @@ nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
  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;
 }
index 1616d7c8bb284d9f8d069f5d02ddf881e1e6844a..33653a3c25c88bbbb49ab85bb73c0992020b5077 100644 (file)
 #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 int  nfs_notify_change(struct dentry *, struct iattr *);
 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 @@ nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
                return NULL;
        }
 
-       inode = __nfs_fhget(sb, &fattr);
+       inode = __nfs_fhget(sb, rootfh, &fattr);
        return inode;
 }
 
@@ -273,9 +270,7 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        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 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
                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 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
                        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 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
        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 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
         * 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 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
                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 @@ nfs_read_super(struct super_block *sb, void *raw_data, int silent)
  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 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
        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));
@@ -589,46 +578,6 @@ int nfs_remountfs(struct super_block *sb, int *flags, char *data)
 }
 #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.
  */
@@ -657,7 +606,7 @@ nfs_invalidate_inode(struct inode *inode)
  * 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_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
                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 @@ nfs_make_new_inode(struct super_block *sb, struct nfs_fattr *fattr)
 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 @@ nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
  * 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 @@ nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
                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 @@ __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
 
        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 @@ nfs_notify_change(struct dentry *dentry, struct iattr *attr)
                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 @@ nfs_wait_on_inode(struct inode *inode, int flag)
 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 @@ int nfs_release(struct inode *inode, struct file *filp)
  * 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 @@ __nfs_revalidate_inode(struct dentry *dentry)
                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);
index d70916fd98bac95ccb6c96d6b1c2cdf45a4763a7..ea80d61187a6b073e855ea20710e8baf790cd350 100644 (file)
  */
 
 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 @@ nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
  * 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 @@ xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
 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 @@ xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 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) {
index d3ba0e83e516d8629a65847945e8102dbb9bde33..3244f477683251c9315fd7cb698677431dadb999 100644 (file)
@@ -46,65 +46,67 @@ nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  * 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 @@ nfs3_proc_access(struct dentry *dentry, int mode, struct nfs_fattr *fattr, int r
                        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 @@ nfs3_proc_access(struct dentry *dentry, int mode, struct nfs_fattr *fattr, int r
 }
 
 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 @@ nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr,
 
        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 @@ nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr,
                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 @@ nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr,
  * 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 @@ nfs3_proc_create(struct dentry *dir, struct nfs_fattr *dir_attr,
        }
 
 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 @@ exit:
                 * 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 @@ exit:
 }
 
 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 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr
                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 @@ nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
 
 
 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 @@ nfs3_proc_rmdir(struct dentry *dir, struct nfs_fattr *dir_attr,
  * 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 @@ nfs3_proc_readdir(struct dentry *dir, struct nfs_fattr *dir_attr,
        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 @@ nfs3_proc_mknod(struct dentry *dir, struct nfs_fattr *dir_attr,
        }
 
        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;
 }
index 62616316fb3471df12e9e25e61d26593fdb99f3b..ba3f6ef9988edeb8d50efd1551dda3f4edb022a7 100644 (file)
@@ -77,34 +77,34 @@ nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  * 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 @@ nfs_proc_lookup(struct dentry *dir, fattr *dir_attr, qstr *name,
        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 @@ nfs_proc_read(struct dentry *dentry, fattr *fattr,
 
        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 @@ nfs_proc_read(struct dentry *dentry, fattr *fattr,
 }
 
 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 @@ nfs_proc_write(struct dentry *dentry, fattr *fattr,
        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 @@ nfs_proc_write(struct dentry *dentry, fattr *fattr,
 }
 
 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 @@ nfs_proc_create(struct dentry *dir, fattr *dir_attr,
        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 @@ nfs_proc_create(struct dentry *dir, fattr *dir_attr,
  * 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 @@ nfs_proc_mknod(struct dentry *dir, fattr *dir_attr,
                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 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *
        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 @@ nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg)
 }
 
 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 @@ nfs_proc_rename(struct dentry *old_dir, fattr *old_attr, qstr *old_name,
        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 @@ nfs_proc_symlink(struct dentry *dir, fattr *dir_attr, qstr *name,
        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 @@ nfs_proc_mkdir(struct dentry *dir, fattr *dir_attr, qstr *name,
        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 @@ nfs_proc_rmdir(struct dentry *dir, fattr *dir_attr, qstr *name)
  * 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 @@ nfs_proc_readdir(struct dentry *dir, fattr *dir_attr,
        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 @@ nfs_proc_readdir(struct dentry *dir, fattr *dir_attr,
        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;
index c56ff28040a9cb6fcf06a2020f3f66ed685e768f..71d842c042b61f918c3bab92e38f21bd3dcaf66f 100644 (file)
@@ -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 @@ static void nfs_readdata_release(struct rpc_task *task)
  * 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 @@ nfs_readpage_sync(struct file *file, struct page *page)
                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 @@ nfs_find_read(struct inode *inode, struct page *page)
 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 @@ nfs_mark_request_read(struct nfs_page *req)
 }
 
 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 @@ nfs_readpage_async(struct file *file, struct page *page)
                }
 
                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 @@ nfs_read_rpcsetup(struct list_head *head, struct nfs_read_data *data)
                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 @@ nfs_async_read_error(struct list_head *head)
 }
 
 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 @@ nfs_pagein_one(struct list_head *head, struct dentry *dentry)
        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 @@ nfs_pagein_list(struct inode *inode, struct list_head *head)
        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 @@ static void
 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 @@ nfs_readpage_result(struct rpc_task *task)
                        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 @@ nfs_readpage_result(struct rpc_task *task)
 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 @@ nfs_readpage(struct file *file, struct page *page)
                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");
 
index f90b792061c3ac22d7d3256375a2e7f2ea39b0d4..00fce2773baaa9678df4a88ce976683dbb8e446a 100644 (file)
@@ -57,19 +57,16 @@ struct inode_operations nfs_symlink_inode_operations = {
 /* 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 @@ static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
 
        /* 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 @@ nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
 
        /* 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;
 
index dc907bbb7eb0d9dda98d5b61d7e2ce40cf6bda6b..00c10bcc53462ff23667b29188acd55aa2191789 100644 (file)
@@ -66,7 +66,7 @@ static unsigned int   nfs_nr_requests = 0;
  */
 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 @@ nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
  * 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 @@ nfs_writepage_sync(struct file *file, struct page *page,
                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 @@ io_error:
 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 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
                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 @@ nfs_inode_remove_request(struct nfs_page *req)
 
        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 @@ void nfs_list_remove_request(struct nfs_page *req)
 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 @@ nfs_mark_request_dirty(struct nfs_page *req)
 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 @@ nfs_dirty_request(struct nfs_page *req)
 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 @@ nfs_mark_request_commit(struct nfs_page *req)
  * 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 @@ struct nfs_page *nfs_create_request(struct file *file, struct page *page,
        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 @@ struct nfs_page *nfs_create_request(struct file *file, struct page *page,
 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 @@ nfs_release_request(struct nfs_page *req)
        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 @@ nfs_release_request(struct nfs_page *req)
 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 @@ int nfs_coalesce_requests(struct list_head *src, struct list_head *dst, unsigned
  * 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 @@ nfs_update_request(struct file* file, struct page *page,
                 */
                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 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
         * 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 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
         * 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 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
                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 @@ nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
  * 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 @@ nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
        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 @@ nfs_flush_list(struct inode *inode, struct list_head *head, int how)
        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 @@ nfs_writeback_done(struct rpc_task *task)
        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_writeback_done(struct rpc_task *task)
                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 @@ static void
 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 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
        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 @@ nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
                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 @@ nfs_commit_list(struct list_head *head, int how)
        /* 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 @@ nfs_commit_done(struct rpc_task *task)
        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 @@ nfs_commit_done(struct rpc_task *task)
                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) {
index 56808a4c8856d0a34b798eda1101428984362898..b01bc5819febc9df3074d69e24653863945e8aa8 100644 (file)
@@ -679,7 +679,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
        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;
index fdced15968607b91798beea6787aab40c16255cf..eb9b24a7b257ba0206e0795a4ba55dab68cf4aa6 100644 (file)
@@ -45,10 +45,10 @@ enum {
 #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 */
index b20219f34fb0423a98921dfaed9170c7b1858724..36df06e286cac58c8660ca4898a5a129a79bd54f 100644 (file)
@@ -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 @@ do { \
 
 #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 @@ do { \
 #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 @@ unsigned long page_index(struct page *page)
 /*
  * 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 void nfs_zap_caches(struct inode *);
 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 @@ extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
  * 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 @@ nfs_time_to_secs(__u64 time)
 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 */
index b0583fe2cee7bca004e78feb3662672d2304fea4..7fdec4624e1ea996890b9e41796524dd87994b01 100644 (file)
@@ -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>
 
@@ -21,6 +22,11 @@ struct nfs_inode_info {
        __u64 fsid;
        __u64 fileid;
 
+       /*
+        * NFS file handle
+        */
+       struct nfs_fh           fh;
+
        /*
         * Various flags
         */
@@ -79,12 +85,10 @@ struct nfs_inode_info {
 /*
  * 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 */
 
 /*
index f65f59d14d80a696b7d981b34bda696a53bf7183..d96d8c6b8ceff7aa3ae19ddb4c2f7f85ebe1e70d 100644 (file)
@@ -26,7 +26,7 @@ struct nfs_page {
                                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 @@ struct nfs_page {
 #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);
index 7d4babe9f671fa1f32fffb7566c63e678fc1f0a9..279845a086305591709b8972f8f3a927c533f35b 100644 (file)
@@ -321,48 +321,43 @@ struct nfs_rpc_ops {
 
        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);
index a58c0c9dd4e048321acaf6b0bf561581d6643272..89260f2ef24432efd9e68aaa3095e3e70ebd46a6 100644 (file)
@@ -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 @@ struct knfs_fh {
        __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
index 3f8d354bd0f820f4c87e02b799bc66657e17d39d..aaeec2c75349c1aa0338020b00188b90efe3a947 100644 (file)
@@ -111,6 +111,8 @@ int         rpc_destroy_client(struct rpc_clnt *);
 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);
 
@@ -144,5 +146,10 @@ extern void rpciod_wake_up(void);
  */
 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 */
index 7bcba579f93836e6c39d1a955f2d1f948f134be5..b9555695b5a1f8a77a1696a5a06785435d1d1e8b 100644 (file)
@@ -45,7 +45,7 @@ struct rpc_task {
        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 @@ struct rpc_task {
        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,11 +111,21 @@ typedef void                      (*rpc_action)(struct rpc_task *);
 #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
  */
index bd183df6ff802def1b5aa52d7f3be2bf832ffd69..6f5d80c09393f3133008b05365de9e565e924e4a 100644 (file)
  * 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_rqst {
        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_xprt {
        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 @@ void                      xprt_set_timeout(struct rpc_timeout *, unsigned int,
                                        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 @@ void rpciod_tcp_dispatcher(void)
                __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__*/
 
index b978f2a207f13556fcde2eb4fc48948f6e20d42d..4a33fa8fe85060781de7070a5f22bd75a6be7e3a 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -340,8 +340,6 @@ asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
                        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;
index 17e1bb246a44dcb35ea083c768006714317f1e9b..2e48c22b1148cc21c566568bb6b6fbc5e5aef2fe 100644 (file)
@@ -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 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
                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 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                                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 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a
                                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
index 1bf4f60700d951e1b02badadbeaa234eeb0d6773..222c57eb19c51d6256489f9209c74f3b798578da 100644 (file)
@@ -11,7 +11,7 @@ O_TARGET := sunrpc.o
 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)
index 8b1c7db63df2751903db91247466e24333b5a2fc..e32b797cba6bc9b0807834ac71e7bfae5a55caa6 100644 (file)
@@ -55,8 +55,8 @@ static void   call_refresh(struct rpc_task *task);
 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 @@ call_encode(struct rpc_task *task)
 
        /* 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 @@ call_status(struct rpc_task *task)
                        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 @@ call_timeout(struct rpc_task *task)
 {
        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 @@ call_timeout(struct rpc_task *task)
                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 @@ minor_timeout:
        } 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 @@ call_decode(struct rpc_task *task)
        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_refreshresult(struct rpc_task *task)
 /*
  * 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;
@@ -780,11 +772,62 @@ call_header(struct rpc_task *task)
        return rpcauth_marshcred(task, p);
 }
 
+/*
+ * 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 --git a/net/sunrpc/ping.c b/net/sunrpc/ping.c
new file mode 100644 (file)
index 0000000..3ff0d58
--- /dev/null
@@ -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);
+}
index 122f78e8a22a550772d90f936159a39a9af25386..52a45fe0284db215f4f36ebfc19ce8428201834c 100644 (file)
@@ -259,7 +259,7 @@ __rpc_make_runnable(struct rpc_task *task)
                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 @@ __rpc_make_runnable(struct rpc_task *task)
                        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 @@ __rpc_schedule_run(struct rpc_task *task)
        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 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
        /* 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 @@ __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
                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 @@ restarted:
 
                /*
                 * 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 @@ restarted:
 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;
 }
 
 /*
index 103a5f486cf0ddb26013d5f87d5e429d16057c06..488330912e9b89a10bef03b433b97b7c057bf06e 100644 (file)
@@ -773,7 +773,6 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
                        "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 @@ again:
        /* 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;
index ff0cd53c7048e9cb2d8264e1152face6442e71c6..b846d679e7541ab440d3913a6450e53799ed351f 100644 (file)
@@ -1010,7 +1010,8 @@ tcp_state_change(struct sock *sk)
 
        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 @@ tcp_write_space(struct sock *sk)
        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 @@ udp_write_space(struct sock *sk)
        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 @@ xprt_down_transmit(struct rpc_task *task)
 {
        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 @@ xprt_down_transmit(struct rpc_task *task)
 #endif
                req->rq_bytes_sent = 0;
        }
+       spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
        return xprt->snd_task == task;
 }
 
@@ -1142,9 +1142,12 @@ xprt_up_transmit(struct rpc_task *task)
        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 @@ do_xprt_transmit(struct rpc_task *task)
                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 @@ do_xprt_transmit(struct rpc_task *task)
        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 @@ xprt_receive(struct rpc_task *task)
 
        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);
 }
@@ -1419,6 +1414,62 @@ xprt_release(struct rpc_task *task)
        end_bh_atomic();
 }
 
+/*
+ * 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
  */
@@ -1490,6 +1541,7 @@ xprt_setup(struct socket *sock, int proto,
        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++)