]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.43 2.1.43
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:24 +0000 (15:13 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:13:24 +0000 (15:13 -0500)
38 files changed:
CREDITS
Documentation/Configure.help
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/README.aic7xxx
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.h
drivers/scsi/aic7xxx.seq [new file with mode: 0644]
drivers/scsi/aic7xxx/Makefile [deleted file]
drivers/scsi/aic7xxx/aic7xxx.reg [deleted file]
drivers/scsi/aic7xxx/aic7xxx.seq [deleted file]
drivers/scsi/aic7xxx/aic7xxx_asm.c [deleted file]
drivers/scsi/aic7xxx/aic7xxx_asm.h [deleted file]
drivers/scsi/aic7xxx/bsd_q.h [deleted file]
drivers/scsi/aic7xxx/gram.y [deleted file]
drivers/scsi/aic7xxx/scan.l [deleted file]
drivers/scsi/aic7xxx/scsi_message.h [deleted file]
drivers/scsi/aic7xxx/sequencer.h [deleted file]
drivers/scsi/aic7xxx/symbol.c [deleted file]
drivers/scsi/aic7xxx/symbol.h [deleted file]
drivers/scsi/aic7xxx_asm.c [new file with mode: 0644]
drivers/scsi/aic7xxx_proc.c
drivers/scsi/aic7xxx_reg.h
drivers/sound/dmabuf.c
fs/buffer.c
fs/dcache.c
fs/inode.c
fs/namei.c
fs/nfs/write.c
include/linux/dalloc.h
include/linux/mm.h
include/linux/swap.h
mm/memory.c
mm/page_alloc.c
mm/page_io.c
mm/swap_state.c
mm/swapfile.c
mm/vmscan.c

diff --git a/CREDITS b/CREDITS
index 96beb8066a3c77e451b9495714cf5ccb9cc8efd8..33d2c8b892892c706e594c1c6ba4ad00924b27a6 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1394,7 +1394,7 @@ S: Sevilla 41005
 S: Spain
 
 N: Linus Torvalds
-E: Linus.Torvalds@Helsinki.FI
+E: torvalds@transmeta.com
 W: http://www.cs.helsinki.fi/~torvalds/
 P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A  BE 67 3C 24 03 13 62 C8
 D: Original kernel hacker
index f4b8ef406bc62d57177f5b0af43f1793db887dd8..863c1d3acb2c330e1201cec92f8d46d2775416be 100644 (file)
@@ -1637,67 +1637,20 @@ CONFIG_SCSI_AHA1740
   want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
-Adaptec AIC7xxx support (includes 274x/284x/294x)
+Adaptec AHA274X/284X/294X support
 CONFIG_SCSI_AIC7XXX
   Information about this SCSI host adapter is contained in
   drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
-  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that
-  the AHA2920 SCSI host adapter is *not* supported by this driver; choose
-  "Future Domain 16xx SCSI support" instead. If you want to compile this
-  driver 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. The module will be called aic7xxx.o.
-
-Enable tagged command queueing
-CONFIG_AIC7XXX_TAGGED_QUEUEING
-  This option allows you to enable tagged command queueing for this
-  driver.  Some scsi devices do not properly support this
-  feature.  Tagged command queueing will improve performance.
-
-Maximum number of commands per LUN
-  CONFIG_AIC7XXX_CMDS_PER_LUN
-  This option allows you to set the maximum number of commands queued
-  per LUN.  If tagged queueing is enabled, then you may want to try
-  increasing AIC7XXX_CMDS_PER_LUN to more than 2.  By default, we limit
-  the SCBs per LUN to 2 with or without tagged queueing enabled.  If
-  tagged queueing is disabled, the sequencer will keep the 2nd SCB in
-  the input queue until the first one completes - so it is OK to to have
-  more than 1 SCB queued.  If tagged queueing is enabled, then the
-  sequencer will attempt to send the 2nd SCB to the device while the
-  first SCB is executing and the device is disconnected.  For adapters
-  limited to 4 SCBs, you may want to actually decrease the commands per
-  LUN to 1, if you often have more than 2 devices active at the same
-  time.  This will allocate 1 SCB for each device and ensure that there
-  will always be a free SCB for up to 4 devices active at the same time.
-  When SCB paging is enabled, set the commands per LUN to 8 or higher
-  (see SCB paging support below).  Note that if AIC7XXX_CMDS_PER_LUN is
-  not defined and tagged queueing is enabled, the driver will attempt to
-  set the commands per LUN using its own heuristic based on the number
-  of available SCBs.
-
-Enable SCB paging
-CONFIG_AIC7XXX_PAGE_ENABLE
-  This option enables SCB paging.  This will increase performance when
-  tagged queueing is enabled.  Note that you should increase the
-  AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices allow at
-  least this many
-
-Use external SCB bank
-CONFIG_AIC7XXX_USE_EXT_SCBRAM
-  This option enables use of the external bank of 255 SCBs.  For 3985
-  adapters, this will also enable sharing of the SCB array across all
-  three controllers.
-
-Collect statistics to report in /proc
-CONFIG_AIC7XXX_PROC_STATS
-  This option enables collection of SCSI transfer statistics for the
-  /proc filesystem.  Do NOT enable this when running on kernels version
-  1.2.x and below.  This does affect performance since it has to
-  maintain statistics.
-
-Delay in seconds after SCSI bus reset
-CONFIG_AIC7XXX_RESET_DELAY
-  This option sets the delay in seconds after a SCSI bus reset.
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it
+  doesn't work out of the box, you may have to change some settings in
+  drivers/scsi/aic7xxx.h. It has been reported that the "wide
+  negotiation" on these cards is not quite working and should be
+  disabled. Note that the AHA2920 SCSI host adapter is *not* supported
+  by this driver; choose "Future Domain 16xx SCSI support" instead. If
+  you want to compile this driver 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. The module will be
+  called aic7xxx.o.
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
@@ -3659,33 +3612,6 @@ CONFIG_ISP16_CDI
   be called isp16.o. If you want to compile it as a module, say M here
   and read Documentation/modules.txt.
 
-New inode implementation
-CONFIG_NEW_INODE
-  This option should disappear in future when the new inode cache
-  becomes standard. For the meantime, you may switch back to the old
-  code if you have trouble with the new one.
-
-New dcache implementation
-CONFIG_NEW_DCACHE
-  The new dcache is a generic one. In contrast to the old dcache,
-  it operates on the VFS level, independently from the concrete
-  filesystems. One benefit of this option is that all symlinks
-  in /proc/<pid>/fd now point to the real file location, with
-  full absolute path.
-  The main benefit of this option is the *basket*:
-  Any deleted file "foo" will be automatically renamed to
-  ".deleted-<some-number>.foo" in a non-permanent way, so that it remains
-  accessible as long as the machine is not rebooted. Currently, a
-  maximum number of 100 files can be kept in the basket (the limit
-  is because it eats up inodes). If space gets low on the filesystem,
-  the basket will (should) be automatically cleared until enough
-  space is available. This currently works only with ext2, but other
-  filesystems need only little modification to support this also.
-  Please check whether (and in which cases) you get
-  speedups by the new code. Before making measurements, be sure that
-  all debugging code is #undef'ed from fs/ndcache.c, fs/ninode.c,
-  and fs/namei.c . 
-
 Preload dcache
 CONFIG_DCACHE_PRELOAD
   Preloading will create dcache entries when a directory is scanned
index 9178871dfe221fd1631caaa48b7c3d65d04cd5e6..b5734501944600ae3bcf98d958cbaf6a4d20694c 100644 (file)
@@ -21,15 +21,7 @@ dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
 dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
 dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
 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' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
-    int  '   Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
-    bool '   Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
-    bool '   Use external SCB bank' CONFIG_AIC7XXX_USE_EXT_SCBRAM N
-    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-    int  '   delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
-fi
+dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
index ed2b0a46ac05d69b6f07c31e7993135e270461b3..e6f98e4e49301ca46c51f9f5c47d8452b1f783fa 100644 (file)
@@ -421,16 +421,12 @@ BusLogic.o: BusLogic.c FlashPoint.c
 aha152x.o: aha152x.c
        $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c 
 
-aic7xxx/aic7xxx_asm:   aic7xxx/aic7xxx_asm.c
-       (cd ./aic7xxx; make aic7xxx_asm)
+aic7xxx_asm:   aic7xxx_asm.c
+       $(HOSTCC) -o $@ aic7xxx_asm.c
 
-aic7xxx_seq.h aic7xxx_reg.h:   aic7xxx/aic7xxx_asm aic7xxx/aic7xxx.seq
-       ./aic7xxx/aic7xxx_asm -nostdinc -I- -Iaic7xxx -o aic7xxx_seq.h \
-               -r aic7xxx_reg.h aic7xxx/aic7xxx.seq
-
-aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
-       $(CC) $(CFLAGS) -c -o $@ aic7xxx.c
-       (cd aic7xxx; make clean_most)
+aic7xxx.c: aic7xxx_seq.h
+aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
+       ./aic7xxx_asm -o $@ aic7xxx.seq
 
 seagate.o: seagate.c
        $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c 
index 21da229cc353adb2849c9e3a4fb5f9ac1ccc20a5..ccbf4a6e2ab26d2fad1760d4254c8c86c4715d51 100644 (file)
@@ -1,5 +1,5 @@
                            AIC7xxx Driver for Linux
-                                June 11, 1997
+                                April 15, 1996
 
 Introduction
 ------------------------
@@ -31,7 +31,6 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     -----------------------
     AIC-777x   
     AIC-785x
-    AIC-786x
     AIC-787x
     AIC-788x
 
@@ -59,7 +58,6 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
     Dan Eischen     deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
     Dean Gehnert    deang@teleport.com             (Linux FTP/patch maintainer)
     Jess Johnson    jester@frenzy.com              (AIC7xxx FAQ author)
-    Doug Ledford    dledford@dialnet.net           (Stress tester/bug squasher)
 
     Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
     author of the driver. John has since retired from the project. Thanks
@@ -113,5 +111,5 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
 Dean W. Gehnert
 deang@teleport.com
 
-$Revision: 3.1 $
+$Revision: 3.0 $
 
index 5026f841c2a10d73e56e93504e2b6d8af7360802..96e66defdd8a2a4bd7e4a48c1b5ae06db3bb98ca 100644 (file)
@@ -1,3 +1,5 @@
+#define EXPERIMENTAL_FLAGS 0
+
 /*+M*************************************************************************
  * Adaptec AIC7xxx device driver for Linux.
  *
  *  Parts of this driver are based on the FreeBSD driver by Justin
  *  T. Gibbs.
  *
- *  Thanks also go to (in alphabetical order) the following:
- *
- *    Rory Bolt     - Sequencer bug fixes
- *    Jay Estabrook - Initial DEC Alpha support
- *    Doug Ledford  - Much needed abort/reset bug fixes
- *    Kai Makisara  - DMAing of SCBs
- *
  *  A Boot time option was also added for not resetting the scsi bus.
  *
- *    Form:  aic7xxx=extended
- *           aic7xxx=no_reset
- *           aic7xxx=ultra
- *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
- *           aic7xxx=verbose
+ *    Form:  aic7xxx=extended,no_reset
  *
- *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
+ *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
  *
- *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
+ *  $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
  *-M*************************************************************************/
 
 #ifdef MODULE
 #include "scsi.h"
 #include "hosts.h"
 #include "aic7xxx.h"
-
-#ifndef u_int8_t
-typedef unsigned char u_int8_t;
-#endif
-#include "aic7xxx/bsd_q.h"
-#include "aic7xxx/sequencer.h"
-#include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
-#include "aic7xxx_seq.h"
 #include <linux/stat.h>
 #include <linux/malloc.h>      /* for kmalloc() */
 
@@ -96,20 +79,16 @@ typedef unsigned char u_int8_t;
  */
 #define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
 
-struct proc_dir_entry proc_scsi_aic7xxx = {
+static struct proc_dir_entry proc_scsi_aic7xxx = {
     PROC_SCSI_AIC7XXX, 7, "aic7xxx",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2,
-    0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+    S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.1 $"
+#define AIC7XXX_C_VERSION  "$Revision: 4.0 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
-#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
+#define MIN(a,b)        ((a < b) ? a : b)
 #define ALL_TARGETS -1
-#define ALL_CHANNELS '\0'
-#define ALL_LUNS -1
 #ifndef TRUE
 #  define TRUE 1
 #endif
@@ -128,8 +107,11 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *     support because all PCI dependent code is bracketed with
  *     "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
  *
- *   o Twin bus support - this has been tested and does work.  It is
- *     not an option anymore.
+ *   o Twin bus support - this has been tested and does work.
+ *
+ *   o DMAing of SCBs - thanks to Kai Makisara, this now works.
+ *     This define is now taken out and DMAing of SCBs is always
+ *     performed (8/12/95 - DE).
  *
  *   o Tagged queueing - this driver is capable of tagged queueing
  *     but I am unsure as to how well the higher level driver implements
@@ -158,16 +140,16 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *     LUN using its own heuristic based on the number of available
  *     SCBs.
  *
- *   o 3985 support - The 3985 adapter is much like the 3940, but has
- *     three 7870 controllers as opposed to two for the 3940.  It will
- *     be probed and recognized as three different adapters, but all
- *     three controllers can share the same external bank of 255 SCBs.
- *     If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
- *     to use and share the common bank of SCBs between the three
- *     controllers of the 3985.  This is experimental and hasn't been
- *     been tested.  By default, we do not use external SCB RAM, and
- *     force the controllers to use their own internal bank of 16 SCBs.
- *     Please let us know if using the external SCB array works.
+ *   o 3985 support - The 3985 adapter is much like the 3940, but
+ *     has three 7870 controllers as opposed to two for the 3940.
+ *     It will get probed and recognized as three different adapters,
+ *     but all three controllers can share the same external bank of
+ *     255 SCBs.  If you enable AIC7XXX_SHARE_SCBS, then the driver
+ *     will attempt to share the common bank of SCBs between the three
+ *     controllers of the 3985.  This is experimental and hasn't
+ *     been tested.  By default, we do not share the bank of SCBs,
+ *     and force the controllers to use their own internal bank of
+ *     16 SCBs.  Please let us know if sharing the SCB array works.
  *
  *   o SCB paging support - SCB paging is enabled by defining
  *     AIC7XXX_PAGE_ENABLE.  Support for this was taken from the
@@ -180,54 +162,43 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  *  Note that sharing of IRQs is not an option any longer.  Linux supports
  *  it so we support it.
  *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 06/30/96
  */
 
+/* Uncomment this for testing twin bus support. */
+#define AIC7XXX_TWIN_SUPPORT
+
 /* Uncomment this for tagged queueing. */
-#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
-#define AIC7XXX_TAGGED_QUEUEING
-#endif
+/* #define AIC7XXX_TAGGED_QUEUEING */
 
 /*
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
-#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
-#endif
+/* #define AIC7XXX_CMDS_PER_LUN 8 */
 
 /* Set this to the delay in seconds after SCSI bus reset. */
-#ifdef CONFIG_AIC7XXX_RESET_DELAY
-#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
-#else
 #define AIC7XXX_RESET_DELAY 15
-#endif
 
 /*
- * Control collection of SCSI transfer statistics for the /proc filesystem.
+ * Uncomment the following define for collection of SCSI transfer statistics
+ * for the /proc filesystem.
  *
  * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
  * NOTE: This does affect performance since it has to maintain statistics.
  */
-#ifdef CONFIG_AIC7XXX_PROC_STATS
-#define AIC7XXX_PROC_STATS
-#endif
+/* #define AIC7XXX_PROC_STATS */
 
 /*
- * Enable SCB paging.
+ * Uncomment the following to enable SCB paging.
  */
-#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
-#define AIC7XXX_PAGE_ENABLE
-#endif
+/* #define AIC7XXX_PAGE_ENABLE */
 
 /*
- * Uncomment the following to enable use of the external bank
- * of 255 SCBs.  For 3985 adapters, this will also enable sharing
- * of the SCB array across all three controllers.
+ * Uncomment the following to enable sharing of the external bank
+ * of 255 SCBs for the 3985.
  */
-#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
-#define AIC7XXX_USE_EXT_SCBRAM
-#endif
+#define AIC7XXX_SHARE_SCBS
 
 /*
  * For debugging the abort/reset code.
@@ -239,86 +210,6 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
  */
 #define AIC7XXX_DEBUG
 
-/*
- * Set this for defining the number of tagged commands on a device
- * by device, and controller by controller basis.  The first set
- * of tagged commands will be used for the first detected aic7xxx
- * controller, the second set will be used for the second detected
- * aic7xxx controller, and so on.  These values will *only* be used
- * for targets that are tagged queueing capable; these values will
- * be ignored in all other cases.  The tag_commands is an array of
- * 16 to allow for wide and twin adapters.  Twin adapters will use
- * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
- *
- * *** Determining commands per LUN ***
- * 
- * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
- * own algorithm to determine the commands/LUN.  If SCB paging is
- * enabled, the commands/LUN is 8.  When SCB paging is not enabled,
- * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
- * and 4 commands/LUN for adapters with 3 or 4 SCBs.
- *
- */
-/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
-
-#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
-typedef struct
-{
-  unsigned char tag_commands[16];   /* Allow for wide/twin channel adapters. */
-} adapter_tag_info_t;
-
-/*
- * Make a define that will tell the driver to use it's own algorithm
- * for determining commands/LUN (see Determining commands per LUN
- * above).
- */
-#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-
-/*
- * Modify this as you see fit for your system.  By setting tag_enable
- * to 0, the driver will use it's own algorithm for determining the
- * number of commands to use (see above).  When -1, the driver will
- * not enable tagged queueing for that particular device.  When positive
- * (> 0) the values in the array are used for the queue_depth.
- *
- * In this example, the first line will enable tagged queueing for all
- * the devices on the first probed aic7xxx adapter and tells the driver
- * to use it's own algorithm for determining commands/LUN.
- *
- * The second line enables tagged queueing with 4 commands/LUN for IDs
- * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
- * driver to use its own algorithm for ID 1.
- *
- * The third line is the same as the first line.
- *
- * The fourth line disables tagged queueing for devices 0 and 3.  It
- * enables tagged queueing for the other IDs, with 16 commands/LUN
- * for IDs 1 and 4, 128 commands/LUN for ID 8, and 4 commands/LUN for
- * IDs 2, 5-7, and 9-15.
- */
-adapter_tag_info_t aic7xxx_tag_info[] =
-{
-  {DEFAULT_TAG_COMMANDS},
-  {4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4},
-  {DEFAULT_TAG_COMMANDS},
-  {-1, 16, 4, -1, 16, 4, 4, 4, 128, 4, 4, 4, 4, 4, 4, 4}
-};
-#endif
-
-/*
- * Don't define this unless you have problems with the driver
- * interrupt handler.  The old method would register the drivers
- * interrupt handler as a "fast" type interrupt handler that would
- * lock out other interrupts.  Since this driver can spend a lot
- * of time in the interrupt handler, this is _not_ a good idea.
- * It also conflicts with some of the more common ethernet drivers
- * that don't use fast interrupts.  Currently, Linux does not allow
- * IRQ sharing unless both drivers can agree on the type of interrupt
- * handler.
- */
-/* #define AIC7XXX_OLD_ISR_TYPE */
-
-
 /*
  * Controller type and options
  */
@@ -341,15 +232,14 @@ typedef enum {
   AIC_7882,    /* PCI  aic7882 on 3940 Ultra */
   AIC_7883,    /* PCI  aic7883 on 3985 Ultra */
   AIC_7884     /* PCI  aic7884 on 294x Ultra Differential */
-} aha_chip_type;
+} aha_type;
 
 typedef enum {
   AIC_777x,    /* AIC-7770 based */
-  AIC_785x,    /* AIC-7850 based (3 SCBs)*/
-  AIC_786x,    /* AIC-7860 based (7850 ultra) */
+  AIC_785x,    /* AIC-7850 based */
   AIC_787x,    /* AIC-7870 based */
-  AIC_788x     /* AIC-7880 based (ultra) */
-} aha_chip_class_type;
+  AIC_788x     /* AIC-7880 based */
+} aha_chip_type;
 
 typedef enum {
   AIC_SINGLE,  /* Single Channel */
@@ -379,24 +269,24 @@ typedef enum {
  * Don't forget to change this when changing the types!
  */
 static const char *board_names[] = {
-  "AIC-7xxx Unknown",                                  /* AIC_NONE */
-  "Adaptec AIC-7770 SCSI host adapter",                        /* AIC_7770 */
-  "Adaptec AHA-274X SCSI host adapter",                        /* AIC_7771 */
-  "Adaptec AHA-284X SCSI host adapter",                        /* AIC_284x */
-  "Adaptec AIC-7850 SCSI host adapter",                        /* AIC_7850 */
-  "Adaptec AIC-7855 SCSI host adapter",                        /* AIC_7855 */
-  "Adaptec AIC-7860 Ultra SCSI host adapter",          /* AIC_7860 */
-  "Adaptec AHA-2940A Ultra SCSI host adapter",         /* AIC_7861 */
-  "Adaptec AIC-7870 SCSI host adapter",                        /* AIC_7870 */
-  "Adaptec AHA-294X SCSI host adapter",                        /* AIC_7871 */
-  "Adaptec AHA-394X SCSI host adapter",                        /* AIC_7872 */
-  "Adaptec AHA-398X SCSI host adapter",                        /* AIC_7873 */
-  "Adaptec AHA-2944 SCSI host adapter",                        /* AIC_7874 */
-  "Adaptec AIC-7880 Ultra SCSI host adapter",          /* AIC_7880 */
-  "Adaptec AHA-294X Ultra SCSI host adapter",          /* AIC_7881 */
-  "Adaptec AHA-394X Ultra SCSI host adapter",          /* AIC_7882 */
-  "Adaptec AHA-398X Ultra SCSI host adapter",          /* AIC_7883 */
-  "Adaptec AHA-2944 Ultra SCSI host adapter"           /* AIC_7884 */
+  "<AIC-7xxx Unknown>",                /* AIC_NONE */
+  "AIC-7770",                  /* AIC_7770 */
+  "AHA-2740",                  /* AIC_7771 */
+  "AHA-2840",                  /* AIC_284x */
+  "AIC-7850",                  /* AIC_7850 */
+  "AIC-7855",                  /* AIC_7855 */
+  "AIC-7850 Ultra",            /* AIC_7860 */
+  "AHA-2940A Ultra",           /* AIC_7861 */
+  "AIC-7870",                  /* AIC_7870 */
+  "AHA-2940",                  /* AIC_7871 */
+  "AHA-3940",                  /* AIC_7872 */
+  "AHA-3985",                  /* AIC_7873 */
+  "AHA-2940 Differential",     /* AIC_7874 */
+  "AIC-7880 Ultra",            /* AIC_7880 */
+  "AHA-2940 Ultra",            /* AIC_7881 */
+  "AHA-3940 Ultra",            /* AIC_7882 */
+  "AHA-3985 Ultra",            /* AIC_7883 */
+  "AHA-2940 Ultra Differential"        /* AIC_7884 */
 };
 
 /*
@@ -420,17 +310,12 @@ static const char *board_names[] = {
  */
 #define DID_RETRY_COMMAND DID_ERROR
 
-#define HSCSIID        0x07
-#define HWSCSIID       0x0F
-#define SCSI_RESET     0x040
-
 /*
  * EISA/VL-bus stuff
  */
 #define MINSLOT                1
 #define MAXSLOT                15
 #define SLOTBASE(x)    ((x) << 12)
-#define BASE_TO_SLOT(x) ((x) >> 12)
 
 /*
  * Standard EISA Host ID regs  (Offset from slot base)
@@ -448,6 +333,14 @@ static const char *board_names[] = {
 
 #define INTDEF         0x5C            /* Interrupt Definition Register */
 
+/*
+ * Some defines for the HCNTRL register.
+ */
+#define        REQ_PAUSE       IRQMS | INTEN | PAUSE
+#define        UNPAUSE_274X    IRQMS | INTEN
+#define        UNPAUSE_284X    INTEN
+#define        UNPAUSE_294X    IRQMS | INTEN
+
 /*
  * AIC-78X0 PCI registers
  */
@@ -484,7 +377,7 @@ static const char *board_names[] = {
  * each word, while the C56 and C66 (4096 bits) use 8 bits to
  * address each word.
  */
-typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
+typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
 
 /*
  *
@@ -524,15 +417,15 @@ struct seeprom_config {
 /*
  * Host Adapter Control Bits
  */
-#define CFAUTOTERM      0x0001          /* Perform Auto termination */
+/* UNUSED               0x0001 */
 #define CFULTRAEN       0x0002          /* Ultra SCSI speed enable (Ultra cards) */
 #define CF284XSELTO     0x0003          /* Selection timeout (284x cards) */
 #define CF284XFIFO      0x000C          /* FIFO Threshold (284x cards) */
-#define CFSTERM         0x0004          /* SCSI low byte termination */
+#define CFSTERM         0x0004          /* SCSI low byte termination (non-wide cards) */
 #define CFWSTERM        0x0008          /* SCSI high byte termination (wide card) */
 #define CFSPARITY      0x0010          /* SCSI parity */
 #define CF284XSTERM    0x0020          /* SCSI low byte termination (284x cards) */
-#define CFRESETB       0x0040          /* reset SCSI bus at boot */
+#define CFRESETB       0x0040          /* reset SCSI bus at IC initialization */
 /* UNUSED              0xFF80 */
   unsigned short adapter_control;      /* word 17 */
 
@@ -555,17 +448,36 @@ struct seeprom_config {
   unsigned short checksum;             /* word 31 */
 };
 
-#define SELBUS_MASK            0x0a
-#define        SELNARROW       0x00
-#define        SELBUSB         0x08
-#define SINGLE_BUS             0x00
 
-#define SCB_TARGET(scb)         \
-       (((scb)->hscb->target_channel_lun & TID) >> 4)
-#define SCB_LUN(scb)            \
-       ((scb)->hscb->target_channel_lun & LID)
-#define SCB_IS_SCSIBUS_B(scb)   \
-       (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
+#define SCSI_RESET 0x040
+
+/*
+ * Pause the sequencer and wait for it to actually stop - this
+ * is important since the sequencer can disable pausing for critical
+ * sections.
+ */
+#define PAUSE_SEQUENCER(p) \
+  synchronize_irq();                                   \
+  outb(p->pause, HCNTRL + p->base);                    \
+  while ((inb(HCNTRL + p->base) & PAUSE) == 0)         \
+    ;                                                  \
+
+/*
+ * Unpause the sequencer. Unremarkable, yet done often enough to
+ * warrant an easy way to do it.
+ */
+#define UNPAUSE_SEQUENCER(p) \
+  outb(p->unpause, HCNTRL + p->base)
+
+/*
+ * Restart the sequencer program from address zero
+ */
+#define RESTART_SEQUENCER(p) \
+  do {                                                 \
+    outb(SEQRESET | FASTMODE, SEQCTL + p->base);       \
+  } while (inb(SEQADDR0 + p->base) != 0 &&             \
+          inb(SEQADDR1 + p->base) != 0);               \
+  UNPAUSE_SEQUENCER(p);
 
 /*
  * If an error occurs during a data transfer phase, run the command
@@ -628,6 +540,12 @@ static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
  */
 static int aic7xxx_spurious_count;
 
+/*
+ * The driver keeps up to four scb structures per card in memory. Only the
+ * first 25 bytes of the structure are valid for the hardware, the rest used
+ * for driver level bookkeeping.
+ */
+
 /*
  * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
  * in the scatter-gather lists.  We need to convert the virtual
@@ -643,47 +561,18 @@ struct hw_scatterlist {
  */
 #define        MAX_SG 256
 
-/*
- * The maximum number of SCBs we could have for ANY type
- * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
- * SEQUENCER CODE IF THIS IS MODIFIED!
- */
-#define AIC7XXX_MAXSCB 255
-
-/*
- * We keep a pool of kernel memory for hardware scatter/gather
- * arrays.  One page (PAGE_SIZE) of kernel memory is allocated
- * at a time, and SG arrays are taken from this pool.  An SG
- * array is 2048 bytes (256 * 8) long.  A page of memory is either
- * 4096 (i386) or 8192 (alpha) bytes from which SG arrays can be
- * taken without fragmenting memory.
- *
- * The number of free SG arrays left in the SG pool is kept in
- * aic7xxx_sg_arrays_free.  The pool of SG arrays is kept in
- * aic7xxx_next_sg_array; after each each allocation of an SG array,
- * this variable is updated to point to the next available SG array
- * in the pool.  When aic7xxx_sg_arrays_free is zero, a new page is
- * allocated for the pool.  See aic7xxx_allocate_sglist() for
- * further details.
- *
- * The SG memory pool is global to the driver, and is not per
- * instance of the driver.
- */
-static struct hw_scatterlist *aic7xxx_next_sg_array = NULL;
-static int aic7xxx_sg_arrays_free = 0;
-
-struct aic7xxx_hwscb {
+struct aic7xxx_scb {
 /* ------------    Begin hardware supported fields    ---------------- */
 /* 0*/  unsigned char control;
 /* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
 /* 2*/  unsigned char target_status;
 /* 3*/  unsigned char SG_segment_count;
-/* 4*/  unsigned int  SG_list_pointer;
+/* 4*/  unsigned char SG_list_pointer[4] __attribute__ ((packed));
 /* 8*/  unsigned char residual_SG_segment_count;
-/* 9*/  unsigned char residual_data_count[3];
-/*12*/  unsigned int  data_pointer;
-/*16*/  unsigned int  data_count;
-/*20*/  unsigned int  SCSI_cmd_pointer;
+/* 9*/  unsigned char residual_data_count[3] __attribute__ ((packed));
+/*12*/  unsigned char data_pointer[4] __attribute__ ((packed));
+/*16*/  unsigned int  data_count __attribute__ ((packed)); /* must be 32 bits */
+/*20*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
 /*24*/  unsigned char SCSI_cmd_length;
 /*25*/ u_char tag;                     /* Index into our kernel SCB array.
                                         * Also used as the tag for tagged I/O
@@ -691,47 +580,29 @@ struct aic7xxx_hwscb {
 #define SCB_PIO_TRANSFER_SIZE  26      /* amount we need to upload/download
                                         * via PIO to initialize a transaction.
                                         */
-/*26*/  unsigned char next;             /* Used to thread SCBs awaiting selection
+/*26*/  u_char next;                    /* Used to thread SCBs awaiting selection
                                          * or disconnected down in the sequencer.
                                          */
-/*27*/  unsigned char prev;
-/*28*/  unsigned int pad;               /*
-                                         * Unused by the kernel, but we require
-                                         * the padding so that the array of
-                                         * hardware SCBs is alligned on 32 byte
-                                         * boundaries so the sequencer can index
-                                         */
-};
-
-typedef enum {
-       SCB_FREE                = 0x0000,
-       SCB_ACTIVE              = 0x0001,
-       SCB_ABORTED             = 0x0002,
-       SCB_DEVICE_RESET        = 0x0004,
-       SCB_SENSE               = 0x0008,
-       SCB_TIMEDOUT            = 0x0010,
-       SCB_QUEUED_FOR_DONE     = 0x0020,
-       SCB_RECOVERY_SCB        = 0x0040,
-       SCB_WAITINGQ            = 0x0080,
-       SCB_ASSIGNEDQ           = 0x0100,
-       SCB_SENTORDEREDTAG      = 0x0200,
-       SCB_MSGOUT_SDTR         = 0x0400,
-       SCB_MSGOUT_WDTR         = 0x0800,
-       SCB_ABORT               = 0x1000,
-       SCB_QUEUED_ABORT        = 0x2000
-} scb_flag_type;
-
-struct aic7xxx_scb {
-        struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
-       Scsi_Cmnd             *cmd;           /* Scsi_Cmnd for this scb */
-        struct aic7xxx_scb    *q_next;        /* next scb in queue */
-       scb_flag_type          flags;         /* current state of scb */
-       struct hw_scatterlist *sg_list;       /* SG list in adapter format */
-        unsigned char          sg_count;
-       unsigned char          sense_cmd[6];  /*
-                                               * Allocate 6 characters for
-                                               * sense command.
-                                               */
+       /*-----------------end of hardware supported fields----------------*/
+       Scsi_Cmnd          *cmd;        /* Scsi_Cmnd for this scb */
+        struct aic7xxx_scb *q_next;     /* next scb in queue */
+#define SCB_FREE               0x00
+#define SCB_ACTIVE             0x01
+#define SCB_ABORTED            0x02
+#define SCB_DEVICE_RESET       0x04
+#define SCB_IMMED              0x08
+#define SCB_SENSE              0x10
+#define SCB_QUEUED_FOR_DONE    0x40
+#define SCB_PAGED_OUT          0x80
+#define SCB_WAITINGQ           0x100
+#define SCB_ASSIGNEDQ          0x200
+#define SCB_SENTORDEREDTAG     0x400
+#define SCB_IN_PROGRESS        (SCB_ACTIVE | SCB_PAGED_OUT | \
+                                SCB_WAITINGQ | SCB_ASSIGNEDQ)
+       int                 state;          /* current state of scb */
+       unsigned int        position;       /* Position in scb array */
+       struct hw_scatterlist  sg_list[MAX_SG]; /* SG list in adapter format */
+       unsigned char       sense_cmd[6];   /* Allocate 6 characters for sense command */
 };
 
 /*
@@ -756,17 +627,20 @@ static unsigned char
 generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
 
 typedef struct {
-  struct aic7xxx_hwscb *hscbs;
   scb_queue_type free_scbs;        /*
                                     * SCBs assigned to free slot on
                                     * card (no paging required)
                                     */
-  unsigned char  numscbs;          /* current number of scbs */
-  unsigned char  maxhscbs;         /* hardware scbs */
-  unsigned char  maxscbs;          /* max scbs including pageable scbs */
-  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
-  unsigned int   reserve[100];
-} scb_data_type;
+  int            numscbs;          /* current number of scbs */
+  int            activescbs;       /* active scbs */
+} scb_usage_type;
+
+/*
+ * The maximum number of SCBs we could have for ANY type
+ * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ * SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB 255
 
 /*
  * Define a structure used for each host adapter, only one per IRQ.
@@ -774,26 +648,17 @@ typedef struct {
 struct aic7xxx_host {
   struct Scsi_Host        *host;             /* pointer to scsi host */
   int                      host_no;          /* SCSI host number */
-  int                      instance;         /* aic7xxx instance number */
-  int                      scsi_id;          /* host adapter SCSI ID */
-  int                      scsi_id_b;        /*   channel B for twin adapters */
-  int                      irq;              /* IRQ for this adapter */
   int                      base;             /* card base address */
-  unsigned int             mbase;            /* I/O memory address */
-  volatile unsigned char  *maddr;            /* memory mapped address */
-#define A_SCANNED               0x0001
-#define B_SCANNED               0x0002
-#define EXTENDED_TRANSLATION    0x0004
-#define FLAGS_CHANNEL_B_PRIMARY 0x0008
-#define MULTI_CHANNEL           0x0010
-#define ULTRA_ENABLED           0x0020
-#define PAGE_ENABLED            0x0040
-#define USE_DEFAULTS            0x0080
-#define BIOS_ENABLED            0x0100
-#define IN_ISR                  0x0200
-#define IN_TIMEOUT              0x0400
-#define SHARED_SCBDATA          0x0800
-#define HAVE_SEEPROM            0x1000
+  int                      maxhscbs;         /* hardware SCBs */
+  int                      maxscbs;          /* max SCBs (including pageable) */
+#define A_SCANNED              0x0001
+#define B_SCANNED              0x0002
+#define EXTENDED_TRANSLATION   0x0004
+#define HAVE_SEEPROM           0x0008
+#define ULTRA_ENABLED          0x0010
+#define PAGE_ENABLED           0x0020
+#define IN_ISR                 0x0040
+#define USE_DEFAULTS           0x0080
   unsigned int             flags;
   unsigned int             isr_count;        /* Interrupt count */
   unsigned short           needsdtr_copy;    /* default config */
@@ -804,22 +669,36 @@ struct aic7xxx_host {
   unsigned short           wdtr_pending;
   unsigned short           orderedtag;
   unsigned short           discenable;      /* Targets allowed to disconnect */
-  aha_chip_type            chip_type;        /* card type */
-  aha_chip_class_type      chip_class;
+  aha_type                 type;             /* card type */
+  aha_chip_type            chip_type;        /* chip base type */
   aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  unsigned char            chan_num;         /* for 39xx, channel number */
+  char *                   mbase;            /* I/O memory address */
+  unsigned char            chan_num;         /* for 3940/3985, channel number */
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   unsigned char            qcntmask;
-  unsigned char            qfullcount;
-  unsigned char            curqincnt;
+  struct seeprom_config    seeprom;
   struct Scsi_Host        *next;             /* allow for multiple IRQs */
-  unsigned char            activescbs;       /* active scbs */
+  struct aic7xxx_scb      *scb_array[AIC7XXX_MAXSCB];  /* active commands */
+  struct aic7xxx_scb      *pagedout_ntscbs[16];  /*
+                                                  * paged-out, non-tagged scbs
+                                                  * indexed by target.
+                                                  */
+  scb_queue_type           page_scbs;        /*
+                                              * SCBs that will require paging
+                                              * before use (no assigned slot)
+                                              */
   scb_queue_type           waiting_scbs;     /*
-                                              * SCBs waiting for space in
-                                              * the QINFIFO.
+                                              * SCBs waiting to be paged and
+                                              * started.
                                               */
-  scb_data_type           *scb_data;
+  scb_queue_type           assigned_scbs;    /*
+                                              * SCBs that were waiting but have
+                                              * have now been assigned a slot
+                                              * by aic7xxx_free_scb
+                                              */
+  scb_usage_type           scb_usage;
+  scb_usage_type          *scb_link;
 
   struct aic7xxx_cmd_queue {
     Scsi_Cmnd *head;
@@ -831,7 +710,6 @@ struct aic7xxx_host {
 #define  BUS_DEVICE_RESET_PENDING       0x02
     int  flags;
     int  commands_sent;
-    int  active_cmds;
   } device_status[16];
 #ifdef AIC7XXX_PROC_STATS
   /*
@@ -857,10 +735,34 @@ struct aic7xxx_host {
 #endif /* AIC7XXX_PROC_STATS */
 };
 
+struct aic7xxx_host_config {
+  int              irq;        /* IRQ number */
+  int              mbase;      /* memory base address*/
+  int              base;       /* I/O base address*/
+  int              maxhscbs;   /* hardware SCBs */
+  int              maxscbs;    /* max SCBs (including pageable) */
+  int              unpause;    /* unpause value for HCNTRL */
+  int              pause;      /* pause value for HCNTRL */
+  int              scsi_id;    /* host SCSI ID */
+  int              scsi_id_b;  /* host SCSI ID B channel for twin cards */
+  unsigned int     flags;      /* used the same as struct aic7xxx_host flags */
+  int              chan_num;   /* for 3940/3985, channel number */
+  unsigned char    busrtime;   /* bus release time */
+  unsigned char    bus_speed;  /* bus speed */
+  unsigned char    qcntmask;
+  aha_type         type;       /* card type */
+  aha_chip_type    chip_type;  /* chip base type */
+  aha_bus_type     bus_type;   /* normal/twin/wide bus */
+  aha_status_type  bios;       /* BIOS is enabled/disabled */
+  aha_status_type  parity;     /* bus parity enabled/disabled */
+  aha_status_type  low_term;   /* bus termination low byte */
+  aha_status_type  high_term;  /* bus termination high byte (wide cards only) */
+};
+
 /*
  * Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns/4 to the proper value to
- * stick in the SCSIRATE reg to use that transfer rate.
+ * Provides a mapping of transfer periods in ns to the proper value to
+ * stick in the scsiscfr reg to use that transfer rate.
  */
 static struct {
   short period;
@@ -869,17 +771,17 @@ static struct {
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
-  { 12,  0x100,  "20.0"  },
-  { 15,  0x110,  "16.0"  },
-  { 18,  0x120,  "13.4"  },
-  { 25,  0x000,  "10.0"  },
-  { 31,  0x010,   "8.0"  },
-  { 37,  0x020,   "6.67" },
-  { 43,  0x030,   "5.7"  },
-  { 50,  0x040,   "5.0"  },
-  { 56,  0x050,   "4.4"  },
-  { 62,  0x060,   "4.0"  },
-  { 68,  0x070,   "3.6"  }
+  {  50,  0x100,  "20.0"  },
+  {  62,  0x110,  "16.0"  },
+  {  75,  0x120,  "13.4"  },
+  { 100,  0x000,  "10.0"  },
+  { 125,  0x010,   "8.0"  },
+  { 150,  0x020,   "6.67" },
+  { 175,  0x030,   "5.7"  },
+  { 200,  0x040,   "5.0"  },
+  { 225,  0x050,   "4.4"  },
+  { 250,  0x060,   "4.0"  },
+  { 275,  0x070,   "3.6"  }
 };
 
 static int num_aic7xxx_syncrates =
@@ -888,51 +790,166 @@ static int num_aic7xxx_syncrates =
 #ifdef CONFIG_PCI
 static int number_of_3940s = 0;
 static int number_of_3985s = 0;
-#endif /* CONFIG_PCI */
+#ifdef AIC7XXX_SHARE_SCBS
+static scb_usage_type *shared_3985_scbs = NULL;
+#endif
+#endif CONFIG_PCI
 
 #ifdef AIC7XXX_DEBUG
 
+static void
+debug_config(struct aic7xxx_host_config *p)
+{
+  int scsi_conf;
+  unsigned char brelease;
+  unsigned char dfthresh;
+
+  static int DFT[] = { 0, 50, 75, 100 };
+  static int SST[] = { 256, 128, 64, 32 };
+  static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
+
+  scsi_conf = inb(SCSICONF + p->base);
+
+  /*
+   * Scale the Data FIFO Threshhold and the Bus Release Time; they are
+   * stored in formats compatible for writing to sequencer registers.
+   */
+  dfthresh = p->bus_speed  >> 6;
+
+  if (p->chip_type == AIC_777x)
+  {
+    brelease = p->busrtime >> 2;
+  }
+  else
+  {
+    brelease = p->busrtime;
+  }
+  if (brelease == 0)
+  {
+    brelease = 2;
+  }
+
+  switch (p->type)
+  {
+    case AIC_7770:
+    case AIC_7771:
+      printk("%s%s AT EISA SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
+             p->base >> 12);
+      break;
+
+    case AIC_284x:
+      printk("%s%s AT VLB SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
+             p->base >> 12);
+      break;
+
+    case AIC_7850:
+    case AIC_7855:
+    case AIC_7860:
+    case AIC_7861:
+    case AIC_7870:
+    case AIC_7871:
+    case AIC_7872:
+    case AIC_7873:
+    case AIC_7874:
+    case AIC_7880:
+    case AIC_7881:
+    case AIC_7882:
+    case AIC_7883:
+    case AIC_7884:
+      printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type],
+             BUSW[p->bus_type], p->base, p->mbase);
+      break;
+
+    default:
+      panic("aic7xxx: (debug_config) internal error.\n");
+  }
+
+  printk("    irq %d\n"
+        "    bus release time %d bclks\n"
+        "    data fifo threshold %d%%\n",
+        p->irq,
+        brelease,
+        DFT[dfthresh]);
+
+  printk("    SCSI CHANNEL A:\n"
+        "        scsi id %d\n"
+        "        scsi selection timeout %d ms\n"
+        "        scsi bus reset at power-on %sabled\n",
+        scsi_conf & 0x07,
+        SST[(scsi_conf >> 3) & 0x03],
+        (scsi_conf & 0x40) ? "en" : "dis");
+
+  if ((p->chip_type == AIC_777x) && (p->parity == AIC_UNKNOWN))
+  {
+    /*
+     * Set the parity for 7770 based cards.
+     */
+    p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
+  }
+  if (p->parity != AIC_UNKNOWN)
+  {
+    printk("        scsi bus parity %sabled\n",
+          (p->parity == AIC_ENABLED) ? "en" : "dis");
+  }
+
+  if ((p->type == AIC_7770) || (p->type == AIC_7771))
+  {
+    p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
+  }
+  if (p->low_term != AIC_UNKNOWN)
+  {
+    printk("        scsi bus termination (low byte) %sabled\n",
+         (p->low_term == AIC_ENABLED) ? "en" : "dis");
+  }
+  if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
+  {
+    printk("        scsi bus termination (high byte) %sabled\n",
+         (p->high_term == AIC_ENABLED) ? "en" : "dis");
+  }
+}
+
 #if 0
 static void
 debug_scb(struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_hwscb *hscb = scb->hscb;
-
-  printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
-    scb,
-    hscb->control,
-    hscb->target_channel_lun,
-    hscb->SCSI_cmd_length,
-    hscb->SCSI_cmd_pointer );
-  printk("        datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
-    hscb->data_count,
-    hscb->data_pointer,
-    hscb->SG_segment_count,
-    hscb->SG_list_pointer);
-  printk("        sg_addr:%lx sg_len:%ld\n",
-    hscb->sg_list[0].address,
-    hscb->sg_list[0].length);
+  printk("control 0x%x, tcl 0x%x, sg_count %d, sg_ptr 0x%x, cmdp 0x%x, cmdlen %d\n",
+         scb->control, scb->target_channel_lun, scb->SG_segment_count,
+         (scb->SG_list_pointer[3] << 24) | (scb->SG_list_pointer[2] << 16) |
+         (scb->SG_list_pointer[1] << 8) | scb->SG_list_pointer[0],
+         (scb->SCSI_cmd_pointer[3] << 24) | (scb->SCSI_cmd_pointer[2] << 16) |
+         (scb->SCSI_cmd_pointer[1] << 8) | scb->SCSI_cmd_pointer[0],
+         scb->SCSI_cmd_length);
+  printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
+         (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
+         scb->residual_SG_segment_count,
+         ((scb->residual_data_count[2] << 16) |
+          (scb->residual_data_count[1] <<  8) |
+          (scb->residual_data_count[0]));
+  printk("data ptr 0x%x, data count %d, next waiting %d\n",
+         (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
+         (scb->data_pointer[1] << 8) | scb->data_pointer[0],
+         scb->data_count, scb->next_waiting);
+  printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
+         (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
+         scb->position);
 }
 #endif
 
 #else
+#  define debug_config(x)
 #  define debug_scb(x)
 #endif AIC7XXX_DEBUG
 
-#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                        (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
-                        ((scb->hscb)->target_channel_lun & 0x07)
-
-#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                       (((scb->hscb)->target_channel_lun >> 3) & 0x01)
-
-#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+#define TCL_OF_SCB(x)  (((x)->target_channel_lun >> 4) & 0xf),  \
+                       (((x)->target_channel_lun >> 3) & 0x01), \
+                       ((x)->target_channel_lun & 0x07)
 
-#define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
+#define TARGET_INDEX(x)  ((x)->target | ((x)->channel << 3))
 
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
- *       cards in the system.  This should be fixed.
+ *       cards in the system. This should be fixed, but then,
+ *       does anyone really have more than one in a machine?
  */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
@@ -942,53 +959,6 @@ static int aic7xxx_irq_trigger = -1;         /*
                                               *  1 use level triggered
                                               */
 static int aic7xxx_enable_ultra = 0;         /* enable ultra SCSI speeds */
-static int aic7xxx_verbose = 0;                     /* verbose messages */
-
-
-/****************************************************************************
- *
- * These functions are not used yet, but when we do memory mapped
- * IO, we'll use them then.
- *
- ***************************************************************************/
-static inline unsigned char
-aic_inb(struct aic7xxx_host *p, long port)
-{
-  if (p->maddr != NULL)
-    return (p->maddr[port]);
-  else
-    return (inb(p->base + port));
-}
-
-static inline void
-aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
-{
-  if (p->maddr != NULL)
-    p->maddr[port] = val;
-  else
-    outb(val, p->base + port);
-}
-
-static inline void
-aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
-{
-  if (p->maddr != NULL)
-  {
-    __asm __volatile("
-      cld;
-    1:  lodsb;
-      movb %%al,(%0);
-      loop 1b"      :
-              :
-      "r" ((p)->maddr + (port)),
-      "S" ((valp)), "c" ((size))  :
-      "%esi", "%ecx", "%eax");
-  }
-  else
-  {
-    outsb(p->base + port, valp, size);
-  }
-}
 
 /*+F*************************************************************************
  * Function:
@@ -1013,7 +983,6 @@ aic7xxx_setup(char *s, int *dummy)
     { "no_reset",    &aic7xxx_no_reset },
     { "irq_trigger", &aic7xxx_irq_trigger },
     { "ultra",       &aic7xxx_enable_ultra },
-    { "verbose",     &aic7xxx_verbose },
     { NULL,          NULL }
   };
 
@@ -1039,328 +1008,150 @@ aic7xxx_setup(char *s, int *dummy)
 
 /*+F*************************************************************************
  * Function:
- *   pause_sequencer
+ *   aic7xxx_loadseq
  *
  * Description:
- *   Pause the sequencer and wait for it to actually stop - this
- *   is important since the sequencer can disable pausing for critical
- *   sections.
+ *   Load the sequencer code into the controller memory.
  *-F*************************************************************************/
-static inline void
-pause_sequencer(struct aic7xxx_host *p)
+static void
+aic7xxx_loadseq(int base)
 {
-  outb(p->pause, p->base + HCNTRL);
-  while ((inb(p->base + HCNTRL) & PAUSE) == 0);
-  {
-    ;
-  }
-}
+  static unsigned char seqprog[] = {
+    /*
+     * Each sequencer instruction is 29 bits
+     * long (fill in the excess with zeroes)
+     * and has to be loaded from least -> most
+     * significant byte, so this table has the
+     * byte ordering reversed.
+     */
+#   include "aic7xxx_seq.h"
+  };
 
-/*+F*************************************************************************
- * Function:
- *   unpause_sequencer
- *
- * Description:
- *   Unpause the sequencer. Unremarkable, yet done often enough to
- *   warrant an easy way to do it.
- *-F*************************************************************************/
-static inline void
-unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
-{
-  if (unpause_always ||
-      ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
-  {
-    outb(p->unpause, p->base + HCNTRL);
-  }
+  /*
+   * When the AIC-7770 is paused (as on chip reset), the
+   * sequencer address can be altered and a sequencer
+   * program can be loaded by writing it, byte by byte, to
+   * the sequencer RAM port - the Adaptec documentation
+   * recommends using REP OUTSB to do this, hence the inline
+   * assembly. Since the address autoincrements as we load
+   * the program, reset it back to zero afterward. Disable
+   * sequencer RAM parity error detection while loading, and
+   * make sure the LOADRAM bit is enabled for loading.
+   */
+  outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
+
+  outsb(SEQRAM + base, seqprog, sizeof(seqprog));
+
+  /*
+   * WARNING!  This is a magic sequence!  After extensive
+   * experimentation, it seems that you MUST turn off the
+   * LOADRAM bit before you play with SEQADDR again, else
+   * you will end up with parity errors being flagged on
+   * your sequencer program. (You would also think that
+   * turning off LOADRAM and setting SEQRESET to reset the
+   * address to zero would work, but you need to do it twice
+   * for it to take effect on the address. Timing problem?)
+   */
+  do {
+    /*
+     * Actually, reset it until
+     * the address shows up as
+     * zero just to be safe..
+     */
+    outb(SEQRESET | FASTMODE, SEQCTL + base);
+  } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
 }
 
 /*+F*************************************************************************
  * Function:
- *   restart_sequencer
+ *   aic7xxx_delay
  *
  * Description:
- *   Restart the sequencer program from address zero.  This assumes
- *   that the sequencer is already paused.
+ *   Delay for specified amount of time.
  *-F*************************************************************************/
-static inline void
-restart_sequencer(struct aic7xxx_host *p)
+static void
+aic7xxx_delay(int seconds)
 {
-  /* Set the sequencer address to 0. */
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
+  unsigned long i;
 
-  /*
-   * Reset and unpause the sequencer.  The reset is suppose to
-   * start the sequencer running, but we do an unpause to make
-   * sure.
-   */
-  outb(SEQRESET | FASTMODE, p->base + SEQCTL);
+  i = jiffies + (seconds * HZ);  /* compute time to stop */
 
-  unpause_sequencer(p, /*unpause_always*/ TRUE);
+  while (jiffies < i)
+  {
+    ;  /* Do nothing! */
+  }
 }
 
-
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_next_patch
+ *   rcs_version
  *
  * Description:
- *   Find the next patch to download.
+ *   Return a string containing just the RCS version number from either
+ *   an Id or Revision RCS clause.
  *-F*************************************************************************/
-static struct patch *
-aic7xxx_next_patch(struct patch *cur_patch, int options, int instrptr)
+static const char *
+rcs_version(const char *version_info)
 {
-  while (cur_patch != NULL)
+  static char buf[10];
+  char *bp, *ep;
+
+  bp = NULL;
+  strcpy(buf, "????");
+  if (!strncmp(version_info, "$Id: ", 5))
   {
-    if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
-      || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
-      || (instrptr >= cur_patch->end))
+    if ((bp = strchr(version_info, ' ')) != NULL)
     {
-      /*
-       * Either we want to keep this section of code, or we have consumed
-       * this patch.  Skip to the next patch.
-       */
-      cur_patch++;
-      if (cur_patch->options == 0)
+      bp++;
+      if ((bp = strchr(bp, ' ')) != NULL)
       {
-        /* Out of patches. */
-        cur_patch = NULL;
+       bp++;
       }
     }
-    else
+  }
+  else
+  {
+    if (!strncmp(version_info, "$Revision: ", 11))
     {
-      /* Found an OK patch. */
-      break;
+      if ((bp = strchr(version_info, ' ')) != NULL)
+      {
+       bp++;
+      }
+    }
+  }
+
+  if (bp != NULL)
+  {
+    if ((ep = strchr(bp, ' ')) != NULL)
+    {
+      register int len = ep - bp;
+
+      strncpy(buf, bp, len);
+      buf[len] = '\0';
     }
   }
-  return (cur_patch);
-}
 
+  return buf;
+}
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_download_instr
+ *   aic7xxx_info
  *
  * Description:
- *   Find the next patch to download.
+ *   Return a string describing the driver.
  *-F*************************************************************************/
-static void
-aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
+const char *
+aic7xxx_info(struct Scsi_Host *notused)
 {
-  unsigned char opcode;
-  struct ins_format3 *instr;
-
-  instr = (struct ins_format3 *) &seqprog[instrptr * 4];
-  /* Pull the opcode */
-  opcode = instr->opcode_addr >> 1;
-  switch (opcode)
-  {
-    case AIC_OP_JMP:
-    case AIC_OP_JC:
-    case AIC_OP_JNC:
-    case AIC_OP_CALL:
-    case AIC_OP_JNE:
-    case AIC_OP_JNZ:
-    case AIC_OP_JE:
-    case AIC_OP_JZ:
-    {
-      int address_offset;
-      struct ins_format3 new_instr;
-      unsigned int address;
-      struct patch *patch;
-      int i;
-
-      address_offset = 0;
-      new_instr = *instr;  /* Strucure copy */
-      address = new_instr.address;
-      address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
-      for (i = 0; i < NUMBER(patches); i++)
-      {
-        patch = &patches[i];
-        if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
-            (((patch->options & options) != 0) && (patch->negative == TRUE)))
-        {
-          if (address >= patch->end)
-          {
-            address_offset += patch->end - patch->begin;
-          }
-        }
-      }
-      address -= address_offset;
-      new_instr.address = address &0xFF;
-      new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
-      new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
-      outsb(p->base + SEQRAM, &new_instr.immediate, 4);
-      break;
-    }
-
-    case AIC_OP_OR:
-    case AIC_OP_AND:
-    case AIC_OP_XOR:
-    case AIC_OP_ADD:
-    case AIC_OP_ADC:
-    case AIC_OP_ROL:
-      outsb(p->base + SEQRAM, &instr->immediate, 4);
-      break;
-
-    default:
-      panic("aic7xxx: Unknown opcode encountered in sequencer program.");
-      break;
-  }
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_loadseq
- *
- * Description:
- *   Load the sequencer code into the controller memory.
- *-F*************************************************************************/
-static void
-aic7xxx_loadseq(struct aic7xxx_host *p)
-{
-  int options;
-  struct patch *cur_patch;
-  int i;
-  int downloaded;
-
-  if (aic7xxx_verbose)
-  {
-    printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
-  }
-  options = 1;  /* Code for all options. */
-  downloaded = 0;
-  if ((p->flags & ULTRA_ENABLED) != 0)
-    options |= ULTRA;
-  if (p->bus_type == AIC_TWIN)
-    options |= TWIN_CHANNEL;
-  if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
-    options |= SCB_PAGING;
-
-  cur_patch = patches;
-  outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
-
-  for (i = 0; i < sizeof(seqprog) / 4;  i++)
-  {
-    cur_patch = aic7xxx_next_patch(cur_patch, options, i);
-    if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
-    {
-      /* Skip this instruction for this configuration. */
-      continue;
-    }
-    aic7xxx_download_instr(p, options, i);
-    downloaded++;
-  }
-
-  outb(FASTMODE, p->base + SEQCTL);
-  outb(0, p->base + SEQADDR0);
-  outb(0, p->base + SEQADDR1);
-
-  if (aic7xxx_verbose)
-  {
-     printk(" %d instructions downloaded\n", downloaded);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_delay
- *
- * Description:
- *   Delay for specified amount of time.  We use udelay because the timer
- *   interrupt is not guaranteed to be enabled.  This will cause an
- *   infinite loop since jiffies (clock ticks) is not updated.
- *-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
-{
-  int i;
-
-  /*                        
-   * Call udelay() for 1 millisecond inside a loop for  
-   * the requested amount of seconds.
-   */
-  for (i=0; i < seconds*1000; i++)
-  {
-    udelay(1000);  /* Delay for 1 millisecond. */
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   rcs_version
- *
- * Description:
- *   Return a string containing just the RCS version number from either
- *   an Id or Revision RCS clause.
- *-F*************************************************************************/
-const char *
-rcs_version(const char *version_info)
-{
-  static char buf[10];
-  char *bp, *ep;
-
-  bp = NULL;
-  strcpy(buf, "????");
-  if (!strncmp(version_info, "$Id: ", 5))
-  {
-    if ((bp = strchr(version_info, ' ')) != NULL)
-    {
-      bp++;
-      if ((bp = strchr(bp, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-  else
-  {
-    if (!strncmp(version_info, "$Revision: ", 11))
-    {
-      if ((bp = strchr(version_info, ' ')) != NULL)
-      {
-       bp++;
-      }
-    }
-  }
-
-  if (bp != NULL)
-  {
-    if ((ep = strchr(bp, ' ')) != NULL)
-    {
-      register int len = ep - bp;
-
-      strncpy(buf, bp, len);
-      buf[len] = '\0';
-    }
-  }
-
-  return buf;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_info
- *
- * Description:
- *   Return a string describing the driver.
- *-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
-{
-  static char buffer[128];
+  static char buffer[128];
 
   strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
   strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
   strcat(buffer, "/");
   strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
-#if 0
   strcat(buffer, "/");
   strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
-#endif
 
   return buffer;
 }
@@ -1370,12 +1161,9 @@ aic7xxx_info(struct Scsi_Host *notused)
  *   aic7xxx_length
  *
  * Description:
- *   How much data should be transferred for this SCSI command?  Assume
- *   all segments are to be transferred except for the last sg_last
- *   segments.  This will allow us to compute underflow easily.  To
- *   calculate the total length of the command, use sg_last = 0.  To
- *   calculate the length of all but the last 2 SG segments, use
- *   sg_last = 2.
+ *   How much data should be transferred for this SCSI command? Stop
+ *   at segment sg_last if it's a scatter-gather command so we can
+ *   compute underflow easily.
  *-F*************************************************************************/
 static unsigned
 aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
@@ -1389,7 +1177,7 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
 
   if (cmd->use_sg)
   {
-    for (i = length = 0; i < segments; i++)
+    for (i = length = 0; (i < cmd->use_sg) && (i < segments); i++)
     {
       length += sg[i].length;
     }
@@ -1411,9 +1199,9 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
  *-F*************************************************************************/
 static void
 aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
-    unsigned char *period, unsigned char *offset, int target, char channel)
+    short period, unsigned char offset, int target, char channel)
 {
-  int i = num_aic7xxx_syncrates;
+  int i;
   unsigned long ultra_enb_addr;
   unsigned char ultra_enb, sxfrctl0;
 
@@ -1421,11 +1209,11 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
    * If the offset is 0, then the device is requesting asynchronous
    * transfers.
    */
-  if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
+  if (offset != 0)
   {
     for (i = 0; i < num_aic7xxx_syncrates; i++)
     {
-      if (*period <= aic7xxx_syncrates[i].period)
+      if ((aic7xxx_syncrates[i].period - period) >= 0)
       {
         /*
          * Watch out for Ultra speeds when ultra is not enabled and
@@ -1441,57 +1229,99 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
            */
           continue;
         }
-        *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
-        *period = aic7xxx_syncrates[i].period;
+        *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
 
-        if (aic7xxx_verbose)
+        /*
+         * Ensure Ultra mode is set properly for this target.
+         */
+        ultra_enb_addr = ULTRA_ENB;
+        if ((channel == 'B') || (target > 7))
         {
-          printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, target, channel,
-                 aic7xxx_syncrates[i].english, *offset);
+          ultra_enb_addr++;
         }
-        break;
+        ultra_enb = inb(p->base + ultra_enb_addr);
+        sxfrctl0 = inb(p->base + SXFRCTL0);
+        if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+        {
+          ultra_enb |= 0x01 << (target & 0x07);
+          sxfrctl0 |= ULTRAEN;
+        }
+        else
+        {
+          ultra_enb &= ~(0x01 << (target & 0x07));
+          sxfrctl0 &= ~ULTRAEN;
+        }
+        outb(ultra_enb, p->base + ultra_enb_addr);
+        outb(sxfrctl0, p->base + SXFRCTL0);
+
+        printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+               "offset %d.\n", p->host_no, target, channel,
+               aic7xxx_syncrates[i].english, offset);
+        return;
       }
     }
   }
 
-  if (i >= num_aic7xxx_syncrates)
-  {
-    /*
-     * Use asynchronous transfers.
-     */
-    *scsirate = 0;
-    *period = 0;
-    *offset = 0;
-    if (aic7xxx_verbose)
-    {
-      printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
-             p->host_no, target, channel);
-    }
-  }
+  /*
+   * Default to asynchronous transfer
+   */
+  *scsirate = 0;
+  printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
+         p->host_no, target, channel);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_putscb
+ *
+ * Description:
+ *   Transfer a SCB to the controller.
+ *-F*************************************************************************/
+static inline void
+aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int base = p->base;
+
+  outb(SCBAUTO, SCBCNT + base);
 
   /*
-   * Ensure Ultra mode is set properly for this target.
+   * By turning on the SCB auto increment, any reference
+   * to the SCB I/O space postincrements the SCB address
+   * we're looking at. So turn this on and dump the relevant
+   * portion of the SCB to the card.
+   *
+   * We can do 16bit transfers on all but 284x.
    */
-  ultra_enb_addr = ULTRA_ENB;
-  if ((channel == 'B') || (target > 7))
+  if (p->type == AIC_284x)
   {
-    ultra_enb_addr++;
-  }
-  ultra_enb = inb(p->base + ultra_enb_addr);
-  sxfrctl0 = inb(p->base + SXFRCTL0);
-  if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
-  {
-    ultra_enb |= 0x01 << (target & 0x07);
-    sxfrctl0 |= FAST20;
+    outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
   }
   else
   {
-    ultra_enb &= ~(0x01 << (target & 0x07));
-    sxfrctl0 &= ~FAST20;
+    outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
   }
-  outb(ultra_enb, p->base + ultra_enb_addr);
-  outb(sxfrctl0, p->base + SXFRCTL0);
+
+  outb(0, SCBCNT + base);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_getscb
+ *
+ * Description:
+ *   Get a SCB from the controller.
+ *-F*************************************************************************/
+static inline void
+aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int base = p->base;
+
+  /*
+   * This is almost identical to aic7xxx_putscb().
+   */
+  outb(SCBAUTO, SCBCNT + base);
+  insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+  outb(0, SCBCNT + base);
 }
 
 /*+F*************************************************************************
@@ -1543,47 +1373,6 @@ scbq_remove_head(scb_queue_type *queue)
     queue->tail = NULL;
 }
 
-/*+F*************************************************************************
- * Function:
- *   scbq_remove
- *
- * Description:
- *   Removes an SCB from the list.
- *
- *-F*************************************************************************/
-static inline void
-scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
-{
-  if (queue->head == scb)
-  {
-    /* At beginning of queue, remove from head. */
-    scbq_remove_head(queue);
-  }
-  else
-  {
-    struct aic7xxx_scb *curscb = queue->head;
-
-    /*
-     * Search until the next scb is the one we're looking for, or
-     * we run out of queue.
-     */
-    while ((curscb != NULL) && (curscb->q_next != scb))
-    {
-      curscb = curscb->q_next;
-    }
-    if (curscb != NULL)
-    {
-      /* Found it. */
-      curscb->q_next = scb->q_next;
-      if (scb->q_next == NULL)
-      {
-        /* Update the tail when removing the tail. */
-        queue->tail = curscb;
-      }
-    }
-  }
-}
-
 /*+F*************************************************************************
  * Function:
  *   scbq_insert_tail
@@ -1615,87 +1404,23 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
  *   to be reset and all devices on that channel must be aborted.
  *-F*************************************************************************/
 static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
-    int lun, unsigned char tag)
+aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
 {
-  int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
-  char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
-  int slun = scb->hscb->target_channel_lun & 0x07;
-  int match;
+  int targ = (scb->target_channel_lun >> 4) & 0x0F;
+  char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
-         scb->cmd->device->host->host_no, target, channel, targ, chan);
+  printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
+         target, channel, targ, chan);
 #endif
-  match = ((chan == channel) || (channel == ALL_CHANNELS));
-  if (match != 0)
-    match = ((targ == target) || (target == ALL_TARGETS));
-  if (match != 0)
-    match = ((lun == slun) || (lun == ALL_LUNS));
-  if (match != 0)
-    match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
-
-  return (match);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_add_curscb_to_free_list
- *
- * Description:
- *   Adds the current scb (in SCBPTR) to the list of free SCBs.
- *-F*************************************************************************/
-static void
-aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
-{
-  /*
-   * Invalidate the tag so that aic7xxx_find_scb doesn't think
-   * it's active
-   */
-  outb(SCB_LIST_NULL, p->base + SCB_TAG);
-
-  outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
-  outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_rem_scb_from_disc_list
- *
- * Description:
- *   Removes the current SCB from the disconnected list and adds it
- *   to the free list.
- *-F*************************************************************************/
-static unsigned char
-aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
-{
-  unsigned char next;
-  unsigned char prev;
-
-  outb(scbptr, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
-  prev = inb(p->base + SCB_PREV);
-
-  outb(0, p->base + SCB_CONTROL);
-
-  aic7xxx_add_curscb_to_free_list(p);
-
-  if (prev != SCB_LIST_NULL)
+  if (target == ALL_TARGETS)
   {
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    return (chan == channel);
   }
   else
   {
-    outb(next, p->base + DISCONNECTED_SCBH);
-  }
-
-  if (next != SCB_LIST_NULL)
-  {
-    outb(next, p->base + SCBPTR);
-    outb(prev, p->base + SCB_PREV);
+    return ((chan == channel) && (targ == target));
   }
-  return next;
 }
 
 /*+F*************************************************************************
@@ -1703,209 +1428,120 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
  *   aic7xxx_busy_target
  *
  * Description:
- *   Set the specified target busy.
+ *   Set the specified target active.
  *-F*************************************************************************/
 static void
-aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, unsigned char scbid)
-{
-  unsigned char active_scb;
-  unsigned char info_scb;
-  unsigned int  scb_offset;
-
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
-
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  outb(scbid, p->base + scb_offset);
-  outb(active_scb, p->base + SCBPTR);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_index_busy_target
- *
- * Description:
- *   Returns the index of the busy target, and optionally sets the
- *   target inactive.
- *-F*************************************************************************/
-static unsigned char
-aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
-    char channel, int unbusy)
+aic7xxx_busy_target(unsigned char target, char channel, int base)
 {
-  unsigned char active_scb;
-  unsigned char info_scb;
-  unsigned char busy_scbid;
-  unsigned int  scb_offset;
-
-  info_scb = target / 4;
-  if (channel == 'B')
-    info_scb = info_scb + 2;
+  unsigned char active;
+  unsigned long active_port = ACTIVE_A + base;
 
-  active_scb = inb(p->base + SCBPTR);
-  outb(info_scb, p->base + SCBPTR);
-  scb_offset = SCB_BUSYTARGETS + (target & 0x03);
-  busy_scbid = inb(p->base + scb_offset);
-  if (unbusy)
+  if ((target > 0x07) || (channel == 'B'))
   {
-    outb(SCB_LIST_NULL, p->base + scb_offset);
+    /*
+     * targets on the Second channel or above id 7 store info in byte two
+     * of ACTIVE
+     */
+    active_port++;
   }
-  outb(active_scb, p->base + SCBPTR);
-  return (busy_scbid);
+  active = inb(active_port);
+  active |= (0x01 << (target & 0x07));
+  outb(active, active_port);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_find_scb
+ *   aic7xxx_unbusy_target
  *
  * Description:
- *   Look through the SCB array of the card and attempt to find the
- *   hardware SCB that corresponds to the passed in SCB.  Return
- *   SCB_LIST_NULL if unsuccessful.  This routine assumes that the
- *   card is already paused.
+ *   Set the specified target inactive.
  *-F*************************************************************************/
-static unsigned char
-aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+static void
+aic7xxx_unbusy_target(unsigned char target, char channel, int base)
 {
-  unsigned char saved_scbptr;
-  unsigned char curindex;
+  unsigned char active;
+  unsigned long active_port = ACTIVE_A + base;
 
-  saved_scbptr = inb(p->base + SCBPTR);
-  curindex = 0;
-  for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
+  if ((target > 0x07) || (channel == 'B'))
   {
-    outb(curindex, p->base + SCBPTR);
-    if (inb(p->base + SCB_TAG) == scb->hscb->tag)
-    {
-      break;
-    }
-  }
-  outb(saved_scbptr, p->base + SCBPTR);
-  if (curindex >= p->scb_data->maxhscbs)
-  {
-    curindex = SCB_LIST_NULL;
+    /*
+     * targets on the Second channel or above id 7 store info in byte two
+     * of ACTIVE
+     */
+    active_port++;
   }
-
-  return (curindex);
+  active = inb(active_port);
+  active &= ~(0x01 << (target & 0x07));
+  outb(active, active_port);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_allocate_sglist
+ *   aic7xxx_allocate_scb
  *
  * Description:
- *   Allocate a hardware SG array.
+ *   Get a free SCB either from one already assigned to a hardware
+ *   slot, or one that will require an SCB to be paged out before
+ *   use.  If there are none, attempt to allocate a new one.
  *-F*************************************************************************/
-static struct hw_scatterlist *
-aic7xxx_allocate_sglist(void)
+static struct aic7xxx_scb *
+aic7xxx_allocate_scb(struct aic7xxx_host *p)
 {
-  int alloc_size;
-  struct hw_scatterlist *sg = NULL;
+  struct aic7xxx_scb *scbp = NULL;
+  int maxscbs;
 
-  if (aic7xxx_next_sg_array == NULL)
+  scbp = p->scb_link->free_scbs.head;
+  if (scbp != NULL)
   {
-    alloc_size = sizeof (struct hw_scatterlist) * MAX_SG;
-    aic7xxx_sg_arrays_free = PAGE_SIZE / alloc_size;
-    alloc_size = alloc_size * aic7xxx_sg_arrays_free;
-    if (alloc_size == 0)
-    {
-      panic("aic7xxx: SG list doesn't fit in a page.\n");
-    }
-#ifdef DMA_KMALLOC
-    aic7xxx_next_sg_array = (struct hw_scatterlist *)
-        kmalloc(alloc_size, GFP_ATOMIC | GFP_DMA);
-#else
-    aic7xxx_next_sg_array = (struct hw_scatterlist *)
-        kmalloc(alloc_size, GFP_ATOMIC);
-#endif
+    scbq_remove_head(&p->scb_link->free_scbs);
   }
-  if (aic7xxx_next_sg_array != NULL)
+  else
   {
-    sg = aic7xxx_next_sg_array;
-    aic7xxx_sg_arrays_free = aic7xxx_sg_arrays_free - 1;
-    if (aic7xxx_sg_arrays_free == 0)
+    /*
+     * This should always be NULL if paging is not enabled.
+     */
+    scbp = p->page_scbs.head;
+    if (scbp != NULL)
     {
-      aic7xxx_next_sg_array = NULL;
+      scbq_remove_head(&p->page_scbs);
     }
     else
     {
       /*
-       * Point to the next available SG array in the pool.
+       * Set limit the SCB allocation to the maximum number of
+       * hardware SCBs if paging is not enabled; otherwise use
+       * the maximum (255).
        */
-      aic7xxx_next_sg_array = &(aic7xxx_next_sg_array[MAX_SG]);
-    }
-  }
-  return (sg);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_allocate_scb
- *
- * Description:
- *   Get an SCB from the free list or by allocating a new one.
- *-F*************************************************************************/
-static struct aic7xxx_scb *
-aic7xxx_allocate_scb(struct aic7xxx_host *p)
-{
-  struct aic7xxx_scb   *scbp = NULL;
-  struct aic7xxx_hwscb *hscbp = NULL;
-#ifdef AGRESSIVE
-  long processor_flags;
-
-  save_flags(processor_flags);
-  cli();
-#endif
-
-  scbp = p->scb_data->free_scbs.head;
-  if (scbp != NULL)
-  {
-    scbq_remove_head(&p->scb_data->free_scbs);
-  }
-  else
-  {
-    if (p->scb_data->numscbs < p->scb_data->maxscbs)
-    {
-      int scb_index = p->scb_data->numscbs;
-      int scb_size = sizeof(struct aic7xxx_scb);
-
-      scbp = kmalloc(scb_size, GFP_ATOMIC);
-      if (scbp != NULL)
+      if (p->flags & PAGE_ENABLED)
+        maxscbs = p->maxscbs;
+      else
+        maxscbs = p->maxhscbs;
+      if (p->scb_link->numscbs < maxscbs)
       {
-        memset(scbp, 0, sizeof(struct aic7xxx_scb));
-        hscbp = &p->scb_data->hscbs[scb_index];
-        scbp->hscb = hscbp;
-        scbp->sg_list = aic7xxx_allocate_sglist();
-        if (scbp->sg_list == NULL)
-        {
-          kfree(scbp);
-        }
-        else
+        int scb_index = p->scb_link->numscbs;
+        int scb_size = sizeof(struct aic7xxx_scb);
+
+        p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
+        scbp = (p->scb_array[scb_index]);
+        if (scbp != NULL)
         {
-          memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
-          hscbp->tag = scb_index;
-          p->scb_data->numscbs++;
-          /*
-           * Place in the scb array; never is removed.
-           */
-          p->scb_data->scb_array[scb_index] = scbp;
+          memset(scbp, 0, sizeof(*scbp));
+          scbp->tag = scb_index;
+          if (scb_index < p->maxhscbs)
+            scbp->position = scb_index;
+          else
+           scbp->position = SCB_LIST_NULL;
+          p->scb_link->numscbs++;
         }
       }
     }
   }
-#ifdef AIC7XXX_DEBUG
   if (scbp != NULL)
   {
-    p->activescbs++;
-  }
-#endif
-
-#ifdef AGRESSIVE
-  restore_flags(processor_flags);
+#ifdef AIC7XXX_DEBUG
+    p->scb_link->activescbs++;
 #endif
+  }
   return (scbp);
 }
 
@@ -1945,7 +1581,6 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    p->device_status[TARGET_INDEX(cmd)].active_cmds--;
     cmd->scsi_done(cmd);
   }
   p->completeq.tail = NULL;
@@ -1956,29 +1591,53 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
  *   aic7xxx_free_scb
  *
  * Description:
- *   Free the scb and insert into the free scb list.
+ *   Free the scb and update the page, waiting, free scb lists.
  *-F*************************************************************************/
 static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  struct aic7xxx_hwscb *hscb;
-  long flags;
-
-  hscb = scb->hscb;
-  save_flags(flags);
-  cli();
+  struct aic7xxx_scb *wscb;
 
-  scb->flags = SCB_FREE;
+  scb->state = SCB_FREE;
   scb->cmd = NULL;
-  hscb->control = 0;
-  hscb->target_status = 0;
+  scb->control = 0;
+  scb->state = 0;
 
-  scbq_insert_head(&p->scb_data->free_scbs, scb);
+  if (scb->position == SCB_LIST_NULL)
+  {
+    scbq_insert_head(&p->page_scbs, scb);
+  }
+  else
+  {
+    /*
+     * If there are any SCBS on the waiting queue, assign the slot of this
+     * "freed" SCB to the first one.  We'll run the waiting queues after
+     * all command completes for a particular interrupt are completed or
+     * when we start another command.
+     */
+    wscb = p->waiting_scbs.head;
+    if (wscb != NULL)
+    {
+      scbq_remove_head(&p->waiting_scbs);
+      wscb->position = scb->position;
+      scbq_insert_tail(&p->assigned_scbs, wscb);
+      wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ;
+
+      /* 
+       * The "freed" SCB will need to be assigned a slot before being
+       * used, so put it in the page_scbs queue.
+       */
+      scb->position = SCB_LIST_NULL;
+      scbq_insert_head(&p->page_scbs, scb);
+    }
+    else
+    {
+      scbq_insert_head(&p->scb_link->free_scbs, scb);
+    }
 #ifdef AIC7XXX_DEBUG
-  p->activescbs--;  /* For debugging purposes. */
+    p->scb_link->activescbs--;  /* For debugging purposes. */
 #endif
-
-  restore_flags(flags);
+  }
 }
 
 /*+F*************************************************************************
@@ -1993,113 +1652,68 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   Scsi_Cmnd *cmd = scb->cmd;
 
-  if (scb->flags & SCB_RECOVERY_SCB)
-  {
-    p->flags &= ~IN_TIMEOUT;
-  }
-  if (cmd->result == DID_OK)
-  {
-    if (scb->flags & SCB_ABORTED)
-    {
-      cmd->result = (DID_RESET << 16);
-    }
-  }
-  if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
-  {
-    unsigned short mask;
-
-    mask = 0x01 << TARGET_INDEX(scb->cmd);
-    if (scb->flags & SCB_MSGOUT_WDTR)
-    {
-      p->wdtr_pending &= ~mask;
-    }
-    if (scb->flags & SCB_MSGOUT_SDTR)
-    {
-      p->sdtr_pending &= ~mask;
-    }
-  }
   aic7xxx_free_scb(p, scb);
   aic7xxx_queue_cmd_complete(p, cmd);
 
-#ifdef AIC7XXX_PROC_STATS
-  {
-    int actual;
-
-    /*
-     * XXX: we should actually know how much actually transferred
-     * XXX: for each command, but apparently that's too difficult.
-     */
-    actual = aic7xxx_length(cmd, 0);
-    if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
-        && (aic7xxx_error(cmd) == 0))
-    {
-      struct aic7xxx_xferstats *sp;
-      long *ptr;
-      int x;
-
-      sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
-      sp->xfers++;
-
-      if (cmd->request.cmd == WRITE)
-      {
-        sp->w_total++;
-        sp->w_total512 += (actual >> 9);
-        ptr = sp->w_bins;
-      }
-      else
-      {
-        sp->r_total++;
-        sp->r_total512 += (actual >> 9);
-        ptr = sp->r_bins;
-      }
-      for (x = 9; x <= 17; x++)
-      {
-        if (actual < (1 << x))
-        {
-          ptr[x - 9]++;
-          break;
-        }
-      }
-      if (x > 17)
-      {
-        ptr[x - 9]++;
-      }
-    }
-  }
-#endif /* AIC7XXX_PROC_STATS */
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_run_done_queue
+ *   aic7xxx_done_aborted_scbs
  *
  * Description:
- *   Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
- *   aborted list, and adds each scb to the free list.  If complete
- *   is TRUE, we also process the commands complete list.
+ *   Calls the scsi_done() for the Scsi_Cmnd of each scb in the
+ *   aborted list, and adds each scb to the free list.
  *-F*************************************************************************/
 static void
-aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
+aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
 {
+  Scsi_Cmnd *cmd;
   struct aic7xxx_scb *scb;
   int i;
 
-  for (i = 0; i < p->scb_data->numscbs; i++)
+  for (i = 0; i < p->scb_link->numscbs; i++)
   {
-    scb = p->scb_data->scb_array[i];
-    if (scb->flags & SCB_QUEUED_FOR_DONE)
+    scb = (p->scb_array[i]);
+    if (scb->state & SCB_QUEUED_FOR_DONE)
     {
 #ifdef AIC7XXX_DEBUG_ABORT
-      printk("(scsi%d:%d:%d) Aborting scb %d\n",
-             p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+      printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
+      scb->position, TCL_OF_SCB(scb));
 #endif
-      aic7xxx_done(p, scb);
+      /*
+       * Process the command after marking the scb as free
+       * and adding it to the free list.
+       */
+      cmd = scb->cmd;
+      p->device_status[TARGET_INDEX(cmd)].flags = 0;
+      aic7xxx_free_scb(p, scb);
+      cmd->scsi_done(cmd);  /* call the done function */
     }
   }
-  if (complete)
-  {
-    aic7xxx_done_cmds_complete(p);
-  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_add_waiting_scb
+ *
+ * Description:
+ *   Add this SCB to the head of the "waiting for selection" list.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
+{
+  unsigned char next;
+  unsigned char curscb;
+
+  curscb = inb(SCBPTR + base);
+  next = inb(WAITING_SCBH + base);
+
+  outb(scb->position, SCBPTR + base);
+  outb(next, SCB_NEXT + base);
+  outb(scb->position, WAITING_SCBH + base);
+
+  outb(curscb, SCBPTR + base);
 }
 
 /*+F*************************************************************************
@@ -2112,23 +1726,26 @@ aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
  *-F*************************************************************************/
 static unsigned char
 aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
-    unsigned char scbpos, unsigned char prev)
+    unsigned char prev)
 {
   unsigned char curscb, next;
+  int target = (scb->target_channel_lun >> 4) & 0x0F;
+  char channel = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+  int base = p->base;
 
   /*
    * Select the SCB we want to abort and pull the next pointer out of it.
    */
-  curscb = inb(p->base + SCBPTR);
-  outb(scbpos, p->base + SCBPTR);
-  next = inb(p->base + SCB_NEXT);
+  curscb = inb(SCBPTR + base);
+  outb(scb->position, SCBPTR + base);
+  next = inb(SCB_NEXT + base);
 
   /*
    * Clear the necessary fields
    */
-  outb(0, p->base + SCB_CONTROL);
-
-  aic7xxx_add_curscb_to_free_list(p);
+  outb(0, SCB_CONTROL + base);
+  outb(SCB_LIST_NULL, SCB_NEXT + base);
+  aic7xxx_unbusy_target(target, channel, base);
 
   /*
    * Update the waiting list
@@ -2138,97 +1755,27 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
     /*
      * First in the list
      */
-    outb(next, p->base + WAITING_SCBH);
+    outb(next, WAITING_SCBH + base);
   }
   else
   {
     /*
      * Select the scb that pointed to us and update its next pointer.
      */
-    outb(prev, p->base + SCBPTR);
-    outb(next, p->base + SCB_NEXT);
+    outb(prev, SCBPTR + base);
+    outb(next, SCB_NEXT + base);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
    * system that the command has been aborted.
    */
-  outb(curscb, p->base + SCBPTR);
-  scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-  scb->flags &= ~SCB_ACTIVE;
+  outb(curscb, SCBPTR + base);
+  scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
   scb->cmd->result = (DID_RESET << 16);
 
   return (next);
 }
 
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_search_qinfifo
- *
- * Description:
- *   Search the queue-in FIFO for matching SCBs and conditionally
- *   requeue.  Returns the number of matching SCBs.
- *-F*************************************************************************/
-static int
-aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
-    int lun, unsigned char tag, int flags, int requeue)
-{
-  unsigned char saved_queue[AIC7XXX_MAXSCB];
-  int      queued = inb(p->base + QINCNT) & p->qcntmask;
-  int      i;
-  int      found;
-  struct aic7xxx_scb *scbp;
-  scb_queue_type removed_scbs;
-
-  found = 0;
-  scbq_init (&removed_scbs);
-  for (i = 0; i < (queued - found); i++)
-  {
-    saved_queue[i] = inb(p->base + QINFIFO);
-    scbp = p->scb_data->scb_array[saved_queue[i]];
-    if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
-    {
-       /*
-        * We found an scb that needs to be removed.
-        */
-       if (requeue)
-       {
-         scbq_insert_head(&removed_scbs, scbp);
-       }
-       else
-       {
-         scbp->flags = flags;
-         scbp->flags &= ~SCB_ACTIVE;
-         /*
-          * XXX - Don't know what error to use here.
-          */
-         aic7xxx_error(scbp->cmd) = DID_RESET;
-       }
-       i--;
-       found++;
-    }
-  }
-  /* Now put the saved scbs back. */
-  for (queued = 0; queued < i; queued++)
-    outb(saved_queue[queued], p->base + QINFIFO);
-
-  if (requeue)
-  {
-    scbp = removed_scbs.head;
-    while (scbp != NULL)
-    {
-      scbq_remove_head(&removed_scbs);
-      /*
-       * XXX - Shouldn't we be adding this to the free list?
-       */
-      scbq_insert_head(&p->waiting_scbs, scbp);
-      scbp->flags |= SCB_WAITINGQ;
-      scbp = removed_scbs.head;
-    }
-  }
-
-  return (found);
-}
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset_device
@@ -2238,250 +1785,118 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
  *   all active and queued scbs for that target/channel.
  *-F*************************************************************************/
 static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
-                     int lun, unsigned char tag)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
 {
-  struct aic7xxx_scb *scbp;
+  int base = p->base;
+  struct aic7xxx_scb *scb;
   unsigned char active_scb;
   int i = 0;
-  int found;
+  int found = 0;
 
   /*
    * Restore this when we're done
    */
-  active_scb = inb(p->base + SCBPTR);
+  active_scb = inb(SCBPTR + base);
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
-         p->host_no, target, CHAN_TO_INT(channel), active_scb);
+  printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
+         target, channel, active_scb);
 #endif
-
   /*
-   * Deal with the busy target and linked next issues.
+   * Search the QINFIFO.
    */
   {
-    int min_target, max_target;
-    unsigned char busy_scbid;
+    int saved_queue[AIC7XXX_MAXSCB];
+    int queued = inb(QINCNT + base) & p->qcntmask;
 
-    /* Make all targets 'relative' to bus A. */
-    if (target == ALL_TARGETS)
+    for (i = 0; i < (queued - found); i++)
     {
-      switch (channel)
+      saved_queue[i] = inb(QINFIFO + base);
+      outb(saved_queue[i], SCBPTR + base);
+      scb = (p->scb_array[inb(SCB_TAG + base)]);
+      if (aic7xxx_match_scb(scb, target, channel))
       {
-        case 'A':
-         min_target = 0;
-         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-         break;
-        case 'B':
-         min_target = 8;
-         max_target = 15;
-         break;
-        case ALL_CHANNELS:
-        default:
-         min_target = 0;
-         max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
-         break;
+        /*
+         * We found an scb that needs to be aborted.
+         */
+#ifdef AIC7XXX_DEBUG_ABORT
+        printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n",
+               saved_queue[i], TCL_OF_SCB(scb));
+#endif
+        scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+        scb->cmd->result = (DID_RESET << 16);
+        outb(0, SCB_CONTROL + base);
+        i--;
+        found++;
       }
     }
-    else
-    { 
-      min_target = target + channel == 'B' ? 8 : 0;
-      max_target = min_target;
-    }
-
-    for (i = min_target; i <= max_target; i++)
+    /*
+     * Now put the saved scbs back.
+     */
+    for (queued = 0; queued < i; queued++)
     {
-      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
-      if (busy_scbid < p->scb_data->numscbs)
-      {
-       struct aic7xxx_scb *busy_scb;
-       struct aic7xxx_scb *next_scb;
-       unsigned char next_scbid;
-
-       busy_scb = p->scb_data->scb_array[busy_scbid];
-  
-       next_scbid = busy_scb->hscb->data_count >> 24;
-
-       if (next_scbid == SCB_LIST_NULL)
-        {
-         busy_scbid = aic7xxx_find_scb(p, busy_scb);
-
-         if (busy_scbid != SCB_LIST_NULL)
-          {
-           outb(busy_scbid, p->base + SCBPTR);
-           next_scbid = inb(p->base + SCB_LINKED_NEXT);
-         }
-       }
-
-       if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
-        {
-         aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
-       }
-
-       if (next_scbid != SCB_LIST_NULL)
-        {
-         next_scb = p->scb_data->scb_array[next_scbid];
-         if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
-          {
-           continue;
-          }
-         /* Requeue for later processing */
-         scbq_insert_head(&p->waiting_scbs, next_scb);
-         next_scb->flags |= SCB_WAITINGQ;
-       }
-      }
+      outb(saved_queue[queued], QINFIFO + base);
     }
   }
 
-  found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
-      SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
-
   /*
    * Search waiting for selection list.
    */
   {
-    unsigned char next, prev, scb_index;
+    unsigned char next, prev;
 
-    next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
+    next = inb(WAITING_SCBH + base);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
 
     while (next != SCB_LIST_NULL)
     {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
-      if (scb_index >= p->scb_data->numscbs)
-      {
-        panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
-              scb_index, p->scb_data->numscbs);
-      }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      outb(next, SCBPTR + base);
+      scb = (p->scb_array[inb(SCB_TAG + base)]);
+      /*
+       * Select the SCB.
+       */
+      if (aic7xxx_match_scb(scb, target, channel))
       {
-        unsigned char linked_next;
-
-        next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-        linked_next = inb(p->base + SCB_LINKED_NEXT);
-        if (linked_next != SCB_LIST_NULL)
-        {
-          struct aic7xxx_scb *next_scb;
-          /*
-           * Requeue the waiting SCB via the waiting list.
-           */
-          next_scb = p->scb_data->scb_array[linked_next];
-          if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
-          {
-            scbq_insert_head(&p->waiting_scbs, next_scb);
-            next_scb->flags |= SCB_WAITINGQ;
-          }
-        }
+        next = aic7xxx_abort_waiting_scb(p, scb, prev);
         found++;
       }
       else
       {
         prev = next;
-        next = inb(p->base + SCB_NEXT);
-      }
-    }
-  }
-
-  /*
-   * Go through disconnected list and remove any entries we have queued
-   * for completion, zeroing their control byte too.
-   */
-  {
-    unsigned char next, prev, scb_index;
-
-    next = inb(p->base + DISCONNECTED_SCBH);
-    prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
-    {
-      outb(next, p->base + SCBPTR);
-      scb_index = inb(p->base + SCB_TAG);
-      if (scb_index > p->scb_data->numscbs)
-      {
-        panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
-              "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
-      }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
-      {
-        next = aic7xxx_rem_scb_from_disc_list(p, next);
-      }
-      else
-      {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
-      }
-    }
-  }
-
-  /*
-   * Go through the hardware SCB array looking for commands that
-   * were active but not on any list.
-   */
-  for (i = 0; i < p->scb_data->maxhscbs; i++)
-  {
-    unsigned char scbid;
-
-    outb(i, p->base + SCBPTR);
-    scbid = inb(p->base + SCB_TAG);
-    if (scbid < p->scb_data->numscbs)
-    {
-      scbp = p->scb_data->scb_array[scbid];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
-      {
-        aic7xxx_add_curscb_to_free_list(p);
+        next = inb(SCB_NEXT + base);
       }
     }
   }
 
   /*
    * Go through the entire SCB array now and look for commands for
-   * for this target that are stillactive.  These are other (most likely
+   * for this target that are active.  These are other (most likely
    * tagged) commands that were disconnected when the reset occurred.
    */
-  for (i = 0; i < p->scb_data->numscbs; i++)
+  for (i = 0; i < p->scb_link->numscbs; i++)
   {
-    scbp = p->scb_data->scb_array[i];
-    if (((scbp->flags & SCB_ACTIVE) != 0) &&
-        aic7xxx_match_scb(scbp, target, channel, lun, tag))
+    scb = (p->scb_array[i]);
+    if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
     {
-      scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
-      scbp->flags &= ~SCB_ACTIVE;
-      aic7xxx_error(scbp->cmd) = DID_RESET;
-
-      found++;
-
-      if ((scbp->flags & SCB_WAITINGQ) != 0)
+      /*
+       * Ensure the target is "free"
+       */
+      aic7xxx_unbusy_target(target, channel, base);
+      if (! (scb->state & SCB_PAGED_OUT))
       {
-        scbq_remove(&p->waiting_scbs, scbp);
-        scbp->flags &= ~SCB_WAITINGQ;
+        outb(scb->position, SCBPTR + base);
+        outb(0, SCB_CONTROL + base);
       }
+      scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+      scb->cmd->result = (DID_RESET << 16);
+      found++;
     }
   }
 
-  outb(active_scb, p->base + SCBPTR);
+  outb(active_scb, SCBPTR + base);
   return (found);
 }
 
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_clear_intstat
- *
- * Description:
- *   Clears the interrupt status.
- *-F*************************************************************************/
-static void
-aic7xxx_clear_intstat(struct aic7xxx_host *p)
-{
-  /* Clear any interrupt conditions this may have caused. */
-  outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
-  outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
-       CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
-  outb(CLRSCSIINT, p->base + CLRINT);
-}
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset_current_bus
@@ -2490,28 +1905,11 @@ aic7xxx_clear_intstat(struct aic7xxx_host *p)
  *   Reset the current SCSI bus.
  *-F*************************************************************************/
 static void
-aic7xxx_reset_current_bus(struct aic7xxx_host *p)
+aic7xxx_reset_current_bus(int base)
 {
-  unsigned char scsiseq;
-
-  /* Disable reset interrupts. */
-  outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
-
-  /* Turn on the bus reset. */
-  scsiseq = inb(p->base + SCSISEQ);
-  outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
-
-  udelay(1000);
-
-  /* Turn off the bus reset. */
-  outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
-
-  aic7xxx_clear_intstat(p);
-
-  /* Re-enable reset interrupts. */
-  outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
-
+  outb(SCSIRSTO, SCSISEQ + base);
   udelay(1000);
+  outb(0, SCSISEQ + base);
 }
 
 /*+F*************************************************************************
@@ -2524,24 +1922,25 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
 static int
 aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
 {
-  unsigned long offset, offset_max;
-  int found;
+  int base = p->base;
   unsigned char sblkctl;
   char cur_channel;
+  unsigned long offset, offset_max;
+  int found;
 
-  pause_sequencer(p);
   /*
-   * Clean up all the state information for the pending transactions
-   * on this bus.
+   * Clean up all the state information for the
+   * pending transactions on this bus.
    */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+  found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
 
   if (channel == 'B')
   {
     p->needsdtr |= (p->needsdtr_copy & 0xFF00);
     p->sdtr_pending &= 0x00FF;
-    offset = TARG_SCRATCH + 8;
-    offset_max = TARG_SCRATCH + 16;
+    outb(0, ACTIVE_B + base);
+    offset = TARG_SCRATCH + base + 8;
+    offset_max = TARG_SCRATCH + base + 16;
   }
   else
   {
@@ -2551,100 +1950,132 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
       p->needwdtr = p->needwdtr_copy;
       p->sdtr_pending = 0x0;
       p->wdtr_pending = 0x0;
-      offset = TARG_SCRATCH;
-      offset_max = TARG_SCRATCH + 16;
+      outb(0, ACTIVE_A + base);
+      outb(0, ACTIVE_B + base);
+      offset = TARG_SCRATCH + base;
+      offset_max = TARG_SCRATCH + base + 16;
     }
     else
     {
-      /* Channel A */
       p->needsdtr |= (p->needsdtr_copy & 0x00FF);
       p->sdtr_pending &= 0xFF00;
-      offset = TARG_SCRATCH;
-      offset_max = TARG_SCRATCH + 8;
+      outb(0, ACTIVE_A + base);
+      offset = TARG_SCRATCH + base;
+      offset_max = TARG_SCRATCH + base + 8;
     }
   }
-
   while (offset < offset_max)
   {
     /*
-     * Revert to async/narrow transfers until we renegotiate.
+     * Revert to async/narrow transfers
+     * until we renegotiate.
      */
     u_char targ_scratch;
-
-    targ_scratch = inb(p->base + offset);
+    targ_scratch = inb(offset);
     targ_scratch &= SXFR;
-    outb(targ_scratch, p->base + offset);
+    outb(targ_scratch, offset);
     offset++;
   }
 
   /*
    * Reset the bus and unpause/restart the controller
    */
-  sblkctl = inb(p->base + SBLKCTL);
+
+  /*
+   * Case 1: Command for another bus is active
+   */
+  sblkctl = inb(SBLKCTL + base);
   cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
   if (cur_channel != channel)
   {
-    /*
-     * Case 1: Command for another bus is active
-     */
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Stealthily resetting channel %c\n",
-           p->host_no, channel);
+    printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
+           channel);
 #endif
     /*
-     * Stealthily reset the other bus without upsetting the current bus.
+     * Stealthily reset the other bus without upsetting the current bus
      */
-    outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+    outb(sblkctl ^ SELBUSB, SBLKCTL + base);
     if (initiate_reset)
     {
-      aic7xxx_reset_current_bus(p);
-      /*
-       * Cause the mid-level SCSI code to delay any further 
-       * queueing by the bus settle time for us.
-       */
-      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
+      aic7xxx_reset_current_bus(base);
     }
-    outb(0, p->base + SCSISEQ);
-    aic7xxx_clear_intstat(p);
-    outb(sblkctl, p->base + SBLKCTL);
-    unpause_sequencer(p, /* unpause_always */ FALSE);
+    outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
+    outb(CLRSCSIINT, CLRINT + base);
+    outb(sblkctl, SBLKCTL + base);
+
+    UNPAUSE_SEQUENCER(p);
   }
+  /*
+   * Case 2: A command from this bus is active or we're idle
+   */
   else
   {
-    /*
-     * Case 2: A command from this bus is active or we're idle.
-     */
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Resetting current channel %c\n",
-           p->host_no, channel);
+    printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
+           channel);
 #endif
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     if (initiate_reset)
     {
-      aic7xxx_reset_current_bus(p);
-      /*
-       * Cause the mid-level SCSI code to delay any further 
-       * queueing by the bus settle time for us.
-       */
-#if 0
-      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-#endif
+      aic7xxx_reset_current_bus(base);
     }
-    outb(0, p->base + SCSISEQ);
-    aic7xxx_clear_intstat(p);
-    restart_sequencer(p);
+    outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
+    outb(CLRSCSIINT, CLRINT + base);
+    RESTART_SEQUENCER(p);
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
+    printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
 #endif
   }
 
+  /*
+   * Cause the mid-level SCSI code to delay any further 
+   * queueing by the bus settle time for us.
+   */
+  p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
+
   /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-  return (found);
+  aic7xxx_done_aborted_scbs(p);
+  return found;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_page_scb
+ *
+ * Description:
+ *   Swap in_scbp for out_scbp down in the cards SCB array.
+ *   We assume that the SCB for out_scbp is already selected in SCBPTR.
+ *
+ *-F*************************************************************************/
+static inline void
+aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp,
+    struct aic7xxx_scb *in_scbp)
+{
+  int index;
+
+  /* Page-out */
+#if 0
+printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
+       out_scbp->cmd->target, in_scbp->cmd->target);
+#endif
+  aic7xxx_getscb(p, out_scbp);
+  out_scbp->state |= SCB_PAGED_OUT;
+  if (!(out_scbp->control & TAG_ENB))
+  {
+    /* Stick in non-tagged array */
+    index = (out_scbp->target_channel_lun >> 4) | 
+            (out_scbp->target_channel_lun & SELBUSB);
+    p->pagedout_ntscbs[index] = out_scbp;
+  }
+
+  /* Page-in */
+  in_scbp->position = out_scbp->position;
+  out_scbp->position = SCB_LIST_NULL;
+  aic7xxx_putscb(p, in_scbp);
+  in_scbp->state &= ~SCB_PAGED_OUT;
 }
 
 /*+F*************************************************************************
@@ -2652,1326 +2083,1159 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
  *   aic7xxx_run_waiting_queues
  *
  * Description:
- *   Scan the awaiting_scbs queue downloading and starting as many
- *   scbs as we can.
+ *   Scan the assigned_scbs and waiting_scbs queues.  For scbs in the
+ *   assigned_scbs queue, we download and start them.  For scbs in the
+ *   waiting_scbs queue, we page in as many as we can being careful
+ *   not to cause a deadlock for a reconnecting target.
+ *
  *-F*************************************************************************/
 static inline void
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
+  u_char cur_scb, intstat;
+  u_long base = p->base;
+  long flags;
 
-  if (p->waiting_scbs.head == NULL)
+  if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
     return;
 
-  pause_sequencer(p);
+  save_flags(flags);
+  cli();
+
+  PAUSE_SEQUENCER(p);
+  cur_scb = inb(SCBPTR + base);
+  intstat = inb(INTSTAT + base);
+
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
-  scb = p->waiting_scbs.head;
+  scb = p->assigned_scbs.head;
   while (scb != NULL)
   {
-    if (p->curqincnt >= p->qfullcount)
+    scbq_remove_head(&(p->assigned_scbs));
+    outb(scb->position, SCBPTR + base);
+    aic7xxx_putscb(p, scb);
+    /* Mark this as an active command. */
+    scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE;
+    outb(scb->position, QINFIFO + base);
+    scb = p->assigned_scbs.head;
+  }
+
+  /* Now deal with SCBs that require paging. */
+  scb = p->waiting_scbs.head;
+  if (scb != NULL)
+  {
+    u_char disc_scb = inb(DISCONNECTED_SCBH + base);
+    u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN);
+    int count = 0;
+    u_char next_scb;
+
+    while (scb != NULL)
     {
-      p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
-      if (p->curqincnt >= p->qfullcount)
-      {
+      /* Attempt to page this SCB in */
+      if (disc_scb == SCB_LIST_NULL)
         break;
-      }
-    }
 
-    /*
-     * We have some space.
-     */
-    scbq_remove_head(&(p->waiting_scbs));
-    scb->flags &= ~SCB_WAITINGQ;
+      /*
+       * Advance disc_scb to the next one in the list.
+       */
+      outb(disc_scb, SCBPTR + base);
+      next_scb = inb(SCB_NEXT + base); 
+
+      /*
+       * We have to be careful about when we allow an SCB to be paged out. 
+       * There must always be at least one slot availible for a reconnecting
+       * target in case it references an SCB that has been paged out.  Our
+       * heuristic is that either the disconnected list has at least two
+       * entries in it or there is one entry and the sequencer is activily
+       * working on an SCB which implies that it will either complete or
+       * disconnect before another reconnection can occur.
+       */
+      if ((next_scb != SCB_LIST_NULL) || active)
+      {
+        u_char out_scbi;
+        struct aic7xxx_scb *out_scbp;
 
-    outb(scb->hscb->tag, p->base + QINFIFO);
+        scbq_remove_head(&(p->waiting_scbs));
 
-    if ((p->flags & PAGE_ENABLED) != 0)
+        /*
+         * Find the in-core SCB for the one we're paging out.
+         */
+        out_scbi = inb(SCB_TAG + base); 
+        out_scbp = (p->scb_array[out_scbi]);
+
+        /* Do the page out and mark the paged in SCB as active. */
+        aic7xxx_page_scb(p, out_scbp, scb);
+
+        /* Mark this as an active command. */
+        scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE;
+
+        /* Queue the command */
+        outb(scb->position, QINFIFO + base);
+        count++;
+
+        /* Advance to the next disconnected SCB */
+        disc_scb = next_scb;
+        scb = p->waiting_scbs.head;
+      }
+      else
+        scb = NULL;
+    }
+
+    if (count)
     {
-      /*
-       * We only care about this statistic when paging
-       * since it's impossible to overflow the qinfifo
-       * in the non-paging case.
+      /* 
+       * Update the head of the disconnected list.
        */
-      p->curqincnt++;
+      outb(disc_scb, DISCONNECTED_SCBH + base);
+      if (disc_scb != SCB_LIST_NULL)
+      {
+        outb(disc_scb, SCBPTR + base);
+        outb(SCB_LIST_NULL, SCB_PREV + base);
+      }
     }
-    scb = p->waiting_scbs.head;
   }
+  /* Restore old position */
+  outb(cur_scb, SCBPTR + base);
 
-  unpause_sequencer(p, FALSE);
-}
+  /*
+   * Guard against unpausing the sequencer if there is an interrupt
+   * waiting to happen.
+   */
+  if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
+  {
+    UNPAUSE_SEQUENCER(p);
+  }
 
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_construct_sdtr
- *
- * Description:
- *   Constucts a synchronous data transfer message in the message
- *   buffer on the sequencer.
- *-F*************************************************************************/
-static void
-aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char period, unsigned char offset)
-{
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_SDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(period,           p->base + MSG_OUT + 3 + start_byte);
-  outb(offset,           p->base + MSG_OUT + 4 + start_byte);
-  outb(start_byte + 5,   p->base + MSG_LEN);
+  restore_flags(flags);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_construct_wdtr
+ *   aic7xxx_isr
  *
  * Description:
- *   Constucts a wide data transfer message in the message buffer
- *   on the sequencer.
- *-F*************************************************************************/
-static void
-aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
-    unsigned char bus_width)
-{
-  outb(MSG_EXTENDED,     p->base + MSG_OUT + start_byte);
-  outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
-  outb(MSG_EXT_WDTR,     p->base + MSG_OUT + 2 + start_byte);
-  outb(bus_width,        p->base + MSG_OUT + 3 + start_byte);
-  outb(start_byte + 4,   p->base + MSG_LEN);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_calc_residual
+ *   SCSI controller interrupt handler.
  *
- * Description:
- *   Calculate the residual data not yet transferred.
+ *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ *         be disabled all through this function unless we say otherwise.
  *-F*************************************************************************/
 static void
-aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
-  struct aic7xxx_hwscb *hscb;
+  int base, intstat, actual, scb_index, run_aborted_queue = FALSE;
+  struct aic7xxx_host *p;
+  struct aic7xxx_scb *scb = NULL;
+  short         transfer;
+  unsigned char ha_flags, scsi_id, bus_width;
+  unsigned char offset, rate, scratch, scratch_offset;
+  unsigned char max_offset, rej_byte;
+  unsigned short target_mask;
+  char channel;
+  unsigned int addr; /* must be 32 bits */
   Scsi_Cmnd *cmd;
-  int actual;
 
-  cmd = scb->cmd;
-  hscb = scb->hscb;
+  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
 
   /*
-   *  Don't destroy valid residual information with
-   *  residual coming from a check sense operation.
+   * Search for the host with a pending interrupt.  If we can't find
+   * one, then we've encountered a spurious interrupt.
    */
-  if (((scb->hscb->control & DISCONNECTED) == 0) &&
-      (scb->flags & SCB_SENSE) == 0)
+  while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
   {
-    /*
-     *  We had an underflow. At this time, there's only
-     *  one other driver that bothers to check for this,
-     *  and cmd->underflow seems to be set rather half-
-     *  heartedly in the higher-level SCSI code.
-     */
-    actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
-
-    actual -= (hscb->residual_data_count[2] << 16) |
-              (hscb->residual_data_count[1] <<  8) |
-              hscb->residual_data_count[0];
-
-    if (actual < cmd->underflow)
+    if (p->next == NULL)
+    {
+      p = NULL;
+    }
+    else
     {
-      printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
-             "Wanted at least %u, got %u, residual SG count %d.\n",
-             p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
-             hscb->residual_SG_segment_count);
-      aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-      aic7xxx_status(cmd) = hscb->target_status;
+      p = (struct aic7xxx_host *) p->next->hostdata;
     }
   }
 
+  if (p == NULL)
+    return;
+
   /*
-   * Clean out the residual information in the SCB for the
-   * next consumer.
+   * Keep track of interrupts for /proc/scsi
    */
-  hscb->residual_data_count[2] = 0;
-  hscb->residual_data_count[1] = 0;
-  hscb->residual_data_count[0] = 0;
-  hscb->residual_SG_segment_count = 0;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_device_reset
- *
- * Description:
- *   Interrupt handler for sequencer interrupts (SEQINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
-{
-  unsigned short targ_mask;
-  unsigned char  targ_scratch;
-  int scratch_offset = target;
-  int found;
+  p->isr_count++;
 
-  if (channel == 'B')
+  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
   {
-    scratch_offset += 8;
+    /*
+     * We must only have one card at this IRQ and it must have been
+     * added to the board data before the spurious interrupt occurred.
+     * It is sufficient that we check isr_count and not the spurious
+     * interrupt count.
+     */
+    printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
+    return;
   }
-  targ_mask = (0x01 << scratch_offset);
+
+  base = p->base;
   /*
-   * Go back to async/narrow transfers and renegotiate.
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
    */
-  p->needsdtr |= p->needsdtr_copy & targ_mask;
-  p->needwdtr |= p->needwdtr_copy & targ_mask;
-  p->sdtr_pending &= ~targ_mask;
-  p->wdtr_pending &= ~targ_mask;
-  targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-  targ_scratch &= SXFR;
-  outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-  found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-  printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
-         "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
-  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-}
+  intstat = inb(INTSTAT + base);
 
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_seqint
- *
- * Description:
- *   Interrupt handler for sequencer interrupts (SEQINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
-{
-  struct aic7xxx_scb *scb;
-  unsigned short target_mask;
-  unsigned char target, scratch_offset;
-  char channel;
+  /*
+   * Indicate that we're in the interrupt handler.
+   */
+  p->flags |= IN_ISR;
 
-  if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
-  {
-    target = (inb(p->base + SELID) >> 4) & 0x0F;
-  }
-  else
-  {
-    target = (inb(p->base + SCSIID) >> 4) & 0x0F;
-  }
-  scratch_offset = target;
-  channel = 'A';
-  if (inb(p->base + SBLKCTL) & SELBUSB)
+  if (intstat & BRKADRINT)
   {
-    channel = 'B';
-    scratch_offset += 8;
+    int i;
+    unsigned char errno = inb(ERROR + base);
+
+    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+    for (i = 0; i < NUMBER(hard_error); i++)
+    {
+      if (errno & hard_error[i].errno)
+      {
+        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
+      }
+    }
+    panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
+          inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
   }
-  target_mask = (0x01 << scratch_offset);
 
-  switch (intstat & SEQINT_MASK)
+  if (intstat & SEQINT)
   {
-    case NO_MATCH:
-      {
-        /*
-         * This could be for a normal abort request.  Figure out
-         * which SCB we were trying to find and only give an error
-         * if we didn't ask for this to happen.
-         */
-        unsigned char scb_index;
-        unsigned char busy_scbid;
-        unsigned char arg1;
+    /*
+     * Although the sequencer is paused immediately on
+     * a SEQINT, an interrupt for a SCSIINT condition will
+     * unpaused the sequencer before this point.
+     */
+    PAUSE_SEQUENCER(p);
 
-        busy_scbid = aic7xxx_index_busy_target(p, target, channel,
-            /*unbusy*/ FALSE);
-        arg1 = inb(p->base + ARG_1);
+    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
+    scratch_offset = scsi_id;
+    channel = 'A';
+    if (inb(SBLKCTL + base) & SELBUSB)
+    {
+      channel = 'B';
+      scratch_offset += 8;
+    }
+    target_mask = (0x01 << scratch_offset);
 
-        if (arg1 == SCB_LIST_NULL)
-        {
-          /* untagged request */
-          scb_index = busy_scbid;
-        }
-        else
+    switch (intstat & SEQINT_MASK)
+    {
+      case NO_MATCH:
+       if (p->flags & PAGE_ENABLED)
         {
-          scb_index = arg1;
-        }
+         /* SCB Page-in request */
+         struct aic7xxx_scb *outscb;
+         u_char arg_1 = inb(ARG_1 + base);
+          int use_disconnected = FALSE;
 
-        if (scb_index < p->scb_data->numscbs)
-        {
-          scb = p->scb_data->scb_array[scb_index];
-          if (scb->hscb->control & ABORT_SCB)
+          /*
+           * The sequencer expects this value upon return.  Assume
+           * we will find the paged out SCB and set the value now.
+           * If we don't, and one of the methods used to acquire an
+           * SCB calls aic7xxx_done(), we will end up in our queue
+           * routine and unpause the sequencer without giving it the
+           * correct return value, which causes a hang.
+           */
+         outb(SCB_PAGEDIN, RETURN_1 + base);
+         if (arg_1 == SCB_LIST_NULL)
           {
-            /*
-             * We expected this.  Let the busfree handler take care
-             * of this when we the abort is finially sent.  Set
-             * IDENTIFY_SEEN so that the busfree handler knows that
-             * there is an SCB to cleanup.
-             */
-            outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
-            printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
-                   p->host_no, TC_OF_SCB(scb));
+           /* Non-tagged command */
+           int index = scsi_id;
+            if (channel == 'B')
+            {
+              index |= SELBUSB;
+            }
+           scb = p->pagedout_ntscbs[index];
+         }
+         else
+           scb = (p->scb_array[arg_1]);
+
+          if (!(scb->state & SCB_PAGED_OUT))
+          {
+           printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting "
+                 "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
+                 p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
+           aic7xxx_unbusy_target(scsi_id, channel, base);
+           outb(CLRSELTIMEO, CLRSINT1 + base);
+            outb(0, RETURN_1 + base);
             break;
           }
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
-               "target - Issuing BUS DEVICE RESET.\n",
-               p->host_no, target, CHAN_TO_INT(channel));
-
-        printk(KERN_WARNING "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
-               inb(p->base + SAVED_TCL), arg1,
-               (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-        aic7xxx_handle_device_reset(p, target, channel);
-      }
-      break;
-
-    case NO_MATCH_BUSY:
-      {
-        /*
-         * XXX - Leave this as a panic for the time being since it
-         * indicates a bug in the timeout code for this to happen.
-         */
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + CUR_SCBID);
-        scb = p->scb_data->scb_array[scb_index];
-
-        panic("scsi%d:  Target %d, channel %c, Target busy link failure, "
-              "but busy SCB exists!\n",
-              p->host_no, target, channel);
-      }
-      break;
-
-    case SEND_REJECT:
-      {
-        unsigned char rej_byte;
-
-        rej_byte = inb(p->base + REJBYTE);
-        printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
-               "received from target, SEQ_FLAGS=0x%x\n",
-               p->host_no, target, CHAN_TO_INT(channel), rej_byte,
-               inb(p->base + SEQ_FLAGS));
-      }
-      break;
-
-    case NO_IDENT:
-      {
-        /*
-         * The reconnecting target either did not send an identify
-         * message, or did, but we didn't find and SCB to match and
-         * before it could respond to our ATN/abort, it hit a dataphase.
-         * The only safe thing to do is to blow it away with a bus
-         * reset.
-         */
-        int found;
-
-        printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
-               "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
-               p->host_no, target, CHAN_TO_INT(channel),
-               inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
-
-        found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
 
-        printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
-              "%d SCBs aborted\n", p->host_no, channel, found);
-      }
-      break;
-
-    case BAD_PHASE:
-      if (inb(p->base + LASTPHASE) == P_BUSFREE)
-      {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
-               p->host_no, CHAN_TO_INT(channel), target);
-        restart_sequencer(p);
-      }
-      else
-      {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
-               "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
-      }
-      break;
-
-    case EXTENDED_MSG:
-      {
-       unsigned char message_length;
-       unsigned char message_code;
-        unsigned char scb_index;
-
-       message_length = inb(p->base + MSGIN_EXT_LEN);
-       message_code = inb(p->base + MSGIN_EXT_OPCODE);
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-
-       switch (message_code)
-       {
-          case MSG_EXT_SDTR:
+         /*
+          * Now to pick the SCB to page out.  Either take a free SCB, an
+           * assigned SCB, an SCB that just completed, or the first one
+           * on the disconnected SCB list.
+          */
+         if (p->scb_link->free_scbs.head != NULL)
+          {
+           outscb = p->scb_link->free_scbs.head;
+           scbq_remove_head(&p->scb_link->free_scbs);
+           scb->position = outscb->position;
+           outscb->position = SCB_LIST_NULL;
+           scbq_insert_head(&p->page_scbs, outscb);
+           outb(scb->position, SCBPTR + base);
+           aic7xxx_putscb(p, scb);
+           scb->state &= ~SCB_PAGED_OUT;
+         }
+         else if (p->assigned_scbs.head != NULL)
+          {
+            outscb = p->assigned_scbs.head;
+            scbq_remove_head(&p->assigned_scbs);
+            scb->position = outscb->position;
+            outscb->position = SCB_LIST_NULL;
+            scbq_insert_head(&p->waiting_scbs, outscb);
+            outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ;
+            outb(scb->position, SCBPTR + base);
+           aic7xxx_putscb(p, scb);
+            scb->state &= ~SCB_PAGED_OUT;
+          }
+          else if (intstat & CMDCMPLT)
           {
-            unsigned char period;
-            unsigned char offset;
-            unsigned char saved_offset;
-            unsigned char targ_scratch;
-            unsigned char max_offset;
-            unsigned char rate;
-
-            if (message_length != MSG_EXT_SDTR_LEN)
+            int scb_index;
+
+            outb(CLRCMDINT, CLRINT + base);
+            scb_index = inb(QOUTFIFO + base);
+            if (!(inb(QOUTCNT + base) & p->qcntmask))
             {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
+              intstat &= ~CMDCMPLT;
+            }
+            outscb = (p->scb_array[scb_index]);
+            if (!(outscb->state & SCB_ACTIVE))
+            {
+             printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
+                    "during NO_MATCH interrupt\n", scb_index, p->host_no);
+              use_disconnected = TRUE;
             }
-
-            period = inb(p->base + MSGIN_EXT_BYTES);
-            saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
-            targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-            if (targ_scratch & WIDEXFER)
-              max_offset = MAX_OFFSET_16BIT;
             else
-              max_offset = MAX_OFFSET_8BIT;
-            offset = MIN(saved_offset, max_offset);
-
-            aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
-
-            /*
-             * Preserve the WideXfer flag.
-             */
-            targ_scratch = rate | (targ_scratch & WIDEXFER);
-
-            /*
-             * Update both the target scratch area and current SCSIRATE.
-             */
-            outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(targ_scratch, p->base + SCSIRATE);
-
-            /*
-             * See if we initiated Sync Negotiation and didn't have
-             * have to fall down to async transfers.
-             */
-            if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
             {
-              /* We started it. */
-              if (saved_offset == offset)
+              scb->position = outscb->position;
+              outscb->position = SCB_LIST_NULL;
+              outb(scb->position, SCBPTR + base);
+              aic7xxx_putscb(p, scb);
+              scb->state &= ~SCB_PAGED_OUT;
+              outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16);
+              if ((outscb->cmd->flags & WAS_SENSE) && 
+                 !(outscb->cmd->flags & ASKED_FOR_SENSE))
               {
-               /*
-                * Don't send an SDTR back to the target.
-                */
-               outb(0, p->base + RETURN_1);
+                /*
+                 * Got sense information.
+                 */
+               outscb->cmd->flags &= ASKED_FOR_SENSE;
               }
-              else
+              p->device_status[TARGET_INDEX(outscb->cmd)].flags
+                |= DEVICE_SUCCESS;
+              aic7xxx_done(p, outscb);
+            }
+          }
+          else
+          {
+            use_disconnected = TRUE;
+          }
+          if (use_disconnected)
+          {
+           u_char tag;
+           u_char next;
+           u_char disc_scb = inb(DISCONNECTED_SCBH + base);
+           if (disc_scb != SCB_LIST_NULL)
+            {
+             outb(disc_scb, SCBPTR + base);
+             tag = inb(SCB_TAG + base);
+             outscb = (p->scb_array[tag]);
+             next = inb(SCB_NEXT + base);
+             if (next != SCB_LIST_NULL)
+              {
+               outb(next, SCBPTR + base);
+               outb(SCB_LIST_NULL, SCB_PREV + base);
+               outb(disc_scb, SCBPTR + base);
+             }
+             outb(next, DISCONNECTED_SCBH + base);
+             aic7xxx_page_scb(p, outscb, scb);
+           }
+            else if (inb(QINCNT + base) & p->qcntmask)
+            {
+              /* Pull one of our queued commands as a last resort. */
+              disc_scb = inb(QINFIFO + base);
+              outb(disc_scb, SCBPTR + base);
+              tag = inb(SCB_TAG + base);
+              outscb = (p->scb_array[tag]);
+              if ((outscb->control & 0x23) != TAG_ENB)
               {
-               /* We went too low - force async. */
-               outb(SEND_REJ, p->base + RETURN_1);
+                /*
+                 * This is not a simple tagged command so its position
+                 * in the queue matters.  Take the command at the end of
+                 * the queue instead.
+                 */
+                int i;
+                int saved_queue[AIC7XXX_MAXSCB];
+                int queued = inb(QINCNT + base) & p->qcntmask;
+
+                /* Count the command we removed already */
+                saved_queue[0] = disc_scb;
+                queued++;
+
+                /* Empty the input queue. */
+                for (i = 1; i < queued; i++)
+                {
+                  saved_queue[i] = inb(QINFIFO + base);
+                }
+
+                /* Put everyone back but the last entry. */
+                queued--;
+                for (i = 0; i < queued; i++)
+                {
+                  outb(saved_queue[i], QINFIFO + base);
+                }
+
+                outb(saved_queue[queued], SCBPTR + base);
+                tag = inb(SCB_TAG + base);
+                outscb = (p->scb_array[tag]);
               }
+              scb->position = outscb->position;
+              outscb->position = SCB_LIST_NULL;
+              scbq_insert_head(&p->waiting_scbs, outscb);
+              outscb->state |= SCB_WAITINGQ;
+              aic7xxx_putscb(p, scb);
+              scb->state &= ~SCB_PAGED_OUT;
             }
             else
             {
-              /*
-               * Send our own SDTR in reply.
-               *
-               * We want to see this message as we don't expect a target
-               * to send us a SDTR request first.
-               */
-              printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
-              aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
-              outb(SEND_MSG, p->base + RETURN_1);
+             printk(KERN_WARNING "scsi%d: Page-in request with no candidates "
+                   "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
+                   p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
+              aic7xxx_unbusy_target(scsi_id, channel, base);
+              outb(CLRSELTIMEO, CLRSINT1 + base);
+              outb(0, RETURN_1 + base);
             }
-            /*
-             * Clear the flags.
-             */
-            p->needsdtr &= ~target_mask;
-            break;
           }
+       }
+       else
+        {
+         printk(KERN_WARNING "scsi%d: No active SCB for reconnecting "
+               "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
+               p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
+         aic7xxx_unbusy_target(scsi_id, channel, base);
+         outb(0, SCB_CONTROL + base);
+         outb(CLRSELTIMEO, CLRSINT1 + base);
+          outb(0, RETURN_1 + base);
+        }
+       break;
 
-          case MSG_EXT_WDTR:
-          {
-            unsigned char scratch, bus_width;
-
-            if (message_length != MSG_EXT_WDTR_LEN)
-            {
-              outb(SEND_REJ, p->base + RETURN_1);
-              break;
-            }
-
-            bus_width = inb(p->base + MSGIN_EXT_BYTES);
-            scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+      case BAD_PHASE:
+       panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
+       break;
 
-            if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
-            {
-              /*
-               * Don't send an WDTR back to the target, since we asked first.
-               */
-              outb(0, p->base + RETURN_1);
-              switch (bus_width)
-              {
-               case BUS_8_BIT:
-                 scratch &= 0x7F;
-                 break;
-
-               case BUS_16_BIT:
-                  if (aic7xxx_verbose)
-                  {
-                   printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
-                        "bit transfers.\n", p->host_no, target, channel);
-                  }
-                 scratch |= WIDEXFER;
-                 break;
-
-               case BUS_32_BIT:
-                 outb(SEND_REJ, p->base + RETURN_1);
-                  /* No verbose here!  We want to see this condition. */
-                 printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
-                       "requesting 32 bit transfers, rejecting...\n",
-                        p->host_no, target, channel);
-                 break;
-
-               default:
-                 break;
-              }
-            }
-            else
-            {
-              /*
-               * Send our own WDTR in reply.
-               */
-              switch (bus_width)
-              {
-               case BUS_8_BIT:
-                 scratch &= 0x7F;
-                 break;
-
-               case BUS_32_BIT:
-               case BUS_16_BIT:
-                 if (p->bus_type == AIC_WIDE)
-                 {
-                    printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
-                          "bit transfers.\n", p->host_no, target, channel);
-                    bus_width = BUS_16_BIT;
-                    scratch |= WIDEXFER;
-                 }
-                 else
-                 {
-                    bus_width = BUS_8_BIT;
-                    scratch &= 0x7F;  /* XXX - FreeBSD doesn't do this. */
-                 }
-                 break;
-
-               default:
-                 break;
-              }
-              aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
-              outb(SEND_MSG, p->base + RETURN_1);
-            }
-            p->needwdtr &= ~target_mask;
-            outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
-            outb(scratch, p->base + SCSIRATE);
-            break;
-         }  /* case MSG_EXT_WDTR */
+      case SEND_REJECT:
+        rej_byte = inb(REJBYTE + base);
+        if ((rej_byte & 0xF0) == 0x20)
+        {
+          scb_index = inb(SCB_TAG + base);
+          scb = (p->scb_array[scb_index]);
+          printk(KERN_WARNING "scsi%d: Tagged message received without identify."
+                 "Disabling tagged commands for target %d channel %c.\n",
+                  p->host_no, scsi_id, channel);
+          scb->cmd->device->tagged_supported = 0;
+          scb->cmd->device->tagged_queue = 0;
+        }
+        else
+        {
+          printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received "
+                 "from target %d channel %c.\n",
+                 p->host_no, rej_byte, scsi_id, channel);
+        }
+       break;
 
-          default:
-            /*
-             * Unknown extended message - reject it.
-             */
-            outb(SEND_REJ, p->base + RETURN_1);
-            break;
-       }  /* switch (message_code) */
-      }  /* case EXTENDED_MSG */
-      break;
+      case NO_IDENT:
+       panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY "
+             "message. SAVED_TCL 0x%x.\n",
+              p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
+       break;
 
-    case REJECT_MSG:
-      {
+      case SDTR_MSG:
        /*
-        * What we care about here is if we had an outstanding SDTR
-        * or WDTR message for this target. If we did, this is a
-        * signal that the target is refusing negotiation.
+        * Help the sequencer to translate the negotiated
+        * transfer rate. Transfer is 1/4 the period
+        * in ns as is returned by the sync negotiation
+        * message. So, we must multiply by four.
         */
-       unsigned char targ_scratch;
-        unsigned char scb_index;
-
-        scb_index = inb(p->base + SCB_TAG);
-        scb = p->scb_data->scb_array[scb_index];
-       targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-
-       if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
+       transfer = (inb(ARG_1 + base) << 2);
+       offset = inb(ACCUM + base);
+       scratch = inb(TARG_SCRATCH + base + scratch_offset);
+       /*
+        * The maximum offset for a wide device is 0x08; for a
+        * 8-bit bus device the maximum offset is 0x0F.
+        */
+       if (scratch & WIDEXFER)
        {
-          /*
-           * note 8bit xfers and clear flag
-           */
-          targ_scratch &= 0x7F;
-          p->needwdtr &= ~target_mask;
-          printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
-                "negotiation; using 8 bit transfers.\n",
-                p->host_no, target, channel);
+         max_offset = 0x08;
        }
        else
        {
-          if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
+         max_offset = 0x0F;
+       }
+       aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
+                         scsi_id, channel);
+       /*
+        * Preserve the wide transfer flag.
+        */
+       scratch = rate | (scratch & WIDEXFER);
+       outb(scratch, TARG_SCRATCH + base + scratch_offset);
+       outb(scratch, SCSIRATE + base);
+       if ((scratch & 0x0F) == 0)
+       {
+          /*
+           * One of two things happened.  Either the device requested
+           * asynchronous data transfers, or it requested a synchronous
+           * data transfer rate that was so low that asynchronous
+           * transfers are faster (not to mention the controller won't
+           * support them).  In both cases the synchronous data transfer
+           * rate and the offset are set to 0 indicating asynchronous
+           * transfers.
+           *
+           * If the device requested an asynchronous transfer, then
+           * accept the request.  If the device is being forced to
+           * asynchronous data transfers and this is the first time
+           * we've seen the request, accept the request.  If we've
+           * already seen the request, then attempt to force
+           * asynchronous data transfers by rejecting the message.
+           */
+          if ((offset == 0) || (p->sdtr_pending & target_mask))
           {
             /*
-             * note asynch xfers and clear flag
+             * Device requested asynchronous transfers or we're
+             * forcing asynchronous transfers for the first time.
              */
-            targ_scratch &= 0xF0;
-            p->needsdtr &= ~target_mask;
-            printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
-                  "synchronous negotiation; using asynchronous transfers.\n",
-                  p->host_no, target, channel);
+            outb(0, RETURN_1 + base);
+          }
+          else
+          {
+            /*
+            * The first time in forcing asynchronous transfers
+             * failed, so we try sending a reject message.
+            */
+           outb(SEND_REJ, RETURN_1 + base);
           }
-          /*
-           * Otherwise, we ignore it.
-           */
        }
-        outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-        outb(targ_scratch, p->base + SCSIRATE);
-      }
-      break;
+       else
+       {
+         /*
+          * See if we initiated Sync Negotiation
+          */
+         if (p->sdtr_pending & target_mask)
+         {
+           /*
+            * Don't send an SDTR back to the target.
+            */
+           outb(0, RETURN_1 + base);
+         }
+         else
+         {
+           /*
+            * Send our own SDTR in reply.
+            */
+           printk("aic7xxx: Sending SDTR!!\n");
+           outb(SEND_SDTR, RETURN_1 + base);
+         }
+       }
+       /*
+        * Clear the flags.
+        */
+       p->needsdtr &= ~target_mask;
+       p->sdtr_pending &= ~target_mask;
+       break;
 
-    case BAD_STATUS:
+      case WDTR_MSG:
       {
-       unsigned char scb_index;
-       struct aic7xxx_hwscb *hscb;
-       Scsi_Cmnd *cmd;
-
-       /* The sequencer will notify us when a command has an error that
-        * would be of interest to the kernel.  This allows us to leave
-        * the sequencer running in the common case of command completes
-        * without error.  The sequencer will have DMA'd the SCB back
-        * up to us, so we can reference the drivers SCB array.
-        */
-       scb_index = inb(p->base + SCB_TAG);
-       scb = p->scb_data->scb_array[scb_index];
-       hscb = scb->hscb;
+       bus_width = inb(ARG_1 + base);
+       printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c "
+              "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr);
+       scratch = inb(TARG_SCRATCH + base + scratch_offset);
 
-       /*
-        * Set the default return value to 0 indicating not to send
-        * sense.  The sense code will change this if needed and this
-        * reduces code duplication.
-        */
-       outb(0, p->base + RETURN_1);
-       if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+       if (p->wdtr_pending & target_mask)
        {
-          printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
-                "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
-                intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
+         /*
+          * Don't send an WDTR back to the target, since we asked first.
+          */
+         outb(0, RETURN_1 + base);
+         switch (bus_width)
+         {
+           case BUS_8_BIT:
+             scratch &= 0x7F;
+             break;
+
+           case BUS_16_BIT:
+             printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
+                     "transfers.\n", p->host_no, scsi_id, channel);
+             scratch |= 0x80;
+             break;
+
+           case BUS_32_BIT:
+             outb(SEND_REJ, RETURN_1 + base);
+             printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
+                     "transfers, rejecting...\n", p->host_no, scsi_id, channel);
+             break;
+         }
        }
        else
        {
-          cmd = scb->cmd;
-         hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
-          aic7xxx_status(cmd) = hscb->target_status;
-
-          cmd->result |= hscb->target_status;
-
-          switch (status_byte(hscb->target_status))
-          {
-            case GOOD:
-             printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
-                     "GOOD???\n", p->host_no, TC_OF_SCB(scb));
-              break;
-
-            case CHECK_CONDITION:
-              if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
-              {
-               unsigned int addr;    /* must be 32 bits */
-               /*
-                * XXX - How do we save the residual (if there is one).
-                */
-                aic7xxx_calculate_residual(p, scb);
-
-               /*
-                * Send a sense command to the requesting target.
-                * XXX - revisit this and get rid of the memcopys.
-                */
-               memcpy((void *) scb->sense_cmd, (void *) generic_sense,
-                      sizeof(generic_sense));
-
-               scb->sense_cmd[1] = (cmd->lun << 5);
-               scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
-               scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
-               scb->sg_list[0].length = sizeof(cmd->sense_buffer);
-               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
-                /*
-                 * XXX - We should allow disconnection, but can't as it
-                 * might allow overlapped tagged commands.
-                 */
-               /* hscb->control &= DISCENB; */
-                hscb->control = 0;
-               hscb->target_status = 0;
-               hscb->SG_segment_count = 1;
-
-               addr = VIRT_TO_BUS(&scb->sg_list[0]);
-               memcpy(&hscb->SG_list_pointer, &addr,
-                      sizeof(hscb->SG_list_pointer));
-
-               memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
-                      sizeof(hscb->data_pointer));
-               /* Maintain SCB_LINKED_NEXT */
-               hscb->data_count &= 0xFF000000;
-               hscb->data_count |= scb->sg_list[0].length;
-
-               addr = VIRT_TO_BUS(scb->sense_cmd);
-               memcpy(&hscb->SCSI_cmd_pointer, &addr,
-                      sizeof(hscb->SCSI_cmd_pointer));
-               hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
-
-                scb->sg_count = hscb->SG_segment_count;
-               scb->flags |= SCB_SENSE;
-                /*
-                 * Ensure the target is busy since this will be an
-                 * an untagged request.
-                 */
-                aic7xxx_busy_target(p, target, channel, hscb->tag);
-               outb(SEND_SENSE, p->base + RETURN_1);
-              }  /* first time sense, no errors */
-             else
-             {
-               if (aic7xxx_error(cmd) == 0)
-               {
-                 aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-               }
-             }
-              break;
-
-            case QUEUE_FULL:
-#ifdef NOT_YET
-              if (scb->hscb->control & TAG_ENB)
-              {
-               if (cmd->device->queue_depth > 2)
-               {
-                  cmd->device->queue_depth--;  /* Not correct */
-                  printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
-                        "reduced to %d\n", p->host_no,
-                        TC_OF_SCB(scb), cmd->device->queue_depth);
-               }
-               /*
-                * XXX - Requeue this unconditionally?
-                */
-
-               /*
-                * We'd like to be able to give the SCB some more time
-                * (untimeout, then timeout).
-                */
-               break;
-              }
-#endif
-              printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
-                     "queue depth %d, active %d\n", p->host_no,
-                     TC_OF_SCB(scb), cmd->device->queue_depth,
-                     p->device_status[TARGET_INDEX(cmd)].active_cmds);
-
-              /* Else treat this as if it was a BUSY condition. */
-              scb->hscb->target_status = (BUSY << 1) |
-                  (scb->hscb->target_status & 0x01);
-              /* Fall through to the BUSY case. */
-
-            case BUSY:
-              printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
-                     p->host_no, TC_OF_SCB(scb));
-              if (!aic7xxx_error(cmd))
-              {
-               /*
-                * The mid-level SCSI code should be fixed to
-                * retry the command at a later time instead of
-                * trying right away.
-                */
-               aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
-              }
-              udelay(1000);  /*  A small pause (1ms) to help the drive */
-              break;
+         /*
+          * Send our own WDTR in reply.
+          */
+         printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
+         switch (bus_width)
+         {
+           case BUS_8_BIT:
+             scratch &= 0x7F;
+             break;
 
-            default:
-              printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
-                     "status 0x%x.\n", p->host_no,
-                    TC_OF_SCB(scb), scb->hscb->target_status);
-              if (!aic7xxx_error(cmd))
-              {
-               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-              }
-              break;
-          }  /* end switch */
-       }  /* end else of */
+           case BUS_32_BIT:
+             /*
+               * Negotiate 16 bits.
+               */
+             bus_width = BUS_16_BIT;
+             /* Yes, we mean to fall thru here. */
+
+           case BUS_16_BIT:
+             printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
+                     "transfers.\n", p->host_no, scsi_id, channel);
+             scratch |= 0x80;
+             break;
+         }
+         outb(bus_width | SEND_WDTR, RETURN_1 + base);
+       }
+       p->needwdtr &= ~target_mask;
+       p->wdtr_pending &= ~target_mask;
+       outb(scratch, TARG_SCRATCH + base + scratch_offset);
+       outb(scratch, SCSIRATE + base);
+       break;
       }
-      break;
 
-    case AWAITING_MSG:
+      case REJECT_MSG:
       {
-       unsigned char scb_index;
-        unsigned char message_offset;
-
-       scb_index = inb(p->base + SCB_TAG);
-       scb = p->scb_data->scb_array[scb_index];
-
        /*
-        * This SCB had a MK_MESSAGE set in its control byte informing
-        * the sequencer that we wanted to send a special message to
-        * this target.
+        * What we care about here is if we had an
+        * outstanding SDTR or WDTR message for this
+        * target. If we did, this is a signal that
+        * the target is refusing negotiation.
         */
-        message_offset = inb(p->base + MSG_LEN);
-       if (scb->flags & SCB_DEVICE_RESET)
+
+       scratch = inb(TARG_SCRATCH + base + scratch_offset);
+
+       if (p->wdtr_pending & target_mask)
        {
-          outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
-          outb(1, p->base + MSG_LEN);
-          printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
-                p->host_no, TC_OF_SCB(scb));
+         /*
+          * note 8bit xfers and clear flag
+          */
+         scratch &= 0x7F;
+         p->needwdtr &= ~target_mask;
+         p->wdtr_pending &= ~target_mask;
+         printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+                 "negotiation; using 8 bit transfers.\n",
+                 p->host_no, scsi_id, channel);
        }
-        else if (scb->flags & SCB_ABORT)
-        {
-          if ((scb->hscb->control & TAG_ENB) != 0)
-          {
-            outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
-          }
-          else
-          {
-            outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
-          }
-          outb(message_offset + 1, p->base + MSG_LEN);
-          printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
-                 p->host_no, TC_OF_SCB(scb));
-        }
-       else if (scb->flags & SCB_MSGOUT_WDTR)
+       else
        {
-          aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
-        }
-        else if (scb->flags & SCB_MSGOUT_SDTR)
-        {
-          unsigned char target_scratch;
-          unsigned short ultra_enable;
-          int i, sxfr;
-
-          /*
-           * Pull the user defined setting from scratch RAM.
-           */
-          target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
-          sxfr = target_scratch & SXFR;
-          ultra_enable = inb(p->base + ULTRA_ENB) |
-              (inb(p->base + ULTRA_ENB + 1) << 8);
-          if (ultra_enable & target_mask)
-          {
-            sxfr |= 0x100;
-          }
-          for (i = 0; i < num_aic7xxx_syncrates; i++)
-          {
-            if (sxfr == aic7xxx_syncrates[i].rate)
-            break;
-          }
-          aic7xxx_construct_sdtr(p, message_offset,
-                                 aic7xxx_syncrates[i].period,
-                                 target_scratch & WIDEXFER ?
-                                 MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
-        }
-        else 
-        {
-          panic("aic7xxx: AWAITING_MSG for an SCB that does "
-                "not have a waiting message.");
+         if (p->sdtr_pending & target_mask)
+         {
+           /*
+            * note asynch xfers and clear flag
+            */
+           scratch &= 0xF0;
+           p->needsdtr &= ~target_mask;
+           p->sdtr_pending &= ~target_mask;
+           printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
+                   "synchronous negotiation; using asynchronous transfers.\n",
+                   p->host_no, scsi_id, channel);
+         }
+         /*
+          * Otherwise, we ignore it.
+          */
        }
+       outb(scratch, TARG_SCRATCH + base + scratch_offset);
+       outb(scratch, SCSIRATE + base);
+       break;
       }
-      break;
 
-    case DATA_OVERRUN:
-      {
-       unsigned char scb_index = inb(p->base + SCB_TAG);
-        unsigned char lastphase = inb(p->base + LASTPHASE);
-       unsigned int i, overrun;
-
-       scb = (p->scb_data->scb_array[scb_index]);
-       overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
-                 (inb(p->base + STCNT + 2) << 16);
-       overrun = 0x00FFFFFF - overrun;
-       printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
-               "in %s phase, tag %d; forcing a retry.\n",
-               p->host_no, TC_OF_SCB(scb), overrun,
-               lastphase == P_DATAIN ? "Data-In" : "Data-Out",
-               scb->hscb->tag);
-        printk(KERN_WARNING "%s seen Data Phase.  Length = %d, NumSGs = %d.\n",
-               inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
-               aic7xxx_length(scb->cmd, 0), scb->sg_count);
-        for (i = 0; i < scb->sg_count; i++)
-        {
-          printk(KERN_INFO "     sg[%d] - Addr 0x%x : Length %d\n",
-                 i, scb->sg_list[i].address, scb->sg_list[i].length);
-        }
-       /*
-        * XXX - What do we really want to do on an overrun?  The
-        *       mid-level SCSI code should handle this, but for now,
-        *       we'll just indicate that the command should retried.
-        */
-       aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
-      }
-      break;
+      case BAD_STATUS:
+        /* The sequencer will notify us when a command has an error that
+         * would be of interest to the kernel.  This allows us to leave
+         * the sequencerrunning in the common case of command completes
+         * without error.
+         */
 
-/* #if AIC7XXX_NOT_YET */
-    /* XXX Fill these in later */
-    case MSG_BUFFER_BUSY:
-      printk("aic7xxx: Message buffer busy.\n");
-      break;
-    case MSGIN_PHASEMIS:
-      printk("aic7xxx: Message-in phasemis.\n");
-      break;
-/*#endif */
-
-    case ABORT_CMDCMPLT:
-      /* This interrupt serves to pause the sequencer until we can clean
-       * up the QOUTFIFO allowing us to handle any abort SCBs that may
-       * completed yet still have an SCB in the QINFIFO or waiting for
-       * selection queue.  By the time we get here, we should have
-       * already cleaned up the queues, so all we need to do is unpause
-       * the sequencer.
-       */
-      break;
+       scb_index = inb(SCB_TAG + base);
+       scb = (p->scb_array[scb_index]);
+       outb(0, RETURN_1 + base);   /* CHECK_CONDITION may change this */
+       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
+                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+       }
+       else
+       {
+         cmd = scb->cmd;
+          scb->target_status = inb(SCB_TARGET_STATUS + base);
+         aic7xxx_status(cmd) = scb->target_status;
 
-    default:              /* unknown */
-      printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
-             p->host_no, intstat, inb(p->base + SCSISIGI));
-      break;
-  }
+         cmd->result |= scb->target_status;
 
-  /*
-   * Clear the sequencer interrupt and unpause the sequencer.
-   */
-  outb(CLRSEQINT, p->base + CLRINT);
-  unpause_sequencer(p, /* unpause always */ TRUE);
-}
+         switch (status_byte(scb->target_status))
+         {
+           case GOOD:
+              printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
+             break;
 
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_handle_scsiint
- *
- * Description:
- *   Interrupt handler for SCSI interrupts (SCSIINT).
- *-F*************************************************************************/
-static void
-aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
-{
-  unsigned char scb_index;
-  unsigned char status;
-  struct aic7xxx_scb *scb;
+           case CHECK_CONDITION:
+             if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
+             {
+                unsigned char tcl;
+               unsigned int  req_buf; /* must be 32 bits */
 
-  scb_index = inb(p->base + SCB_TAG);
-  status = inb(p->base + SSTAT1);
+                tcl = scb->target_channel_lun;
 
-  if (scb_index < p->scb_data->numscbs)
-  {
-    scb = p->scb_data->scb_array[scb_index];
-    if ((scb->flags & SCB_ACTIVE) == 0)
-    {
-      scb = NULL;
-    }
-  }
-  else
-  {
-    scb = NULL;
-  }
-
-  if ((status & SCSIRSTI) != 0)
-  {
-    char channel;
-
-    channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+               /*
+                 * Send a sense command to the requesting target.
+                 */
+               cmd->flags |= WAS_SENSE;
+               memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+                      sizeof(generic_sense));
+
+               scb->sense_cmd[1] = (cmd->lun << 5);
+               scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+               scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
+               scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+               req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
+               cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+                scb->control = scb->control & DISCENB;
+               scb->target_channel_lun = tcl;
+               addr = VIRT_TO_BUS(scb->sense_cmd);
+               scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+               memcpy(scb->SCSI_cmd_pointer, &addr,
+                      sizeof(scb->SCSI_cmd_pointer));
+               scb->SG_segment_count = 1;
+               memcpy(scb->SG_list_pointer, &req_buf,
+                      sizeof(scb->SG_list_pointer));
+                scb->data_count = scb->sg_list[0].length;
+               memcpy(scb->data_pointer, &(scb->sg_list[0].address),
+                      sizeof(scb->data_pointer));
+
+                aic7xxx_putscb(p, scb);
+                /*
+                 * Ensure that the target is "BUSY" so we don't get overlapping
+                 * commands if we happen to be doing tagged I/O.
+                 */
+               aic7xxx_busy_target(scsi_id, channel, base);
 
-    printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
-           p->host_no, channel);
-    /*
-     * Go through and abort all commands for the channel, but do not
-     * reset the channel again.
-     */
-    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
-    scb = NULL;
-  }
-  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
-  {
-    /*
-     * First look at what phase we were last in.  If it's message-out,
-     * chances are pretty good that the bus free was in response to
-     * one of our abort requests.
-     */
-    unsigned char lastphase = inb(p->base + LASTPHASE);
-    unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
-    char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
-    int printerror = TRUE;
+                aic7xxx_add_waiting_scb(base, scb);
+               outb(SEND_SENSE, RETURN_1 + base);
+             }  /* first time sense, no errors */
+              else
+              {
+                cmd->flags &= ~ASKED_FOR_SENSE;
+               if (aic7xxx_error(cmd) == 0)
+                {
+                 aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+                }
+              }
+             break;
+
+           case BUSY:
+             printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
+                     p->host_no, scb->target_channel_lun);
+             if (!aic7xxx_error(cmd))
+             {
+                /* The error code here used to be DID_BUS_BUSY,
+                 * but after extensive testing, it has been determined
+                 * that a DID_BUS_BUSY return is a waste of time.  If
+                 * the problem is something that will go away, then it
+                 * will, if it isn't, then you don't want the endless
+                 * looping that you get with a DID_BUS_BUSY.  Better
+                 * to be on the safe side and specify an error condition
+                 * that will eventually lead to a reset or abort of some
+                 * sort instead of an endless loop.
+                 */
+               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+             }
+             break;
+
+           case QUEUE_FULL:
+             printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no);
+              scb->state |= SCB_ASSIGNEDQ;
+              scbq_insert_tail(&p->assigned_scbs, scb);
+             break;
+
+           default:
+             printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n",
+                    p->host_no, scb->target_status);
+             if (!aic7xxx_error(cmd))
+             {
+               aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+             }
+             break;
+         }  /* end switch */
+       }  /* end else of */
+       break;
 
-    outb(0, p->base + SCSISEQ);
-    if (lastphase == P_MESGOUT)
-    {
-      unsigned char sindex;
-      unsigned char message;
+      case RESIDUAL:
+       scb_index = inb(SCB_TAG + base);
+       scb = (p->scb_array[scb_index]);
+       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
+                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+       }
+       else
+       {
+         cmd = scb->cmd;
+         /*
+          *  Don't destroy valid residual information with
+          *  residual coming from a check sense operation.
+          */
+         if (!(cmd->flags & WAS_SENSE))
+         {
+           /*
+            *  We had an underflow. At this time, there's only
+            *  one other driver that bothers to check for this,
+            *  and cmd->underflow seems to be set rather half-
+            *  heartedly in the higher-level SCSI code.
+            */
+           actual = aic7xxx_length(cmd, scb->residual_SG_segment_count);
+
+           actual -= (inb(SCB_RESID_DCNT2 + base) << 16) |
+                     (inb(SCB_RESID_DCNT1 + base) <<  8) |
+                     inb(SCB_RESID_DCNT0 + base);
+
+           if (actual < cmd->underflow)
+           {
+             printk(KERN_WARNING "scsi%d: Target %d underflow - "
+                    "Wanted at least %u, got %u, residual SG count %d.\n",
+                    p->host_no, cmd->target, cmd->underflow, actual,
+                     inb(SCB_RESID_SGCNT + base));
+             aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+             aic7xxx_status(cmd) = scb->target_status;
+           }
+         }
+       }
+       break;
 
-      sindex = inb(p->base + SINDEX);
-      message = inb(p->base + sindex - 1);
+      case ABORT_TAG:
+       scb_index = inb(SCB_TAG + base);
+       scb = (p->scb_array[scb_index]);
+       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
+                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+       }
+       else
+       {
+         cmd = scb->cmd;
+         /*
+          * We didn't receive a valid tag back from the target
+          * on a reconnect.
+          */
+         printk("scsi%d: Invalid tag received on target %d, channel %c, "
+                 "lun %d - Sending ABORT_TAG.\n", p->host_no,
+                 scsi_id, channel, cmd->lun & 0x07);
+
+         cmd->result = (DID_RETRY_COMMAND << 16);
+          aic7xxx_done(p, scb);
+       }
+       break;
 
-      if (message == MSG_ABORT)
-      {
-        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
-                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
-        aic7xxx_run_done_queue(p, /* complete */ TRUE);
-        scb = NULL;
-        printerror = 0;
-      }
-      else if (message == MSG_ABORT_TAG)
-      {
-        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
-                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
-        aic7xxx_run_done_queue(p, /* complete */ TRUE);
-        scb = NULL;
-        printerror = 0;
-      }
-      else if (message == MSG_BUS_DEV_RESET)
-      {
-        aic7xxx_handle_device_reset(p, target, channel);
-        scb = NULL;
-        printerror = 0;
-      }
-    }
-    if (printerror != 0)
-    {
-      if (scb != NULL)
-      {
-        unsigned char tag;
+      case AWAITING_MSG:
+       scb_index = inb(SCB_TAG + base);
+       scb = (p->scb_array[scb_index]);
+       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+       {
+         printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+                "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
+                intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+       }
+       else
+       {
+         /*
+          * This SCB had a zero length command, informing the sequencer
+          * that we wanted to send a special message to this target.
+          * We only do this for BUS_DEVICE_RESET messages currently.
+          */
+          if (scb->state & SCB_DEVICE_RESET)
+          {
+#ifdef AIC7XXX_DEBUG_ABORT
+  printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
+          scsi_id);
+#endif
+            outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
+            outb(1, MSG_LEN + base);
+          }
+          else
+          {
+            panic("scsi%d: AWAITING_SCB for an SCB that does "
+                  "not have a waiting message.\n", p->host_no);
+          }
+       }
+       break;
 
-        if ((scb->hscb->control & TAG_ENB) != 0)
+      case IMMEDDONE:
+        scb_index = inb(SCB_TAG + base);
+       scb = (p->scb_array[scb_index]);
+#ifdef AIC7XXX_DEBUG_ABORT
+  printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
+         scsi_id, scb_index, scb->state);
+#endif
+        if (scb->state & SCB_DEVICE_RESET)
         {
-          tag = scb->hscb->tag;
+          int found;
+
+          /*
+           * Go back to async/narrow transfers and renegotiate.
+           */
+          aic7xxx_unbusy_target(scsi_id, channel, base);
+          p->needsdtr |= (p->needsdtr_copy & target_mask);
+          p->needwdtr |= (p->needwdtr_copy & target_mask);
+          p->sdtr_pending &= ~target_mask;
+          p->wdtr_pending &= ~target_mask;
+          scratch = inb(TARG_SCRATCH + base + scratch_offset);
+          scratch &= SXFR;
+          outb(scratch, TARG_SCRATCH + base + scratch_offset);
+          found = aic7xxx_reset_device(p, (int) scsi_id, channel);
+          printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs "
+                 "aborted.\n", p->host_no, found);
+          /* Indicate that we want to call aic7xxx_done_aborted_scbs() */
+          run_aborted_queue = TRUE;
         }
         else
         {
-          tag = SCB_LIST_NULL;
+          panic("scsi%d: Immediate complete for unknown operation.\n",
+                p->host_no);
         }
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
-      }
-      else
-      {
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-      }
-      printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
-             "SEQADDR = 0x%x\n", p->host_no, lastphase,
-             (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-    }
-    outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
-    outb(CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
-    restart_sequencer(p);
-  }
-  else if ((status & SELTO) != 0)
-  {
-    unsigned char scbptr;
-    unsigned char nextscb;
-    Scsi_Cmnd *cmd;
-
-    scbptr = inb(p->base + WAITING_SCBH);
-    outb(scbptr, p->base + SCBPTR);
-    scb_index = inb(p->base + SCB_TAG);
+        break;
 
-    scb = NULL;
-    if (scb_index < p->scb_data->numscbs)
-    {
-      scb = p->scb_data->scb_array[scb_index];
-      if ((scb->flags & SCB_ACTIVE) == 0)
+      case DATA_OVERRUN:
       {
-        scb = NULL;
+        unsigned int overrun;
+
+        scb = (p->scb_array[inb(base + SCB_TAG)]);
+        overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
+                  (inb(base + STCNT2) << 16);
+        overrun =0x00FFFFFF - overrun;
+        printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing "
+               "a retry.\n", p->host_no, overrun);
+        aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
+        break;
       }
-    }
-    if (scb == NULL)
-    {
-      printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
-             p->host_no, scb_index);
-      printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
-             "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
-             inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-             inb(p->base + SSTAT0), inb(p->base + SSTAT1));
-    }
-    else
-    {
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       */
-      cmd = scb->cmd;
-      cmd->result = (DID_TIME_OUT << 16);
-
-      /*
-       * Clear an pending messages for the timed out
-       * target and mark the target as free.
-       */
-      outb(0, p->base + MSG_LEN);
-      aic7xxx_index_busy_target(p, cmd->target,
-          cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
-      outb(0, p->base + SCB_CONTROL);
-
-      /*
-       * Shift the waiting for selection queue forward
-       */
-      nextscb = inb(p->base + SCB_NEXT);
-      outb(nextscb, p->base + WAITING_SCBH);
-
-      /*
-       * Put this SCB back on the free list.
-       */
-      aic7xxx_add_curscb_to_free_list(p);
-    }
-    /*
-     * Stop the selection.
-     */
-    outb(0, p->base + SCSISEQ);
-    outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
-    restart_sequencer(p);
-  }
-  else if (scb == NULL)
-  {
-    printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
-           "during scsiint 0x%x scb(%d)\n"
-           "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
-           p->host_no, status, scb_index, inb(p->base + SIMODE0),
-           inb(p->base + SIMODE1), inb(p->base + SSTAT0),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-    /*
-     * Turn off the interrupt and set status to zero, so that it
-     * falls through the rest of the SCSIINT code.
-     */
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
-    unpause_sequencer(p, /* unpause always */ TRUE);
-    scb = NULL;
-  }
-  else if (status & SCSIPERR)
-  {
-    /*
-     * Determine the bus phase and queue an appropriate message.
-     */
-    char  *phase;
-    Scsi_Cmnd *cmd;
-    unsigned char mesg_out = MSG_NOOP;
-    unsigned char lastphase = inb(p->base + LASTPHASE);
 
-    cmd = scb->cmd;
-    switch (lastphase)
-    {
-      case P_DATAOUT:
-        phase = "Data-Out";
-        break;
-      case P_DATAIN:
-        phase = "Data-In";
-        mesg_out = MSG_INITIATOR_DET_ERR;
+#if AIC7XXX_NOT_YET
+      /* XXX Fill these in later */
+      case MESG_BUFFER_BUSY:
         break;
-      case P_COMMAND:
-        phase = "Command";
-        break;
-      case P_MESGOUT:
-        phase = "Message-Out";
-        break;
-      case P_STATUS:
-        phase = "Status";
-        mesg_out = MSG_INITIATOR_DET_ERR;
-        break;
-      case P_MESGIN:
-        phase = "Message-In";
-        mesg_out = MSG_PARITY_ERROR;
-        break;
-      default:
-        phase = "unknown";
+      case MSGIN_PHASEMIS:
         break;
+#endif
+
+      default:               /* unknown */
+       printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+              p->host_no, intstat, inb(SCSISIGI + base));
+       break;
     }
 
     /*
-     * A parity error has occurred during a data
-     * transfer phase. Flag it and continue.
+     * Clear the sequencer interrupt and unpause the sequencer.
      */
-    printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
-           p->host_no, TC_OF_SCB(scb), phase);
+    outb(CLRSEQINT, CLRINT + base);
+    UNPAUSE_SEQUENCER(p);
+  }
 
-    /*
-     * We've set the hardware to assert ATN if we get a parity
-     * error on "in" phases, so all we need to do is stuff the
-     * message buffer with the appropriate message.  "In" phases
-     * have set mesg_out to something other than MSG_NOP.
-     */
-    if (mesg_out != MSG_NOOP)
+  if (intstat & SCSIINT)
+  {
+    int status = inb(SSTAT1 + base);
+    scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
+    channel = 'A';
+    if (inb(SBLKCTL + base) & SELBUSB)
     {
-      outb(mesg_out, p->base + MSG_OUT);
-      outb(1, p->base + MSG_LEN);
-      scb = NULL;
+      channel = 'B';
     }
-    else
+
+    scb_index = inb(SCB_TAG + base);
+    scb = (p->scb_array[scb_index]);
+    if (status & SCSIRSTI)
     {
+      PAUSE_SEQUENCER(p);
+      printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
+             p->host_no, channel);
       /*
-       * Should we allow the target to make this decision for us?
+       * Go through and abort all commands for the channel, but do not
+       * reset the channel again.
        */
-      cmd->result = DID_RETRY_COMMAND << 16;
-    }
-    outb(CLRSCSIPERR, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-  }
-  else
-  {
-    /*
-     * We don't know what's going on. Turn off the
-     * interrupt source and try to continue.
-     */
-    printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
-    outb(status, p->base + CLRSINT1);
-    outb(CLRSCSIINT, p->base + CLRINT);
-    unpause_sequencer(p, /* unpause always */ TRUE);
-    scb = NULL;
-  }
-  if (scb != NULL)
-  {
-    aic7xxx_done(p, scb);
-    aic7xxx_done_cmds_complete(p);
-  }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_isr
- *
- * Description:
- *   SCSI controller interrupt handler.
- *
- *   NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- *         be disabled all through this function unless we say otherwise.
- *-F*************************************************************************/
-static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
-{
-  struct aic7xxx_host *p;
-  unsigned char intstat;
-  unsigned long flags;
-
-  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
-
-  /*
-   * Search for the host with a pending interrupt.  If we can't find
-   * one, then we've encountered a spurious interrupt.
-   */
-  while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
-  {
-    if (p->next == NULL)
+      aic7xxx_reset_channel(p, channel, FALSE);
+      run_aborted_queue = TRUE;
+    }
+    else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
     {
-      p = NULL;
+      printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no);
+      /*
+       * Turn off the interrupt and set status to zero, so that it
+       * falls through the rest of the SCSIINT code.
+       */
+      outb(status, CLRSINT1 + base);
+      UNPAUSE_SEQUENCER(p);
+      outb(CLRSCSIINT, CLRINT + base);
+      scb = NULL;
     }
-    else
+    else if (status & SCSIPERR)
     {
-      p = (struct aic7xxx_host *) p->next->hostdata;
+      char  *phase;
+      unsigned char mesg_out = MSG_NOP;
+      unsigned char lastphase = inb(LASTPHASE + base);
+
+      cmd = scb->cmd;
+      switch (lastphase)
+      {
+        case P_DATAOUT:
+          phase = "Data-Out";
+          break;
+        case P_DATAIN:
+          phase = "Data-In";
+          mesg_out = MSG_INITIATOR_DET_ERROR;
+          break;
+        case P_COMMAND:
+          phase = "Command";
+          break;
+        case P_MESGOUT:
+          phase = "Message-Out";
+          break;
+        case P_STATUS:
+          phase = "Status";
+          mesg_out = MSG_INITIATOR_DET_ERROR;
+          break;
+        case P_MESGIN:
+          phase = "Message-In";
+          mesg_out = MSG_MSG_PARITY_ERROR;
+          break;
+        default:
+          phase = "unknown";
+          break;
+      }
+
+      /*
+       * A parity error has occurred during a data
+       * transfer phase. Flag it and continue.
+       */
+      printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, "
+             "channel %d, lun %d.\n", p->host_no, phase,
+             cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
+
+      /*
+       * We've set the hardware to assert ATN if we get a parity
+       * error on "in" phases, so all we need to do is stuff the
+       * message buffer with the appropriate message. In phases
+       * have set mesg_out to something other than MSG_NOP.
+       */
+      if (mesg_out != MSG_NOP)
+      {
+        outb(mesg_out, MSG0 + base);
+        outb(1, MSG_LEN + base);
+        cmd->result = DID_PARITY << 16;
+      }
+      else
+      {
+        /*
+         * Should we allow the target to make this decision for us?
+         */
+        cmd->result = DID_RETRY_COMMAND << 16;
+      }
+      aic7xxx_done(p, scb);
     }
-  }
+    else if (status & SELTO)
+    {
+      unsigned char waiting;
 
-  if (p == NULL)
-    return;
+      cmd = scb->cmd;
 
-  /*
-   * Handle all the interrupt sources - especially for SCSI
-   * interrupts, we won't get a second chance at them.
-   */
-  intstat = inb(p->base + INTSTAT);
+      cmd->result = (DID_TIME_OUT << 16);
+      /*
+       * Clear an pending messages for the timed out
+       * target and mark the target as free.
+       */
+      ha_flags = inb(FLAGS + base);
+      outb(0, MSG_LEN + base);
+      aic7xxx_unbusy_target(scsi_id, channel, base);
+      /*
+       * Stop the selection.
+       */
+      outb(0, SCSISEQ + base);
+      outb(0, SCB_CONTROL + base);
+      outb(CLRSELTIMEO, CLRSINT1 + base);
+      outb(CLRSCSIINT, CLRINT + base);
 
-  /*
-   * Keep track of interrupts for /proc/scsi
-   */
-  p->isr_count++;
+      /*
+       * Shift the waiting for selection queue forward
+       */
+      waiting = inb(WAITING_SCBH + base);
+      outb(waiting, SCBPTR + base);
+      waiting = inb(SCB_NEXT + base);
+      outb(waiting, WAITING_SCBH + base);
 
-  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
-  {
-    /*
-     * We must only have one card at this IRQ and it must have been
-     * added to the board data before the spurious interrupt occurred.
-     * It is sufficient that we check isr_count and not the spurious
-     * interrupt count.
-     */
-    printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
-    if (intstat)
+      RESTART_SEQUENCER(p);
+      aic7xxx_done(p, scb);
+    }
+    else if (!(status & BUSFREE))
     {
-      /* Try clearing all interrupts. */
-      outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
+      /*
+       * We don't know what's going on. Turn off the
+       * interrupt source and try to continue.
+       */
+      printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
+      outb(status, CLRSINT1 + base);
+      UNPAUSE_SEQUENCER(p);
+      outb(CLRSCSIINT, CLRINT + base);
     }
-    return;
-  }
-
-  if (p->flags & IN_ISR)
-  {
-    printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
-           p->host_no);
-    return;
   }
 
-  /*
-   * Indicate that we're in the interrupt handler.
-   */
-  save_flags(flags);
-  cli();
-  p->flags |= IN_ISR;
+  if (run_aborted_queue)
+    aic7xxx_done_aborted_scbs(p);
 
   if (intstat & CMDCMPLT)
   {
-    struct aic7xxx_scb *scb = NULL;
-    Scsi_Cmnd *cmd;
-    unsigned char qoutcnt;
-    unsigned char scb_index;
-    int i, interrupts_cleared = 0;
+    int complete;
 
     /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
-    qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
+    do {
+      complete = inb(QOUTFIFO + base);
 
-#if 1
-  if (qoutcnt >= p->qfullcount - 1)
-    printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
-           "qoutcnt = %d.\n", qoutcnt);
-#endif
-    while (qoutcnt > 0)
-    {
-      for (i = 0; i < qoutcnt; i++)
+      scb = (p->scb_array[complete]);
+      if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
       {
-        scb_index = inb(p->base + QOUTFIFO);
-        scb = p->scb_data->scb_array[scb_index];
-        if (scb == NULL)
-        {
-         printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
-                "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
-                 inb(p->base + QOUTCNT), inb(p->base + QINCNT));
-          continue;
-        }
-        else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
-        {
-         printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
-                "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
-                 p->host_no, scb_index, inb(p->base + QOUTCNT),
-                 inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
-         continue;
-        }
-        cmd = scb->cmd;
-        if (scb->hscb->residual_SG_segment_count != 0)
-        {
-          aic7xxx_calculate_residual(p, scb);
-        }
-        if ((scb->flags & SCB_QUEUED_ABORT) != 0)
-        {
-          /*
-           * Have to clean up any possible entries in the
-           * waiting queue and the QINFIFO.
-           */
-          int target;
-          char channel;
-          int lun;
-          unsigned char tag;
-
-          tag = SCB_LIST_NULL;
-          target = cmd->target;
-          lun = cmd->lun;
-          channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
-          if (scb->hscb->control & TAG_ENB)
-          {
-            tag = scb->hscb->tag;
-          }
-          aic7xxx_reset_device(p, target, channel, lun, tag);
-          /*
-           * Run the done queue, but don't complete the commands; we
-           * do this once at the end of the loop.
-           */
-          aic7xxx_run_done_queue(p, /*complete*/ FALSE);
-        }
-        cmd->result |= (aic7xxx_error(cmd) << 16);
-        p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-        aic7xxx_done(p, scb);
+       printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
+              "       QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
+               "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
+               inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
+               scb->position);
+       outb(CLRCMDINT, CLRINT + base);
+       continue;
+      }
+      cmd = scb->cmd;
+      cmd->result |= (aic7xxx_error(cmd) << 16);
+      if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+      {
+        /*
+         * Got sense information.
+         */
+       cmd->flags &= ASKED_FOR_SENSE;
       }
+      p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
+
       /*
        * Clear interrupt status before checking the output queue again.
        * This eliminates a race condition whereby a command could
@@ -3979,152 +3243,56 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
        * so notification of the command being complete never made it
        * back up to the kernel.
        */
-      outb(CLRCMDINT, p->base + CLRINT);
-      interrupts_cleared++;
-      qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
-    }
-
-    if (interrupts_cleared == 0)
-    {
-      outb(CLRCMDINT, p->base + CLRINT);
-    }
-
-    aic7xxx_done_cmds_complete(p);
-  }
-
-  if (intstat & BRKADRINT)
-  {
-    int i;
-    unsigned char errno = inb(p->base + ERROR);
+      outb(CLRCMDINT, CLRINT + base);
+      aic7xxx_done(p, scb);
 
-    printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
-    for (i = 0; i < NUMBER(hard_error); i++)
-    {
-      if (errno & hard_error[i].errno)
+#ifdef AIC7XXX_PROC_STATS
+      /*
+       * XXX: we should actually know how much actually transferred
+       * XXX: for each command, but apparently that's too difficult.
+       */
+      actual = aic7xxx_length(cmd, 0);
+      if (!(cmd->flags & WAS_SENSE) && (actual > 0))
       {
-        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
-      }
-    }
-    printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
-           inb(p->base + ERROR),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-    aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
-    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-  }
-
-  if (intstat & SEQINT)
-  {
-    aic7xxx_handle_seqint(p, intstat);
-  }
-
-  if (intstat & SCSIINT)
-  {
-    aic7xxx_handle_scsiint(p, intstat);
-  }
-
-  if (p->waiting_scbs.head != NULL)
-  {
-    aic7xxx_run_waiting_queues(p);
-  }
-
-  p->flags &= ~IN_ISR;
-  restore_flags(flags);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_device_queue_depth
- *
- * Description:
- *   Determines the queue depth for a given device.  There are two ways
- *   a queue depth can be obtained for a tagged queueing device.  One
- *   way is the default queue depth which is determined by whether
- *   AIC7XXX_CMDS_PER_LUN is defined.  If it is defined, then it is used
- *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
- *   default queue depth (dependent on the number of hardware SCBs).
- *   The other way we determine queue depth is through the use of the
- *   aic7xxx_tag_info array which is enabled by defining
- *   AIC7XXX_TAGGED_QUEUEING_BY_DEVICE.  This array can be initialized
- *   with queue depths for individual devices.  It also allows tagged
- *   queueing to be [en|dis]abled for a specific adapter.
- *-F*************************************************************************/
-static void
-aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
-{
-  int default_depth = 2;
-
-  device->queue_depth = default_depth;
-#ifdef AIC7XXX_TAGGED_QUEUEING
-  if (device->tagged_supported)
-  {
-    unsigned short target_mask;
-    int tag_enabled = TRUE;
-
-    target_mask = (1 << (device->id | (device->channel << 3)));
+        struct aic7xxx_xferstats *sp;
+        long *ptr;
+        int x;
 
-#ifdef AIC7XXX_CMDS_PER_LUN
-    default_depth = AIC7XXX_CMDS_PER_LUN;
-#else
-    if (p->scb_data->maxhscbs <= 4)
-    {
-      default_depth = 4;  /* Not many SCBs to work with. */
-    }
-    else
-    {
-      default_depth = 8;
-    }
-#endif
-    if (!(p->discenable & target_mask))
-    {
-      printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
-             "enable tagged queueing.\n",
-             p->host_no, device->id, device->channel);
-    }
-    else
-    {
-#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
-      device->queue_depth = default_depth;
-#else
-      if (p->instance > NUMBER(aic7xxx_tag_info))
-      {
-        device->queue_depth = default_depth;
-      }
-      else
-      {
-        unsigned char  tindex;
+        sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+        sp->xfers++;
 
-        tindex = device->id | (device->channel << 3);
-        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == -1)
+        if (cmd->request.cmd == WRITE)
         {
-          tag_enabled = FALSE;
-          device->queue_depth = 2;  /* Tagged queueing is disabled. */
+          sp->w_total++;
+          sp->w_total512 += (actual >> 9);
+          ptr = sp->w_bins;
         }
-        else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
+        else
         {
-          device->queue_depth = default_depth;
+          sp->r_total++;
+          sp->r_total512 += (actual >> 9);
+          ptr = sp->r_bins;
         }
-        else
+        for (x = 9; x <= 17; x++)
         {
-          device->queue_depth =
-            aic7xxx_tag_info[p->instance].tag_commands[tindex];
+          if (actual < (1 << x))
+          {
+            ptr[x - 9]++;
+            break;
+          }
         }
-      }
-#endif
-      if ((device->tagged_queue == 0) && tag_enabled)
-      {
-        if (aic7xxx_verbose)
+        if (x > 17)
         {
-         printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
-                "queue depth %d.\n", p->host_no,
-                device->id, device->channel, device->queue_depth);
+          ptr[x - 9]++;
         }
-        device->tagged_queue = 1;
-        device->current_tag = SCB_LIST_NULL;
       }
-    }
+#endif /* AIC7XXX_PROC_STATS */
+
+    } while (inb(QOUTCNT + base) & p->qcntmask);
   }
-#endif
+  aic7xxx_done_cmds_complete(p);
+  p->flags &= ~IN_ISR;
+  aic7xxx_run_waiting_queues(p);
 }
 
 /*+F*************************************************************************
@@ -4139,18 +3307,59 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
  *   algorithm for determining the queue depth based on the maximum
  *   SCBs for the controller.
  *-F*************************************************************************/
-static void
-aic7xxx_select_queue_depth(struct Scsi_Host *host,
+static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
     Scsi_Device *scsi_devs)
 {
-  Scsi_Device *device;
+  Scsi_Device *device = scsi_devs;
+  int tq_depth = 2;
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
 
+#ifdef AIC7XXX_CMDS_PER_LUN
+  tq_depth = AIC7XXX_CMDS_PER_LUN;
+#else
+  {
+    if (p->maxhscbs <= 4)
+    {
+      tq_depth = 4;  /* Not many SCBs to work with. */
+    }
+    else
+    {
+      tq_depth = 8;
+    }
+  }
+#endif
+
   for (device = scsi_devs; device != NULL; device = device->next)
   {
     if (device->host == host)
     {
-      aic7xxx_device_queue_depth(p, device);
+      device->queue_depth = 2;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+      if (device->tagged_supported)
+      {
+        unsigned short target_mask = (1 << device->id) | device->channel;
+
+        if (!(p->discenable & target_mask))
+        {
+          printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
+                 "tagged queueing for target %d, channel %d, LUN %d.\n",
+                 host->host_no, device->id, device->channel, device->lun);
+        }
+        else
+        {
+          device->queue_depth = tq_depth;
+          if (device->tagged_queue == 0)
+          {
+            printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
+                  "channel %d, LUN %d, queue depth %d.\n", host->host_no,
+                   device->id, device->channel, device->lun,
+                   device->queue_depth);
+            device->tagged_queue = 1;
+            device->current_tag = SCB_LIST_NULL;
+          }
+        }
+      }
+#endif
     }
   }
 }
@@ -4177,7 +3386,7 @@ aic7xxx_select_queue_depth(struct Scsi_Host *host,
  *   The fourth byte's lowest bit seems to be an enabled/disabled
  *   flag (rest of the bits are reserved?).
  *-F*************************************************************************/
-static aha_chip_type
+static aha_type
 aic7xxx_probe(int slot, int base, aha_status_type *bios)
 {
   int i;
@@ -4186,7 +3395,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
   static struct {
     int n;
     unsigned char signature[sizeof(buf)];
-    aha_chip_type type;
+    aha_type type;
     int bios_disabled;
   } AIC7xxx[] = {
     { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
@@ -4225,8 +3434,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
        return (AIC7xxx[i].type);
       }
 
-      printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
-             "disabled at slot %d, ignored.\n", slot);
+      printk("aic7xxx: Disabled at slot %d, ignored.\n", slot);
     }
   }
 
@@ -4253,9 +3461,10 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
  *   useful in that it gives us an 800 nsec timer.  After a read from the
  *   SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
  *   later.
+ *
  *-F*************************************************************************/
 static int
-read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
+read_2840_seeprom(int base, struct seeprom_config *sc)
 {
   int i = 0, k = 0;
   unsigned char temp;
@@ -4268,11 +3477,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0)        \
+  while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0)   \
   {                                            \
     ;  /* Do nothing */                                \
   }                                            \
-  (void) inb(p->base + SEECTL_2840);
+  (void) inb(SEECTL_2840 + base);
 
   /*
    * Read the first 32 registers of the seeprom.  For the 2840,
@@ -4285,8 +3494,8 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     /*
      * Send chip select for one clock cycle.
      */
-    outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
-    CLOCK_PULSE(p);
+    outb(CK_2840 | CS_2840, SEECTL_2840 + base);
+    CLOCK_PULSE(base);
 
     /*
      * Now we're ready to send the read command followed by the
@@ -4295,11 +3504,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = CS_2840 | seeprom_read.bits[i];
-      outb(temp, p->base + SEECTL_2840);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL_2840 + base);
+      CLOCK_PULSE(base);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL_2840 + base);
+      CLOCK_PULSE(base);
     }
     /*
      * Send the 6 bit address (MSB first, LSB last).
@@ -4309,11 +3518,11 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
       temp = k;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = CS_2840 | temp;
-      outb(temp, p->base + SEECTL_2840);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL_2840 + base);
+      CLOCK_PULSE(base);
       temp = temp ^ CK_2840;
-      outb(temp, p->base + SEECTL_2840);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL_2840 + base);
+      CLOCK_PULSE(base);
     }
 
     /*
@@ -4325,12 +3534,12 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     for (i = 0; i <= 16; i++)
     {
       temp = CS_2840;
-      outb(temp, p->base + SEECTL_2840);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL_2840 + base);
+      CLOCK_PULSE(base);
       temp = temp ^ CK_2840;
-      seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
-      outb(temp, p->base + SEECTL_2840);
-      CLOCK_PULSE(p);
+      seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
+      outb(temp, SEECTL_2840 + base);
+      CLOCK_PULSE(base);
     }
     /*
      * The serial EEPROM has a checksum in the last word.  Keep a
@@ -4346,12 +3555,12 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(0, p->base + SEECTL_2840);
-    CLOCK_PULSE(p);
-    outb(CK_2840, p->base + SEECTL_2840);
-    CLOCK_PULSE(p);
-    outb(0, p->base + SEECTL_2840);
-    CLOCK_PULSE(p);
+    outb(0, SEECTL_2840 + base);
+    CLOCK_PULSE(base);
+    outb(CK_2840, SEECTL_2840 + base);
+    CLOCK_PULSE(base);
+    outb(0, SEECTL_2840 + base);
+    CLOCK_PULSE(base);
   }
 
 #if 0
@@ -4378,53 +3587,6 @@ read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
 #undef CLOCK_PULSE
 }
 
-/*+F*************************************************************************
- * Function:
- *   acquire_seeprom
- *
- * Description:
- *   Acquires access to the memory port on PCI controllers.
- *-F*************************************************************************/
-static inline int
-acquire_seeprom(struct aic7xxx_host *p)
-{
-  int wait;
-
-  /*
-   * Request access of the memory port.  When access is
-   * granted, SEERDY will go high.  We use a 1 second
-   * timeout which should be near 1 second more than
-   * is needed.  Reason: after the 7870 chip reset, there
-   * should be no contention.
-   */
-  outb(SEEMS, p->base + SEECTL);
-  wait = 1000;  /* 1000 msec = 1 second */
-  while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
-  {
-    wait--;
-    udelay(1000);  /* 1 msec */
-  }
-  if ((inb(p->base + SEECTL) & SEERDY) == 0)
-  {
-    outb(0, p->base + SEECTL);
-    return (0);
-  }
-  return (1);
-}
-
-/*+F*************************************************************************
- * Function:
- *   release_seeprom
- *
- * Description:
- *   Releases access to the memory port on PCI controllers.
- *-F*************************************************************************/
-static inline void
-release_seeprom(struct aic7xxx_host *p)
-{
-  outb(0, p->base + SEECTL);
-}
-
 /*+F*************************************************************************
  * Function:
  *   read_seeprom
@@ -4464,7 +3626,7 @@ release_seeprom(struct aic7xxx_host *p)
  *   first).  The clock cycling from low to high initiates the next data
  *   bit to be sent from the chip.
  *
- *   The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
+ *   The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
  *   register.  After successful arbitration for the memory port, the
  *   SEECS bit of the SEECTL register is connected to the chip select.
  *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
@@ -4474,14 +3636,17 @@ release_seeprom(struct aic7xxx_host *p)
  *   to this is when we first request access to the memory port.  The
  *   SEERDY goes high to signify that access has been granted and, for
  *   this case, has no implied timing.
+ *
  *-F*************************************************************************/
 static int
-read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
-    unsigned int len, seeprom_chip_type chip)
+read_seeprom(int base, int offset, struct seeprom_config *sc,
+    seeprom_chip_type chip)
 {
   int i = 0, k;
+  unsigned long timeout;
   unsigned char temp;
   unsigned short checksum = 0;
+  unsigned short *seeprom = (unsigned short *) sc;
   struct seeprom_cmd {
     unsigned char len;
     unsigned char bits[3];
@@ -4489,33 +3654,43 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
   struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
 
 #define CLOCK_PULSE(p) \
-  while ((inb(p->base + SEECTL) & SEERDY) == 0)        \
+  while ((inb(SEECTL + base) & SEERDY) == 0)   \
   {                                            \
     ;  /* Do nothing */                                \
   }
 
   /*
-   * Request access of the memory port.
+   * Request access of the memory port.  When access is
+   * granted, SEERDY will go high.  We use a 1 second
+   * timeout which should be near 1 second more than
+   * is needed.  Reason: after the 7870 chip reset, there
+   * should be no contention.
    */
-  if (acquire_seeprom(p) == 0)
+  outb(SEEMS, SEECTL + base);
+  timeout = jiffies + 100;  /* 1 second timeout */
+  while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
+  {
+    ; /* Do nothing!  Wait for access to be granted.  */
+  }
+  if ((inb(SEECTL + base) & SEERDY) == 0)
   {
+    outb(0, SEECTL + base);
     return (0);
   }
 
   /*
-   * Read 'len' registers of the seeprom.  For the 7870, the 93C46
-   * SEEPROM is a 1024-bit device with 64 16-bit registers but only
-   * the first 32 are used by Adaptec BIOS.  Some adapters use the
-   * 93C56 SEEPROM which is a 2048-bit device.  The loop will range
-   * from 0 to 'len' - 1.
+   * Read the first 32 registers of the seeprom.  For the 7870,
+   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
+   * but only the first 32 are used by Adaptec BIOS.  The loop
+   * will range from 0 to 31.
    */
-  for (k = 0; k < len; k++)
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
   {
     /*
      * Send chip select for one clock cycle.
      */
-    outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
-    CLOCK_PULSE(p);
+    outb(SEEMS | SEECK | SEECS, SEECTL + base);
+    CLOCK_PULSE(base);
 
     /*
      * Now we're ready to send the read command followed by the
@@ -4524,25 +3699,25 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     for (i = 0; i < seeprom_read.len; i++)
     {
       temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
-      outb(temp, p->base + SEECTL);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL + base);
+      CLOCK_PULSE(base);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL + base);
+      CLOCK_PULSE(base);
     }
     /*
-     * Send the 6 or 8 bit address (MSB first, LSB last).
+     * Send the 6 bit address (MSB first, LSB last).
      */
     for (i = ((int) chip - 1); i >= 0; i--)
     {
       temp = k + offset;
       temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
       temp = SEEMS | SEECS | (temp << 1);
-      outb(temp, p->base + SEECTL);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL + base);
+      CLOCK_PULSE(base);
       temp = temp ^ SEECK;
-      outb(temp, p->base + SEECTL);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL + base);
+      CLOCK_PULSE(base);
     }
 
     /*
@@ -4554,57 +3729,56 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
     for (i = 0; i <= 16; i++)
     {
       temp = SEEMS | SEECS;
-      outb(temp, p->base + SEECTL);
-      CLOCK_PULSE(p);
+      outb(temp, SEECTL + base);
+      CLOCK_PULSE(base);
       temp = temp ^ SEECK;
-      scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
-      outb(temp, p->base + SEECTL);
-      CLOCK_PULSE(p);
+      seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
+      outb(temp, SEECTL + base);
+      CLOCK_PULSE(base);
     }
 
     /*
-     * The serial EEPROM should have a checksum in the last word.
-     * Keep a running checksum for all words read except for the
-     * last word.  We'll verify the checksum after all words have
-     * been read.
+     * The serial EEPROM has a checksum in the last word.  Keep a
+     * running checksum for all words read except for the last
+     * word.  We'll verify the checksum after all words have been
+     * read.
      */
-    if (k < (len - 1))
+    if (k < (sizeof(*sc) / 2) - 1)
     {
-      checksum = checksum + scarray[k];
+      checksum = checksum + seeprom[k];
     }
 
     /*
      * Reset the chip select for the next command cycle.
      */
-    outb(SEEMS, p->base + SEECTL);
-    CLOCK_PULSE(p);
-    outb(SEEMS | SEECK, p->base + SEECTL);
-    CLOCK_PULSE(p);
-    outb(SEEMS, p->base + SEECTL);
-    CLOCK_PULSE(p);
+    outb(SEEMS, SEECTL + base);
+    CLOCK_PULSE(base);
+    outb(SEEMS | SEECK, SEECTL + base);
+    CLOCK_PULSE(base);
+    outb(SEEMS, SEECTL + base);
+    CLOCK_PULSE(base);
   }
 
   /*
    * Release access to the memory port and the serial EEPROM.
    */
-  release_seeprom(p);
+  outb(0, SEECTL + base);
 
 #if 0
-  printk("Computed checksum 0x%x, checksum read 0x%x\n",
-         checksum, scarray[len - 1]);
+  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
   printk("Serial EEPROM:");
-  for (k = 0; k < len; k++)
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
   {
     if (((k % 8) == 0) && (k != 0))
     {
       printk("\n              ");
     }
-    printk(" 0x%x", scarray[k]);
+    printk(" 0x%x", seeprom[k]);
   }
   printk("\n");
 #endif
 
-  if (checksum != scarray[len - 1])
+  if (checksum != sc->checksum)
   {
     return (0);
   }
@@ -4615,451 +3789,563 @@ read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
 
 /*+F*************************************************************************
  * Function:
- *   write_brdctl
+ *   detect_maxscb
  *
  * Description:
- *   Writes a value to the BRDCTL register.
+ *   Detects the maximum number of SCBs for the controller and returns
+ *   the count and a mask in config (config->maxscbs, config->qcntmask).
  *-F*************************************************************************/
-static inline void
-write_brdctl(struct aic7xxx_host *p, unsigned char value)
+static void
+detect_maxscb(struct aic7xxx_host_config *config)
 {
-  unsigned char brdctl;
-
-  brdctl = BRDCS | BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
-  brdctl |= value;
-  outb(brdctl, p->base + BRDCTL);
-  brdctl &= ~BRDSTB;
-  outb(brdctl, p->base + BRDCTL);
-  brdctl &= ~BRDCS;
-  outb(brdctl, p->base + BRDCTL);
-}
+  unsigned char sblkctl_reg;
+  int base, i;
+
+#ifdef AIC7XXX_PAGE_ENABLE
+  config->flags |= PAGE_ENABLED;
+#endif
+  base = config->base;
+  switch (config->type)
+  {
+    case AIC_7770:
+    case AIC_7771:
+    case AIC_284x:
+      /*
+       * Check for Rev C or E boards. Rev E boards can supposedly have
+       * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
+       * It's still not clear extactly what is different about the Rev E
+       * boards, but we think it allows 8 bit entries in the QOUTFIFO to
+       * support "paging" SCBs (more than 4 commands can be active at once).
+       *
+       * The Rev E boards have a read/write autoflush bit in the
+       * SBLKCTL register, while in the Rev C boards it is read only.
+       */
+      sblkctl_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
+      outb(sblkctl_reg, SBLKCTL + base);
+      if (inb(SBLKCTL + base) == sblkctl_reg)
+      {
+        /*
+         * We detected a Rev E board, we allow paging on this board.
+         */
+        printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
+               board_names[config->type]);
+       outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
+      }
+      else
+      {
+        /* Do not allow paging. */
+        config->flags &= ~PAGE_ENABLED;
+        printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
+               board_names[config->type]);
+      }
+      break;
+
+    default:
+      break;
+  }
+
+  /*
+   * Walk the SCBs to determine how many there are.
+   */
+  i = 1;
+  outb(0, SCBPTR + base);
+  outb(0, SCBARRAY + base);
+
+  while (i < AIC7XXX_MAXSCB)
+  {
+    outb(i, SCBPTR + base);
+    outb(i, SCBARRAY + base);
+    if (inb(SCBARRAY + base) != i)
+      break;
+    outb(0, SCBPTR + base);
+    if (inb(SCBARRAY + base) != 0)
+      break;
+
+    outb(i, SCBPTR + base);      /* Clear the control byte. */
+    outb(0, SCBARRAY + base);
+
+    config->qcntmask |= i;       /* Update the count mask. */
+    i++;
+  }
+  outb(i, SCBPTR + base);   /* Ensure we clear the control bytes. */
+  outb(0, SCBARRAY + base);
+  outb(0, SCBPTR + base); 
+  outb(0, SCBARRAY + base);
+
+  config->maxhscbs = i;
+  config->qcntmask |= i;
+  if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB))
+  {
+    config->maxscbs = AIC7XXX_MAXSCB;
+  }
+  else
+  {
+    config->flags &= ~PAGE_ENABLED;  /* Disable paging if we have 255 SCBs!. */
+    config->maxscbs = config->maxhscbs;
+  }
+
+  printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs);
+  if (config->flags & PAGE_ENABLED)
+    printk(", %d page-enabled SCBs.\n", config->maxscbs);
+  else
+    printk(", paging not enabled.\n");
 
-/*+F*************************************************************************
- * Function:
- *   read_brdctl
- *
- * Description:
- *   Reads the BRDCTL register.
- *-F*************************************************************************/
-static inline unsigned char
-read_brdctl(struct aic7xxx_host *p)
-{
-  outb(BRDRW | BRDCS, p->base + BRDCTL);
-  return (inb(p->base + BRDCTL));
 }
 
 /*+F*************************************************************************
  * Function:
- *   configure_termination
+ *   aic7xxx_register
  *
  * Description:
- *   Configures the termination settings on PCI adapters that have
- *   SEEPROMs available.
+ *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
  *-F*************************************************************************/
-static void
-configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
-    unsigned short adapter_control, unsigned char max_targ)
+static int
+aic7xxx_register(Scsi_Host_Template *template,
+    struct aic7xxx_host_config *config)
 {
-  unsigned char brdctl_int, brdctl_ext;
-  int internal50_present;
-  int internal68_present = 0;
-  int external_present = 0;
-  int eprom_present;
-  int high_on;
-  int low_on;
-  int old_verbose;
-
-  if (acquire_seeprom(p))
-  {
-    if (adapter_control & CFAUTOTERM)
-    {
-      old_verbose = aic7xxx_verbose;
-      printk(KERN_INFO "aic7xxx: Warning - detected auto-termination.  Please "
-                       "verify driver");
-      printk(KERN_INFO "         detected settings and use manual termination "
-                       "if necessary."); 
+  int i;
+  unsigned char sblkctl, flags = 0;
+  int max_targets;
+  int found = 1;
+  unsigned int sram, base;
+  unsigned char target_settings;
+  unsigned char scsi_conf, host_conf;
+  unsigned short ultraenable = 0;
+  int have_seeprom = FALSE;
+  struct Scsi_Host *host;
+  struct aic7xxx_host *p;
+  struct seeprom_config sc;
 
-      /* Configure auto termination. */
-      outb(SEECS | SEEMS, p->base + SEECTL);
+  base = config->base;
+
+  /*
+   * Lock out other contenders for our i/o space.
+   */
+  request_region(base, MAXREG - MINREG, "aic7xxx");
+
+  switch (config->type)
+  {
+    case AIC_7770:
+    case AIC_7771:
+      /*
+       * Use the boot-time option for the interrupt trigger type.  If not
+       * supplied (-1), then we use BIOS settings to determine the interrupt
+       * trigger type (level or edge) and use this value for pausing and
+       * unpausing the sequencer.
+       */
+      switch (aic7xxx_irq_trigger)
+      {
+        case  0: config->unpause = INTEN;          /* Edge */
+                 break;
+        case  1: config->unpause = IRQMS | INTEN;  /* Level */
+                 break;
+        case -1:
+        default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN; 
+                 break;
+      }
+      config->pause = config->unpause | PAUSE;
 
       /*
-       * First read the status of our cables.  Set the rom bank to
-       * 0 since the bank setting serves as a multiplexor for the
-       * cable detection logic.  BRDDAT5 controls the bank switch.
+       * For some 274x boards, we must clear the CHIPRST bit and pause
+       * the sequencer. For some reason, this makes the driver work.
+       * For 284x boards, we give it a CHIPRST just like the 294x boards.
        */
-      write_brdctl(p, 0);
+      outb(config->pause | CHIPRST, HCNTRL + base);
+      aic7xxx_delay(1);
+      if (inb(HCNTRL + base) & CHIPRST)
+      {
+       printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
+      }
+      outb(config->pause, HCNTRL + base);
 
       /*
-       * Now read the state of the internal connectors.  The
-       * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
-       * set when cables are not present (BRDDAT6 is INT50 and
-       * BRDDAT7 is INT68).
+       * Just to be on the safe side with the 274x, we will re-read the irq
+       * since there was some issue about resetting the board.
        */
-      brdctl_int = read_brdctl(p);
-      internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
-      if (max_targ > 8)
+      config->irq = inb(INTDEF + base) & 0x0F;
+      if ((config->type == AIC_7771) &&
+          (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
+      {
+        config->bios = AIC_DISABLED;
+        config->flags |= USE_DEFAULTS;
+      }
+      else
       {
-        internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
+        host_conf = inb(HOSTCONF + base);
+        config->bus_speed = host_conf & DFTHRSH;
+        config->busrtime = (host_conf << 2) & BOFF;
       }
 
       /*
-       * Set the rom bank to 1 and determine
-       * the other signals.
+       * Setup the FIFO threshold and the bus off time
        */
-      write_brdctl(p, BRDDAT5);
+      outb(config->bus_speed & DFTHRSH, BUSSPD + base);
+      outb(config->busrtime, BUSTIME + base);
 
       /*
-       * Now read the state of the external connectors.  BRDDAT6 is
-       * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
-       * set when the eprom is present.
+       * A reminder until this can be detected automatically.
        */
-      brdctl_ext = read_brdctl(p);
-      external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
-      eprom_present = brdctl_ext & BRDDAT7;
-      if (aic7xxx_verbose)
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+            (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+      break;
+
+    case AIC_284x:
+      outb(CHIPRST, HCNTRL + base);
+      config->unpause = UNPAUSE_284X;
+      config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
+      aic7xxx_delay(1);
+      outb(config->pause, HCNTRL + base);
+
+      config->parity = AIC_ENABLED;
+      config->irq = inb(INTDEF + base) & 0x0F;
+      host_conf = inb(HOSTCONF + base);
+
+      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
+      have_seeprom = read_2840_seeprom(base, &sc);
+      if (!have_seeprom)
       {
-        if (max_targ > 8)
+       printk("aic7xxx: Unable to read SEEPROM.\n");
+      }
+      else
+      {
+       printk("done.\n");
+        config->flags |= HAVE_SEEPROM;
+        if (sc.bios_control & CF284XEXTEND)
+          config->flags |= EXTENDED_TRANSLATION;
+        if (!(sc.bios_control & CFBIOSEN))
         {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
-                 "Ext-68 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 internal68_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
+          /*
+           * The BIOS is disabled; the values left over in scratch
+           * RAM are still valid.  Do not use defaults as in the
+           * AIC-7770 case.
+           */
+          config->bios = AIC_DISABLED;
         }
         else
         {
-          printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
-                 internal50_present ? "YES" : "NO",
-                 external_present ? "YES" : "NO");
+         config->parity = (sc.adapter_control & CFSPARITY) ?
+                          AIC_ENABLED : AIC_DISABLED;
+         config->low_term = (sc.adapter_control & CF284XSTERM) ?
+                               AIC_ENABLED : AIC_DISABLED;
+         /*
+          * XXX - Adaptec *does* make 284x wide controllers, but the
+          *       documents do not say where the high byte termination
+          *       enable bit is located.
+           */
         }
-        printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
-               "brdctl_ext=0x%x\n",
-               eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
       }
 
+      host_conf = inb(HOSTCONF + base);
+      config->bus_speed = host_conf & DFTHRSH;
+      config->busrtime = (host_conf << 2) & BOFF;
+
       /*
-       * Now set the termination based on what we found.  BRDDAT6
-       * controls wide termination enable.
+       * Setup the FIFO threshold and the bus off time
        */
-      high_on = FALSE;
-      low_on = FALSE;
-      if ((max_targ > 8) &&
-          ((external_present == 0) || (internal68_present == 0)))
-      {
-        high_on = TRUE;
-      }
+      outb(config->bus_speed & DFTHRSH, BUSSPD + base);
+      outb(config->busrtime, BUSTIME + base);
+
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+            (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+      break;
+
+    case AIC_7860:
+    case AIC_7861:
+    case AIC_7880:
+    case AIC_7881:
+    case AIC_7882:
+    case AIC_7883:
+    case AIC_7884:
+      /*
+       * Remember if Ultra was enabled in case there is no SEEPROM.
+       * Fall through to the rest of the AIC_78xx code.
+       */
+      if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
+        config->flags |= ULTRA_ENABLED;
 
-      if ((internal50_present + internal68_present + external_present) <= 1)
+    case AIC_7850:
+    case AIC_7855:
+    case AIC_7870:
+    case AIC_7871:
+    case AIC_7872:
+    case AIC_7873:
+    case AIC_7874:
+      /*
+       * Grab the SCSI ID before chip reset in case there is no SEEPROM.
+       */
+      config->scsi_id = inb(SCSIID + base) & OID;
+      outb(CHIPRST, HCNTRL + base);
+      config->unpause = UNPAUSE_294X;
+      config->pause = config->unpause | PAUSE;
+      aic7xxx_delay(1);
+      outb(config->pause, HCNTRL + base);
+
+      config->parity = AIC_ENABLED;
+
+      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
+      if ((config->type == AIC_7873) || (config->type == AIC_7883))
       {
-        low_on = TRUE;
+        have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
+                                    &sc, c56_66);
       }
-          
-      if (internal50_present && internal68_present && external_present)
+      else
       {
-        printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
-               "         Only two connectors on the adapter may be "
-               "used at a time!\n");
+        have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
+                                    &sc, c46);
       }
-
-      if (high_on == TRUE)
-        write_brdctl(p, BRDDAT6);
-      else
-        write_brdctl(p, 0);
-
-      if (low_on == TRUE)
-        *sxfrctl1 |= STPWEN;
-
-      if (aic7xxx_verbose)
+      if (!have_seeprom)
       {
-        if (max_targ > 8)
+        for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
         {
-          printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-                 low_on ? "ON" : "OFF",
-                 high_on ? "ON" : "OFF");
+          if (inb(sram) != 0x00)
+            break;
+        }
+        if (sram == base + TARG_SCRATCH)
+        {
+          for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
+          {
+            if (inb(sram) != 0xFF)
+              break;
+          }
+        }
+        if ((sram != base + 0x60) && (config->scsi_id != 0))
+        {
+          config->flags &= ~USE_DEFAULTS;
+         printk("\naic7xxx: Unable to read SEEPROM; "
+                 "using leftover BIOS values.\n");
         }
         else
         {
-          printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
+          printk("\n");
+          printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default "
+                 "settings.\n");
+          config->flags |= USE_DEFAULTS;
+          config->flags &= ~ULTRA_ENABLED;
+          config->scsi_id = 7;
         }
-      }
-      aic7xxx_verbose = old_verbose;
-    }
-    else
-    {
-      if (adapter_control & CFSTERM)
-      {
-        *sxfrctl1 |= STPWEN;
-      }
-      outb(SEEMS | SEECS, p->base + SEECTL);
-      /*
-       * Configure high byte termination.
-       */
-      if (adapter_control & CFWSTERM)
-      {
-        write_brdctl(p, BRDDAT6);
+        scsi_conf = ENSPCHK | RESET_SCSI;
       }
       else
       {
-        write_brdctl(p, 0);
-      }
-      if (aic7xxx_verbose)
-      {
-        printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
-               (adapter_control & CFSTERM) ? "ON" : "OFF",
-               (adapter_control & CFWSTERM) ? "ON" : "OFF");
+       printk("done.\n");
+        config->flags |= HAVE_SEEPROM;
+        if (!(sc.bios_control & CFBIOSEN))
+        {
+          /*
+           * The BIOS is disabled; the values left over in scratch
+           * RAM are still valid.  Do not use defaults as in the
+           * AIC-7770 case.
+           */
+          config->bios = AIC_DISABLED;
+          scsi_conf = ENSPCHK | RESET_SCSI;
+        }
+        else
+        {
+          scsi_conf = 0;
+          if (sc.adapter_control & CFRESETB)
+            scsi_conf |= RESET_SCSI;
+          if (sc.adapter_control & CFSPARITY)
+            scsi_conf |= ENSPCHK;
+         if (sc.bios_control & CFEXTEND)
+            config->flags |= EXTENDED_TRANSLATION;
+         config->scsi_id = (sc.brtime_id & CFSCSIID);
+         config->parity = (sc.adapter_control & CFSPARITY) ?
+                            AIC_ENABLED : AIC_DISABLED;
+         config->low_term = (sc.adapter_control & CFSTERM) ?
+                              AIC_ENABLED : AIC_DISABLED;
+         config->high_term = (sc.adapter_control & CFWSTERM) ?
+                               AIC_ENABLED : AIC_DISABLED;
+         config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
+          if (((config->type == AIC_7880) || (config->type == AIC_7881) ||
+               (config->type == AIC_7882) || (config->type == AIC_7883) ||
+               (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN))
+          {
+            printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
+                   "speed.\n");
+            config->flags |= ULTRA_ENABLED;
+          }
+        }
       }
-    }
-    release_seeprom(p);
-  }
-}
 
-/*+F*************************************************************************
- * Function:
- *   detect_maxscb
- *
- * Description:
- *   Detects the maximum number of SCBs for the controller and returns
- *   the count and a mask in p (p->maxscbs, p->qcntmask).
- *-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host *p)
-{
-  int i;
-  unsigned char max_scbid = 255;
-
-  /*
-   * It's possible that we've already done this for multichannel
-   * adapters.
-   */
-  if (p->scb_data->maxhscbs == 0)
-  {
-    /*
-     * We haven't initialized the SCB settings yet.  Walk the SCBs to
-     * determince how many there are.
-     */
-    outb(0, p->base + FREE_SCBH);
+      outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
+      config->bus_speed = DFTHRSH_100;
+      outb(config->bus_speed, DSPCISTATUS + base);
 
-    for (i = 0; i < AIC7XXX_MAXSCB; i++)
-    {
-      outb(i, p->base + SCBPTR);
-      outb(i, p->base + SCB_CONTROL);
-      if (inb(p->base + SCB_CONTROL) != i)
-        break;
-      outb(0, p->base + SCBPTR);
-      if (inb(p->base + SCB_CONTROL) != 0)
-        break;
-
-      outb(i, p->base + SCBPTR);
-      outb(0, p->base + SCB_CONTROL);   /* Clear the control byte. */
-      outb(i + 1, p->base + SCB_NEXT);  /* Set the next pointer. */
-      outb(SCB_LIST_NULL, p->base + SCB_TAG);  /* Make the tag invalid. */
-
-      /* Make the non-tagged targets not busy. */
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
-      outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
-    }
-
-    /* Make sure the last SCB terminates the free list. */
-    outb(i - 1, p->base + SCBPTR);
-    outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+      /*
+       * In case we are a wide card...
+       */
+      outb(config->scsi_id, SCSICONF + base + 1);
 
-    /* Ensure we clear the first (0) SCBs control byte. */
-    outb(0, p->base + SCBPTR);
-    outb(0, p->base + SCB_CONTROL);
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+            (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+      break;
 
-    p->scb_data->maxhscbs = i;
+    default:
+      panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
   }
 
-  if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
-  {
-    /* Determine the number of valid bits in the FIFOs. */
-    outb(max_scbid, p->base + QINFIFO);
-    max_scbid = inb(p->base + QINFIFO);
-    p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
-  }
-  else
-  {
-    p->scb_data->maxscbs = p->scb_data->maxhscbs;
-  }
-  if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
-  {
-    /*
-     * Disable paging if the QINFIFO doesn't allow more SCBs than
-     * we have in hardware.
-     */
-    p->flags &= ~PAGE_ENABLED;
-  }
+  detect_maxscb(config);
 
-  /*
-   * Set the Queue Full Count.  Some cards have more queue space than
-   * SCBs.
-   */
-  switch (p->chip_class)
+  if (config->chip_type == AIC_777x)
   {
-    case AIC_777x:
-      p->qfullcount = 4;
-      p->qcntmask = 0x07;
-      break;
-    case AIC_785x:
-    case AIC_786x:
-      p->qfullcount = 8;
-      p->qcntmask = 0x0f;
-      break;
-    case AIC_787x:
-    case AIC_788x:
-      if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
-      {
-        p->qfullcount = AIC7XXX_MAXSCB;
-        p->qcntmask = 0xFF;
-      }
-      else
-      {
-        p->qfullcount = 16;
-        p->qcntmask = 0x1F;
-      }
-      break;
+    if (config->pause & IRQMS)
+    {
+      printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
+    }
+    else
+    {
+      printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
+    }
   }
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_register
- *
- * Description:
- *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
- *-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
-{
-  int i;
-  unsigned char sblkctl, flags = 0;
-  int max_targets;
-  int found = 1;
-  char channel_ids[] = {'A', 'B', 'C'};
-  unsigned char target_settings;
-  unsigned char scsi_conf, sxfrctl1;
-  unsigned short ultraenable = 0;
-  struct Scsi_Host *host;
-
-  /*
-   * Lock out other contenders for our i/o space.
-   */
-  request_region(p->base, MAXREG - MINREG, "aic7xxx");
 
   /*
    * Read the bus type from the SBLKCTL register. Set the FLAGS
    * register in the sequencer for twin and wide bus cards.
    */
-  sblkctl = inb(p->base + SBLKCTL);
-  if (p->flags & PAGE_ENABLED)
+  sblkctl = inb(SBLKCTL + base);
+  if (config->flags & PAGE_ENABLED)
     flags = PAGESCBS;
 
   switch (sblkctl & SELBUS_MASK)
   {
     case SELNARROW:     /* narrow/normal bus */
-      p->scsi_id = inb(p->base + SCSICONF) & 0x07;
-      p->bus_type = AIC_SINGLE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
+      config->scsi_id = inb(SCSICONF + base) & 0x07;
+      config->bus_type = AIC_SINGLE;
+      outb(flags | SINGLE_BUS, FLAGS + base);
       break;
 
     case SELWIDE:     /* Wide bus */
-      p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
-      p->bus_type = AIC_WIDE;
-      p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
-      if (p->flags & MULTI_CHANNEL)
-      {
-        printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
-               channel_ids[p->chan_num], p->scsi_id);
-      }
-      else
-      {
-        printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
-                p->scsi_id);
-      }
-      outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
+      config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
+      config->bus_type = AIC_WIDE;
+      printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
+            board_names[config->type]);
+      outb(flags | WIDE_BUS, FLAGS + base);
       break;
 
     case SELBUSB:     /* Twin bus */
-      p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
-      p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
-      p->bus_type = AIC_TWIN;
-      printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
-             p->scsi_id, p->scsi_id_b);
-      outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
+      config->scsi_id = inb(SCSICONF + base) & 0x07;
+#ifdef AIC7XXX_TWIN_SUPPORT
+      config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
+      config->bus_type = AIC_TWIN;
+      printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
+            board_names[config->type]);
+      outb(flags | TWIN_BUS, FLAGS + base);
+#else
+      config->bus_type = AIC_SINGLE;
+      printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
+            board_names[config->type]);
+      outb(flags, FLAGS + base);
+#endif
       break;
 
     default:
       printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
-            "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
-      outb(0, p->base + SEQ_FLAGS);
+            "mail deang@teleport.com\n", inb(SBLKCTL + base));
+      outb(0, FLAGS + base);
       return (0);
   }
 
   /*
-   * Detect SCB parameters and initialize the SCB array.
+   * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
+   * take the card out of diagnostic mode and make the host adapter
+   * LED follow bus activity (will not always be on).
+   */
+  outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + base);
+
+  /*
+   * The IRQ level in i/o port 4 maps directly onto the real
+   * IRQ number. If it's ok, register it with the kernel.
+   *
+   * NB. the Adaptec documentation says the IRQ number is only
+   *     in the lower four bits; the ECU information shows the
+   *     high bit being used as well. Which is correct?
+   *
+   * The PCI cards get their interrupt from PCI BIOS.
    */
-  detect_maxscb(p);
-  printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
-         p->scb_data->maxhscbs, p->scb_data->maxscbs,
-         p->qfullcount, p->qcntmask);
+  if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
+  {
+    printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
+          "ignoring.\n");
+    return (0);
+  }
 
-  host = p->host;
+  /*
+   * Print out debugging information before re-enabling
+   * the card - a lot of registers on it can't be read
+   * when the sequencer is active.
+   */
+  debug_config(config);
 
-  host->can_queue = p->scb_data->maxscbs;
+  /*
+   * Register each "host" and fill in the returned Scsi_Host
+   * structure as best we can. Some of the parameters aren't
+   * really relevant for bus types beyond ISA, and none of the
+   * high-level SCSI code looks at it anyway. Why are the fields
+   * there? Also save the pointer so that we can find the
+   * information when an IRQ is triggered.
+   */
+  host = scsi_register(template, sizeof(struct aic7xxx_host));
+  host->can_queue = config->maxscbs;
   host->cmd_per_lun = 2;
   host->select_queue_depths = aic7xxx_select_queue_depth;
-  host->this_id = p->scsi_id;
-  host->io_port = p->base;
+  host->this_id = config->scsi_id;
+  host->io_port = config->base;
   host->n_io_port = 0xFF;
-  host->base = (unsigned char *) p->mbase;
-  host->irq = p->irq;
-  if (p->bus_type == AIC_WIDE)
+  host->base = (unsigned char *)config->mbase;
+  host->irq = config->irq;
+  if (config->bus_type == AIC_WIDE)
   {
     host->max_id = 16;
   }
-  if (p->bus_type == AIC_TWIN)
+  if (config->bus_type == AIC_TWIN)
   {
     host->max_channel = 1;
   }
 
+  p = (struct aic7xxx_host *) host->hostdata;
+
   p->host = host;
-  p->host_no = host->host_no;
+  p->host_no = (int)host->host_no;
   p->isr_count = 0;
+  p->base = base;
+  p->maxscbs = config->maxscbs;
+  p->maxhscbs = config->maxhscbs;
+  p->qcntmask = config->qcntmask;
+  p->mbase = (char *)config->mbase;
+  p->type = config->type;
+  p->chip_type = config->chip_type;
+  p->flags = config->flags;
+  p->chan_num = config->chan_num;
+  p->scb_link = &(p->scb_usage);
+#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
+  if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
+  {
+    shared_3985_scbs = &(p->scb_usage);
+    p->scb_link = &(p->scb_usage);
+  }
+#endif
+  p->scb_link->numscbs = 0;
+  p->bus_type = config->bus_type;
+  p->seeprom = sc;
   p->next = NULL;
   p->completeq.head = NULL;
   p->completeq.tail = NULL;
-  scbq_init(&p->scb_data->free_scbs);
+  scbq_init(&p->scb_link->free_scbs);
+  scbq_init(&p->page_scbs);
   scbq_init(&p->waiting_scbs);
+  scbq_init(&p->assigned_scbs);
+
+  p->unpause = config->unpause;
+  p->pause = config->pause;
 
-  for (i = 0; i <= NUMBER(p->device_status); i++)
+  for (i = 0; i <= 15; i++)
   {
     p->device_status[i].commands_sent = 0;
     p->device_status[i].flags = 0;
-    p->device_status[i].active_cmds = 0;
     p->device_status[i].last_reset = 0;
   }
-  if (aic7xxx_boards[p->irq] == NULL)
+  if (aic7xxx_boards[config->irq] == NULL)
   {
-    int result;
-    int irq_flags = 0;
-
-#ifdef AIC7XXX_OLD_ISR_TYPE
-    irg_flags = SA_INTERRUPT;
-#endif
     /*
      * Warning! This must be done before requesting the irq.  It is
      * possible for some boards to raise an interrupt as soon as
@@ -5067,26 +4353,17 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
      * kernel, an interrupt is triggered immediately.  Therefore, we
      * must ensure the board data is correctly set before the request.
      */
-    aic7xxx_boards[p->irq] = host;
+    aic7xxx_boards[config->irq] = host;
 
     /*
-     * Register IRQ with the kernel.  Only allow sharing IRQs with
-     * PCI devices.
+     * Register IRQ with the kernel.
      */
-    if (p->chip_class == AIC_777x)
-    {
-      result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
-    }
-    else
-    {
-      result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
-                "aic7xxx", NULL));
-    }
-    if (result < 0)
+    if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+       "aic7xxx", NULL))
     {
       printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
-             p->irq);
-      aic7xxx_boards[p->irq] = NULL;
+             config->irq);
+      aic7xxx_boards[config->irq] = NULL;
       return (0);
     }
   }
@@ -5097,74 +4374,79 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
      * registered host adapter. Add this host adapter's Scsi_Host
      * to the beginning of the linked list of hosts at the same IRQ.
      */
-    p->next = aic7xxx_boards[p->irq];
-    aic7xxx_boards[p->irq] = host;
+    p->next = aic7xxx_boards[config->irq];
+    aic7xxx_boards[config->irq] = host;
+  }
+
+  /*
+   * Load the sequencer program, then re-enable the board -
+   * resetting the AIC-7770 disables it, leaving the lights
+   * on with nobody home. On the PCI bus you *may* be home,
+   * but then your mailing address is dynamically assigned
+   * so no one can find you anyway :-)
+   */
+  printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+  aic7xxx_loadseq(base);
+
+  /*
+   * Set Fast Mode and Enable the board
+   */
+  outb(FASTMODE, SEQCTL + base);
+
+  if (p->chip_type == AIC_777x)
+  {
+    outb(ENABLE, BCTL + base);
   }
 
+  printk("done.\n");
+
   /*
    * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
    */
   if (p->bus_type == AIC_TWIN)
   {
     /*
-     * The controller is gated to channel B after a chip reset; set
-     * bus B values first.
+     * Select Channel B.
      */
-    outb(p->scsi_id_b, p->base + SCSIID);
-    scsi_conf = inb(p->base + SCSICONF + 1);
-    sxfrctl1 = inb(p->base + SXFRCTL1);
-    outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-         ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
+    outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
+
+    outb(config->scsi_id_b, SCSIID + base);
+    scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
+    outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
+#if EXPERIMENTAL_FLAGS
+    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
+#else
+    outb(ENSELTIMO, SIMODE1 + base);
+#endif
     if (p->flags & ULTRA_ENABLED)
     {
-      outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+      outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
     }
     else
     {
-      outb(DFON | SPIOEN, p->base + SXFRCTL0);
-    }
-
-    if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
-    {
-      /* Reset SCSI bus B. */
-      if (aic7xxx_verbose)
-        printk(KERN_INFO "aic7xxx: Resetting channel B\n");
-
-      aic7xxx_reset_current_bus(p);
+      outb(DFON | SPIOEN, SXFRCTL0 + base);
     }
 
-    /* Select channel A */
-    outb(SELNARROW, p->base + SBLKCTL);
+    /*
+     * Select Channel A
+     */
+    outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
   }
-
-  outb(p->scsi_id, p->base + SCSIID);
-  scsi_conf = inb(p->base + SCSICONF);
-  sxfrctl1 = inb(p->base + SXFRCTL1);
-  outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) | 
-       ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
-  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
+  outb(config->scsi_id, SCSIID + base);
+  scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
+  outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
+#if EXPERIMENTAL_FLAGS
+  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
+#else
+  outb(ENSELTIMO, SIMODE1 + base);
+#endif
   if (p->flags & ULTRA_ENABLED)
   {
-    outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
+    outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
   }
   else
   {
-    outb(DFON | SPIOEN, p->base + SXFRCTL0);
-  }
-
-  if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
-  {
-    /* Reset SCSI bus A. */
-    if (aic7xxx_verbose)
-      printk(KERN_INFO "aic7xxx: Resetting channel A\n");
-
-    aic7xxx_reset_current_bus(p);
-
-    /*
-     * Delay for the reset delay.
-     */
-    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+    outb(DFON | SPIOEN, SXFRCTL0 + base);
   }
 
   /*
@@ -5191,47 +4473,67 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   /*
    * Grab the disconnection disable table and invert it for our needs
    */
-  if (p->flags & USE_DEFAULTS)
+  if (have_seeprom)
   {
-    printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
-           "device parameters.\n");
-    p->discenable = 0xFFFF;
+    p->discenable = 0x0;
   }
   else
   {
-    p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
-        inb(p->base + DISC_DSB));
+    if (config->bios == AIC_DISABLED)
+    {
+      printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
+             "device parameters.\n");
+      p->discenable = 0xFFFF;
+    }
+    else
+    {
+      p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
+          inb(DISC_DSB + base));
+    }
   }
 
   for (i = 0; i < max_targets; i++)
   {
-    if (p->flags & USE_DEFAULTS)
+    if (config->flags & USE_DEFAULTS)
     {
-      target_settings = 0;  /* 10 or 20 MHz depending on Ultra enable */
+      target_settings = 0;  /* 10 MHz */
       p->needsdtr_copy |= (0x01 << i);
       p->needwdtr_copy |= (0x01 << i);
-      if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
-        ultraenable |= (0x01 << i);
     }
     else
     {
-      target_settings = inb(p->base + TARG_SCRATCH + i);
-      if (target_settings & 0x0F)
+      if (have_seeprom)
       {
-        p->needsdtr_copy |= (0x01 << i);
-        /*
-         * Default to asynchronous transfers (0 offset)
-         */
-        target_settings &= 0xF0;
+       target_settings = ((sc.device_flags[i] & CFXFER) << 4);
+       if (sc.device_flags[i] & CFSYNCH)
+       {
+         p->needsdtr_copy |= (0x01 << i);
+       }
+       if (sc.device_flags[i] & CFWIDEB)
+       {
+         p->needwdtr_copy |= (0x01 << i);
+       }
+       if (sc.device_flags[i] & CFDISC)
+        {
+          p->discenable |= (0x01 << i);
+        }
       }
-      if (target_settings & 0x80)
+      else
       {
-        p->needwdtr_copy |= (0x01 << i);
-        /*
-         * Clear the wide flag. When wide negotiation is successful,
-         * we'll enable it.
-         */
-        target_settings &= 0x7F;
+        target_settings = inb(TARG_SCRATCH + base + i);
+        if (target_settings & 0x0F)
+        {
+          p->needsdtr_copy |= (0x01 << i);
+          /*
+           * Default to asynchronous transfers (0 offset)
+           */
+          target_settings &= 0xF0;
+        }
+        if (target_settings & 0x80)
+        {
+          p->needwdtr_copy |= (0x01 << i);
+          target_settings &= 0x7F;
+        }
       }
       if (p->flags & ULTRA_ENABLED)
       {
@@ -5242,471 +4544,126 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
           case 0x20:
             ultraenable |= (0x01 << i);
             break;
-          case 0x40:  /* treat 10MHz as 10MHz without Ultra enabled */
+          case 0x40:
             target_settings &= ~(0x70);
             break;
           default:
-            break;
-        }
-      }
-    }
-    outb(target_settings, p->base + TARG_SCRATCH + i);
-  }
-
-  /*
-   * If we are not wide, forget WDTR. This makes the driver
-   * work on some cards that don't leave these fields cleared
-   * when BIOS is not installed.
-   */
-  if (p->bus_type != AIC_WIDE)
-  {
-    p->needwdtr_copy = 0;
-  }
-  p->needsdtr = p->needsdtr_copy;
-  p->needwdtr = p->needwdtr_copy;
-  p->orderedtag = 0;
-  outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
-  outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
-
-  /*
-   * Set the number of available hardware SCBs.
-   */
-  outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
-
-  /*
-   * 2s compliment of maximum tag value.
-   */
-  i = p->scb_data->maxscbs;
-  outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
-
-  /*
-   * Allocate enough hardware scbs to handle the maximum number of
-   * concurrent transactions we can have.  We have to make sure that
-   * the allocated memory is contiguous memory.  The Linux kmalloc
-   * routine should only allocate contiguous memory, but note that
-   * this could be a problem if kmalloc() is changed.
-   */
-  if (p->scb_data->hscbs == NULL)
-  {
-    size_t array_size;
-    unsigned int hscb_physaddr;
-
-    array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
-    p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
-    if (p->scb_data->hscbs == NULL)
-    {
-      printk("aic7xxx: Unable to allocate hardware SCB array; "
-             "failing detection.\n");
-      release_region(p->base, MAXREG - MINREG);
-      /*
-       * Ensure that we only free the IRQ when there is _not_ another
-       * aic7xxx adapter sharing this IRQ.  The adapters are always
-       * added to the beginning of the list, so we can grab the next
-       * pointer and place it back in the board array.
-       */
-      if (p->next == NULL)
-      {
-        free_irq(p->irq, aic7xxx_isr);
-      }
-      aic7xxx_boards[p->irq] = p->next;
-      return(0);
-    }
-    /* At least the control byte of each SCB needs to be 0. */
-    memset(p->scb_data->hscbs, 0, array_size);
-
-    /* Tell the sequencer where it can find the hardware SCB array. */
-    hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
-    outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
-    outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
-    outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
-    outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
-  }
-
-  /*
-   * QCount mask to deal with broken aic7850s that sporadically get
-   * garbage in the upper bits of their QCNT registers.
-    */
-  outb(p->qcntmask, p->base + QCNTMASK);
-
-  /*
-   * We don't have any waiting selections or disconnected SCBs.
-   */
-  outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
-  outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
-
-  /*
-   * Message out buffer starts empty
-   */
-  outb(0, p->base + MSG_LEN);
-
-  /*
-   * Load the sequencer program, then re-enable the board -
-   * resetting the AIC-7770 disables it, leaving the lights
-   * on with nobody home. On the PCI bus you *may* be home,
-   * but then your mailing address is dynamically assigned
-   * so no one can find you anyway :-)
-   */
-  aic7xxx_loadseq(p);
-
-  if (p->chip_class == AIC_777x)
-  {
-    outb(ENABLE, p->base + BCTL);  /* Enable the boards BUS drivers. */
-  }
-
-  /*
-   * Unpause the sequencer before returning and enable
-   * interrupts - we shouldn't get any until the first
-   * command is sent to us by the high-level SCSI code.
-   */
-  unpause_sequencer(p, /* unpause_always */ TRUE);
-
-  return (found);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_chip_reset
- *
- * Description:
- *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
- *   is paused upon return.
- *-F*************************************************************************/
-static void
-aic7xxx_chip_reset(struct aic7xxx_host *p)
-{
-  unsigned char hcntrl;
-  int wait;
-
-  /* Retain the IRQ type across the chip reset. */
-  hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
-
-  /*
-   * For some 274x boards, we must clear the CHIPRST bit and pause
-   * the sequencer. For some reason, this makes the driver work.
-   */
-  outb(PAUSE | CHIPRST, p->base + HCNTRL);
-
-  /*
-   * In the future, we may call this function as a last resort for
-   * error handling.  Let's be nice and not do any unecessary delays.
-   */
-  wait = 1000;  /* 1 second (1000 * 1000 usec) */
-  while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
-  {
-    udelay(1000);  /* 1 msec = 1000 usec */
-    wait = wait - 1;
-  }
-
-  if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
-  {
-    printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
-  }
-
-  outb(hcntrl | PAUSE, p->base + HCNTRL);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_alloc
- *
- * Description:
- *   Allocate and initialize a host structure.  Returns NULL upon error
- *   and a pointer to a aic7xxx_host struct upon success.
- *-F*************************************************************************/
-static struct aic7xxx_host *
-aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
-    aha_chip_type chip_type, int flags, scb_data_type *scb_data)
-{
-  struct aic7xxx_host *p = NULL;
-  struct Scsi_Host *host;
-
-  /*
-   * Allocate a storage area by registering us with the mid-level
-   * SCSI layer.
-   */
-  host = scsi_register(sht, sizeof(struct aic7xxx_host));
-
-  if (host != NULL)
-  {
-    p = (struct aic7xxx_host *) host->hostdata;
-    memset(p, 0, sizeof(struct aic7xxx_host));
-    p->host = host;
-
-    if (scb_data != NULL)
-    {
-      /*
-       * We are sharing SCB data areas; use the SCB data pointer
-       * provided.
-       */
-      p->scb_data = scb_data;
-      p->flags |= SHARED_SCBDATA;
-    }
-    else
-    {
-      /*
-       * We are not sharing SCB data; allocate one.
-       */
-      p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
-      if (p->scb_data != NULL)
-      {
-        memset(p->scb_data, 0, sizeof(scb_data_type));
-        scbq_init (&p->scb_data->free_scbs);
-      }
-      else
-      {
-        /*
-         * For some reason we don't have enough memory.  Free the
-         * allocated memory for the aic7xxx_host struct, and return NULL.
-         */
-        scsi_unregister(host);
-        p = NULL;
-      }
-    }
-    if (p != NULL)
-    {
-      p->host_no = host->host_no;
-      p->base = base;
-      p->mbase = mbase;
-      p->maddr = NULL;
-      p->flags = flags;
-      p->chip_type = chip_type;
-      p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
-      p->pause = p->unpause | PAUSE;
-    }
-  }
-  return (p);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_free
- *
- * Description:
- *   Frees and releases all resources associated with an instance of
- *   the driver (struct aic7xxx_host *).
- *-F*************************************************************************/
-static void
-aic7xxx_free (struct aic7xxx_host *p)
-{
-  int i;
-
-  /*
-   * We should be careful in freeing the scb_data area.  For those
-   * adapters sharing external SCB RAM(398x), there will be only one
-   * scb_data area allocated.  The flag SHARED_SCBDATA indicates if
-   * one adapter is sharing anothers SCB RAM.
-   */
-  if (!(p->flags & SHARED_SCBDATA))
-  {
-    /*
-     * Free the allocated hardware SCB space.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-    /*
-     * Free the driver SCBs.  These were allocated on an as-need
-     * basis.
-     */
-    for (i = 0; i < p->scb_data->numscbs; i++)
-    {
-      kfree(p->scb_data->scb_array[i]);
-    }
-    /*
-     * Free the hardware SCBs.
-     */
-    if (p->scb_data->hscbs != NULL)
-    {
-      kfree(p->scb_data->hscbs);
-    }
-
-    /*
-     * Free the SCB data area.
-     */
-    kfree(p->scb_data);
-  }
-  /*
-   * Free the instance of the device structure.
-   */
-  scsi_unregister(p->host);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_load_seeprom
- *
- * Description:
- *   Load the seeprom and configure adapter and target settings.
- *   Returns 1 if the load was successful and 0 otherwise.
- *-F*************************************************************************/
-static int
-load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
-{
-  int have_seeprom = 0;
-  int i, max_targets;
-  unsigned char target_settings, scsi_conf;
-  unsigned short scarray[128];
-  struct seeprom_config *sc = (struct seeprom_config *) scarray;
-
-  if (aic7xxx_verbose)
-  {
-    printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
-  }
-  switch (p->chip_type)
-  {
-    case AIC_7770:  /* None of these adapters have seeproms. */
-    case AIC_7771:
-    case AIC_7850:
-    case AIC_7855:
-      break;
-
-    case AIC_284x:
-      have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
-      break;
-
-    case AIC_7861:
-    case AIC_7870:
-    case AIC_7871:
-    case AIC_7872:
-    case AIC_7874:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7884:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
-                                  scarray, sizeof(*sc)/2, C46);
-      break;
-
-    case AIC_7860:  /* Motherboard Ultra controllers might have RAID port. */
-    case AIC_7880:
-      have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
-      if (!have_seeprom)
-      {
-        have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
+            break;
+        }
       }
-      break;
-
-    case AIC_7873:  /* The 3985 adapters use the 93c56 serial EEPROM. */
-    case AIC_7883:
-      have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
-                                  scarray, sizeof(scarray)/2, C56_66);
-      break;
-
-    default:
-      break;
+    }
+    outb(target_settings, (TARG_SCRATCH + base + i));
   }
 
-  if (!have_seeprom)
+  /*
+   * If we are not wide, forget WDTR. This makes the driver
+   * work on some cards that don't leave these fields cleared
+   * when BIOS is not installed.
+   */
+  if (p->bus_type != AIC_WIDE)
   {
-    if (aic7xxx_verbose)
-    {
-      printk("\naic7xxx: No SEEPROM available; using defaults.\n");
-    }
-    p->flags |= USE_DEFAULTS;
+    p->needwdtr_copy = 0;
   }
-  else
-  {
-    if (aic7xxx_verbose)
-    {
-      printk("done\n");
-    }
-    p->flags |= HAVE_SEEPROM;
-
-    /*
-     * Update the settings in sxfrctl1 to match the termination settings.
-     */
-    *sxfrctl1 = 0;
-
-    /*
-     * First process the settings that are different between the VLB
-     * and PCI adapter seeproms.
-     */
-    if (p->chip_class == AIC_777x)
-    {
-      /* VLB adapter seeproms */
-      if (sc->bios_control & CF284XEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+  p->needsdtr = p->needsdtr_copy;
+  p->needwdtr = p->needwdtr_copy;
+  p->orderedtag = 0;
+#if 0
+  printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
+  printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
+#endif
+  outb(ultraenable & 0xFF, ULTRA_ENB + base);
+  outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1);
 
-      if (sc->adapter_control & CF284XSTERM)
-        *sxfrctl1 |= STPWEN;
-      /*
-       * The 284x SEEPROM doesn't have a max targets field.  We
-       * set it to 16 to make sure we take care of the 284x-wide
-       * adapters.  For narrow adapters, going through the extra
-       * 8 target entries will not cause any harm since they will
-       * will not be used.
-       *
-       * XXX - We should probably break out the bus detection
-       *       from the register function so we can use it here
-       *       to tell us how many targets there really are.
-       */
-      max_targets = 16;
-    }
-    else
-    {
-      /* PCI adapter seeproms */
-      if (sc->bios_control & CFEXTEND)
-        p->flags |= EXTENDED_TRANSLATION;
+  /*
+   * Set the number of available SCBs.
+   */
+  outb(config->maxhscbs, SCBCOUNT + base);
 
-      if (sc->adapter_control & CFSTERM)
-        *sxfrctl1 |= STPWEN;
+  /*
+   * 2s compliment of maximum tag value.
+   */
+  i = p->maxscbs;
+  outb(-i & 0xFF, COMP_SCBCOUNT + base);
 
-      /* Limit to 16 targets just in case. */
-      max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
-    }
+  /*
+   * Set the QCNT (queue count) mask to deal with broken aic7850s that
+   * sporatically get garbage in the upper bits of their QCNT registers.
+   */
+  outb(config->qcntmask, QCNTMASK + base);
 
-    for (i = 0; i < max_targets; i++)
-    {
-      target_settings = (sc->device_flags[i] & CFXFER) << 4;
-      if (sc->device_flags[i] & CFSYNCH)
-        target_settings |= SOFS;
-      if (sc->device_flags[i] & CFWIDEB)
-        target_settings |= WIDEXFER;
-      if (sc->device_flags[i] & CFDISC)
-        p->discenable |= (0x01 << i);
-      outb(target_settings, p->base + TARG_SCRATCH + i);
-    }
-    outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
-    outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
+  /*
+   * Clear the active flags - no targets are busy.
+   */
+  outb(0, ACTIVE_A + base);
+  outb(0, ACTIVE_B + base);
 
-    p->scsi_id = sc->brtime_id & CFSCSIID;
+  /*
+   * We don't have any waiting selections or disconnected SCBs.
+   */
+  outb(SCB_LIST_NULL, WAITING_SCBH + base);
+  outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
 
-    scsi_conf = (p->scsi_id & 0x7);
-    if (sc->adapter_control & CFSPARITY)
-      scsi_conf |= ENSPCHK;
-    if (sc->adapter_control & CFRESETB)
-      scsi_conf |= RESET_SCSI;
+  /*
+   * Message out buffer starts empty
+   */
+  outb(0, MSG_LEN + base);
 
-    if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+  /*
+   * Reset the SCSI bus. Is this necessary?
+   *   There may be problems for a warm boot without resetting
+   *   the SCSI bus. Either BIOS settings in scratch RAM
+   *   will not get reinitialized, or devices may stay at
+   *   previous negotiated settings (SDTR and WDTR) while
+   *   the driver will think that no negotiations have been
+   *   performed.
+   *
+   * Some devices need a long time to "settle" after a SCSI
+   * bus reset.
+   */
+  if (!aic7xxx_no_reset)
+  {
+    printk("aic7xxx: Resetting the SCSI bus...");
+    if (p->bus_type == AIC_TWIN)
     {
       /*
-       * We allow the operator to override ultra enable through
-       * the boot prompt.
+       * Select Channel B.
        */
-      if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
-      {
-        /* Treat us as a non-ultra card */
-        p->flags &= ~ULTRA_ENABLED;
-      }
-    }
+      outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
 
-    /* Set the host ID */
-    outb(scsi_conf, p->base + SCSICONF);
-    /* In case we are a wide card */
-    outb(p->scsi_id, p->base + SCSICONF + 1);
+      outb(SCSIRSTO, SCSISEQ + base);
+      udelay(1000);
+      outb(0, SCSISEQ + base);
 
-    if (p->chip_class != AIC_777x)
-    {
-      /*
-       * Update the settings in sxfrctl1 to match the termination
-       * settings.
+      /* Ensure we don't get a RSTI interrupt from this. */
+      outb(CLRSCSIRSTI, CLRSINT1 + base);
+      outb(CLRSCSIINT, CLRINT + base);
+
+     /*
+       * Select Channel A.
        */
-      *sxfrctl1 = 0;
-      configure_termination(p, sxfrctl1, sc->adapter_control,
-        (unsigned char) sc->max_targets & CFMAXTARG);
+      outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
     }
+
+    outb(SCSIRSTO, SCSISEQ + base);
+    udelay(1000);
+    outb(0, SCSISEQ + base);
+
+    /* Ensure we don't get a RSTI interrupt from this. */
+    outb(CLRSCSIRSTI, CLRSINT1 + base);
+    outb(CLRSCSIINT, CLRINT + base);
+
+    aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+    printk("done.\n");
   }
-  return (have_seeprom);
+
+  /*
+   * Unpause the sequencer before returning and enable
+   * interrupts - we shouldn't get any until the first
+   * command is sent to us by the high-level SCSI code.
+   */
+  UNPAUSE_SEQUENCER(p);
+  return (found);
 }
 
 /*+F*************************************************************************
@@ -5715,24 +4672,17 @@ load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
  *
  * 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)
 {
-  int found = 0;
-  aha_status_type adapter_bios;
-  aha_chip_class_type chip_class;
-  aha_chip_type chip_type;
-  int slot, base;
-  int chan_num = 0;
-  unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
+  int found = 0, slot, base;
+  unsigned char irq = 0;
   int i;
-  struct aic7xxx_host *p;
+  struct aic7xxx_host_config config;
+
+  template->proc_dir = &proc_scsi_aic7xxx;
+  config.chan_num = 0;
 
   /*
    * Since we may allow sharing of IRQs, it is imperative
@@ -5746,9 +4696,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
     aic7xxx_boards[i] = NULL;
   }
 
-  template->proc_dir = &proc_scsi_aic7xxx;
-  template->name = aic7xxx_info(NULL);
-
   /*
    * Initialize the spurious count to 0.
    */
@@ -5770,170 +4717,33 @@ aic7xxx_detect(Scsi_Host_Template *template)
       continue;
     }
 
-    chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
-    if (chip_type != AIC_NONE)
+    config.type = aic7xxx_probe(slot, HID0 + base, &(config.bios));
+    if (config.type != AIC_NONE)
     {
-
-      switch (chip_type)
-      {
-        case AIC_7770:
-        case AIC_7771:
-          printk("aic7xxx: <%s> at EISA %d\n",
-                 board_names[chip_type], slot);
-          break;
-        case AIC_284x:
-          printk("aic7xxx: <%s> at VLB %d\n",
-                 board_names[chip_type], slot);
-          break;
-        default:
-          break;
-      }
-
       /*
        * We found a card, allow 1 spurious interrupt.
        */
       aic7xxx_spurious_count = 1;
 
       /*
-       * Pause the card preserving the IRQ type.  Allow the operator
-       * to override the IRQ trigger.
+       * We "find" a AIC-7770 if we locate the card
+       * signature and we can set it up and register
+       * it with the kernel without incident.
        */
-      if (aic7xxx_irq_trigger == 1)
-        hcntrl = IRQMS;  /* Level */
-      else if (aic7xxx_irq_trigger == 0)
-        hcntrl = 0;  /* Edge */
-      else
-        hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
-      outb(hcntrl | PAUSE, base + HCNTRL);
-
-      irq = inb(INTDEF + base) & 0x0F;
-      switch (irq)
-      {
-        case 9:
-        case 10:
-        case 11:
-        case 12:
-        case 14:
-        case 15:
-          break;
-
-        default:
-          printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
-          "level, ignoring.\n");
-          irq = 0;
-          break;
-      }
-
-      if (irq != 0)
-      {
-        p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
-        if (p == NULL)
-        {
-          printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-          continue;
-        }
-        p->irq = irq & 0x0F;
-        p->chip_class = AIC_777x;
-#ifdef AIC7XXX_PAGE_ENABLE
-        p->flags |= PAGE_ENABLED;
-#endif
-        p->instance = found;
-        if (aic7xxx_extended)
-        {
-          p->flags |= EXTENDED_TRANSLATION;
-        }
-        aic7xxx_chip_reset(p);
-
-        switch (p->chip_type)
-        {
-          case AIC_7770:
-          case AIC_7771:
-          {
-            unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
-
-            /*
-             * Get the primary channel information.  Right now we don't
-             * do anything with this, but someday we will be able to inform
-             * the mid-level SCSI code which channel is primary.
-             */
-            if (biosctrl & CHANNEL_B_PRIMARY)
-            {
-              p->flags |= FLAGS_CHANNEL_B_PRIMARY;
-            }
-
-            if ((biosctrl & BIOSMODE) == BIOSDISABLED)
-            {
-              p->flags |= USE_DEFAULTS;
-            }
-            break;
-          }
-
-          case AIC_284x:
-            if (!load_seeprom(p, &sxfrctl1))
-            {
-              if (aic7xxx_verbose)
-                printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
-            }
-            break;
-
-          default:  /* Won't get here. */
-            break;
-        }
-        printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
-               (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
-               (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
-        /*
-         * Check for Rev C or E boards. Rev E boards can supposedly have
-         * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
-         * It's still not clear extactly what is different about the Rev E
-         * boards, but we think it allows 8 bit entries in the QOUTFIFO to
-         * support "paging" SCBs (more than 4 commands can be active at once).
-         *
-         * The Rev E boards have a read/write autoflush bit in the
-         * SBLKCTL register, while in the Rev C boards it is read only.
-         */
-        sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
-        outb(sblkctl, p->base + SBLKCTL);
-        if (inb(p->base + SBLKCTL) == sblkctl)
-        {
-          /*
-           * We detected a Rev E board, we allow paging on this board.
-           */
-          printk("Revision >= E\n");
-          outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
-        }
-        else
-        {
-          /* Do not allow paging. */
-          p->flags &= ~PAGE_ENABLED;
-          printk("Revision <= C\n");
-        }
+      config.chip_type = AIC_777x;
+      config.base = base;
+      config.mbase = 0;
+      config.irq = irq;
+      config.parity = AIC_ENABLED;
+      config.low_term = AIC_UNKNOWN;
+      config.high_term = AIC_UNKNOWN;
+      config.flags = 0;
+      if (aic7xxx_extended)
+        config.flags |= EXTENDED_TRANSLATION;
+      config.bus_speed = DFTHRSH_100;
+      config.busrtime = BOFF;
+      found += aic7xxx_register(template, &config);
 
-        /*
-         * Set the FIFO threshold and the bus off time.
-         */
-        hostconf = inb(p->base + HOSTCONF);
-        outb(hostconf & DFTHRSH, p->base + BUSSPD);
-        outb((hostconf << 2) & BOFF, p->base + BUSTIME);
-
-        /*
-         * Try to initialize the card and register it with the kernel.
-         */
-        if (aic7xxx_register(template, p))
-        {
-          /*
-           * We successfully found a board and registered it.
-           */
-          found = found + 1;
-        }
-        else
-        {
-          /*
-           * Something went wrong; release and free all resources.
-           */
-          aic7xxx_free(p);
-        }
-      }
       /*
        * Disallow spurious interrupts.
        */
@@ -5949,15 +4759,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
   {
     struct
     {
-      unsigned short      vendor_id;
-      unsigned short      device_id;
-      aha_chip_type       chip_type;
-      aha_chip_class_type chip_class;
+      unsigned short vendor_id;
+      unsigned short device_id;
+      aha_type       card_type;
+      aha_chip_type  chip_type;
     } const aic7xxx_pci_devices[] = {
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
-      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x},
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_785x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
@@ -5970,14 +4780,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
     };
 
-    int error, flags;
+    int error;
     int done = 0;
     unsigned int iobase, mbase;
     unsigned short index = 0;
     unsigned char pci_bus, pci_device_fn;
-    unsigned char ultra_enb = 0;
-    unsigned int  devconfig, class_revid;
-    scb_data_type *shared_scb_data = NULL;
+    unsigned int  csize_lattime;
+    unsigned int  class_revid;
+    unsigned int  devconfig;
     char rev_id[] = {'B', 'C', 'D'};
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -5994,33 +4804,36 @@ aic7xxx_detect(Scsi_Host_Template *template)
         }
         else  /* Found an Adaptec PCI device. */
         {
-          chip_class = aic7xxx_pci_devices[i].chip_class;
-          chip_type = aic7xxx_pci_devices[i].chip_type;
-          chan_num = 0;
-          flags = 0;
-          switch (aic7xxx_pci_devices[i].chip_type)
+          config.type = aic7xxx_pci_devices[i].card_type;
+          config.chip_type = aic7xxx_pci_devices[i].chip_type;
+          config.chan_num = 0;
+          config.bios = AIC_ENABLED;  /* Assume bios is enabled. */
+          config.flags = 0;
+          config.busrtime = 40;
+          switch (config.type)
           {
             case AIC_7850:
             case AIC_7855:
-              flags |= USE_DEFAULTS;
+            case AIC_7860:
+            case AIC_7861:
+              config.bios = AIC_DISABLED;
+              config.flags |= USE_DEFAULTS;
+              config.bus_speed = DFTHRSH_100;
               break;
 
             case AIC_7872:  /* 3940 */
             case AIC_7882:  /* 3940-Ultra */
-              flags |= MULTI_CHANNEL;
-              chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
+              config.chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
               number_of_3940s++;
               break;
 
             case AIC_7873:  /* 3985 */
             case AIC_7883:  /* 3985-Ultra */
-              chan_num = number_of_3985s;  /* Has 3 controllers */
-              flags |= MULTI_CHANNEL;
+              config.chan_num = number_of_3985s;  /* Has 3 controllers */
               number_of_3985s++;
               if (number_of_3985s == 3)
               {
                 number_of_3985s = 0;
-                shared_scb_data = NULL;
               }
               break;
 
@@ -6037,165 +4850,39 @@ aic7xxx_detect(Scsi_Host_Template *template)
                                             PCI_INTERRUPT_LINE, &irq);
           error += pcibios_read_config_dword(pci_bus, pci_device_fn,
                                             PCI_BASE_ADDRESS_1, &mbase);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             DEVCONFIG, &devconfig);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                             CLASS_PROGIF_REVID, &class_revid);
-
-          printk("aic7xxx: <%s> at PCI %d\n",
-                 board_names[chip_type], PCI_SLOT(pci_device_fn));
 
           /*
-           * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
+           * The first bit of PCI_BASE_ADDRESS_0 is always set, so
            * we mask it off.
            */
           iobase &= PCI_BASE_ADDRESS_IO_MASK;
 
-          p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
-                            shared_scb_data);
-
-          if (p == NULL)
-          {
-            printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
-            continue;
-          }
-
-          /* Remember to set the channel number, irq, and chip class. */
-          p->chan_num = chan_num;
-          p->irq = irq;
-          p->chip_class = chip_class;
-#ifdef AIC7XXX_PAGE_ENABLE
-          p->flags |= PAGE_ENABLED;
-#endif
-          p->instance = found;
-
           /*
-           * Remember how the card was setup in case there is no seeprom.
+           * Read the PCI burst size and latency timer.
            */
-          p->scsi_id = inb(p->base + SCSIID) & OID;
-          if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
-          {
-            p->flags |= ULTRA_ENABLED;
-            ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
-          }
-         sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
-
-          aic7xxx_chip_reset(p);
-
-#ifdef AIC7XXX_USE_EXT_SCBRAM
-          if (devconfig & RAMPSM)
-          {
-            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
-                   "access.\n");
-            /*
-             * XXX - Assume 9 bit SRAM and enable parity checking.
-             */
-            devconfig |= EXTSCBPEN;
-
-            /*
-             * XXX - Assume fast SRAM and only enable 2 cycle access if we
-             *       are sharing the SRAM across multiple adapters (398x).
-             */
-            if ((devconfig & MPORTMODE) == 0)
-            {
-              devconfig |= EXTSCBTIME;
-            }
-            devconfig &= ~SCBRAMSEL;
-            pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                       DEVCONFIG, devconfig);
-          }
-#endif
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             CSIZE_LATTIME, &csize_lattime);
+          printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
+                 "PCLKS\n", (int) (csize_lattime & CACHESIZE),
+                 (csize_lattime >> 8) & 0x000000ff);
 
-          if ((p->flags & USE_DEFAULTS) == 0)
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             CLASS_PROGIF_REVID, &class_revid);
+          if ((class_revid & DEVREVID) < 3)
           {
-            load_seeprom(p, &sxfrctl1);
+            printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
+                   rev_id[class_revid & DEVREVID]);
           }
 
-          /*
-           * Take the LED out of diagnostic mode
-           */
-          sblkctl = inb(p->base + SBLKCTL);
-          outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
-
-          /*
-           * We don't know where this is set in the SEEPROM or by the
-           * BIOS, so we default to 100%.
-           */
-          outb(DFTHRSH_100, p->base + DSPCISTATUS);
-
-          if (p->flags & USE_DEFAULTS)
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                             DEVCONFIG, &devconfig);
+          if (error)
           {
-            int j;
-            /*
-             * Default setup; should only be used if the adapter does
-             * not have a SEEPROM.
-             */
-            /*
-             * Check the target scratch area to see if someone set us
-             * up already.  We are previously set up if the scratch
-             * area contains something other than all zeroes and ones.
-             */
-            for (j = TARG_SCRATCH; j < 0x60; j++)
-            {
-              if (inb(p->base + j) != 0x00)      /* Check for all zeroes. */
-                break;
-            }
-            if (j == TARG_SCRATCH)
-            {
-              for (j = TARG_SCRATCH; j < 0x60; j++)
-              {
-                if (inb(p->base + 1) != 0xFF)    /* Check for all ones. */
-                  break;
-              }
-            }
-            if ((j != 0x60) && (p->scsi_id != 0))
-            {
-              p->flags &= ~USE_DEFAULTS;
-              if (aic7xxx_verbose)
-              {
-                printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
-              }
-            }
-            else
-            {
-              if (aic7xxx_verbose)
-              {
-                printk(KERN_INFO "aic7xxx: No BIOS found; using default "
-                       "settings.\n");
-              }
-              /*
-               * Assume only one connector and always turn on
-               * termination.
-               */
-              sxfrctl1 = STPWEN;
-              p->scsi_id = 7;
-            }
-            outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
-                 p->base + SCSICONF);
-            /* In case we are a wide card. */
-            outb(p->scsi_id, p->base + SCSICONF + 1);
-            if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
-            {
-              /*
-               * If there wasn't a BIOS or the board wasn't in this mode
-               * to begin with, turn off Ultra.
-               */
-              p->flags &= ~ULTRA_ENABLED;
-            }
+            panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
+                  error);
           }
 
-          /*
-           * Print some additional information about the adapter.
-           */
-          printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
-                 "IO Mem 0x%x, IRQ %d",
-                 (p->flags & USE_DEFAULTS) ? "dis" : "en",
-                 p->base, p->mbase, p->irq);
-          if ((class_revid & DEVREVID) < 3)
-          {
-            printk(", Revision %c", rev_id[class_revid & DEVREVID]);
-          }
-          printk("\n");
+          printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
 
           /*
            * I don't think we need to bother with allowing
@@ -6204,53 +4891,58 @@ aic7xxx_detect(Scsi_Host_Template *template)
            */
           aic7xxx_spurious_count = 1;
 
+          config.base = iobase;
+          config.mbase = mbase;
+          config.irq = irq;
+          config.parity = AIC_ENABLED;
+          config.low_term = AIC_UNKNOWN;
+          config.high_term = AIC_UNKNOWN;
           if (aic7xxx_extended)
-            p->flags |= EXTENDED_TRANSLATION;
-
-          /*
-           * Put our termination setting into sxfrctl1 now that the
-           * generic initialization is complete.
-           */
-          sxfrctl1 |= inb(p->base + SXFRCTL1);
-          outb(sxfrctl1, p->base + SXFRCTL1);
-
-          if (aic7xxx_register(template, p) == 0)
-          {
-            aic7xxx_free(p);
-          }
-          else
+            config.flags |= EXTENDED_TRANSLATION;
+#ifdef AIC7XXX_SHARE_SCBs
+          if (devconfig & RAMPSM)
+#else
+          if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
+              (config.type != AIC_7883))
+#endif
           {
-            found = found + 1;
-
-#ifdef AIC7XXX_USE_EXT_SCBRAM
             /*
-             * Set the shared SCB data once we've successfully probed a
-             * 398x adapter.
+             * External SRAM present.  The probe will walk the SCBs to see
+             * how much SRAM we have and set the number of SCBs accordingly.
+             * We have to turn off SCBRAMSEL to access the external SCB
+             * SRAM.
              *
-             * Note that we can only do this if the use of external
-             * SCB RAM is enabled.
+             * It seems that early versions of the aic7870 didn't use these
+             * bits, hence the hack for the 3940 above.  I would guess that
+             * recent 3940s using later aic7870 or aic7880 chips do actually
+             * set RAMPSM.
+             *
+             * The documentation isn't clear, but it sounds like the value
+             * written to devconfig must not have RAMPSM set.  The second
+             * sixteen bits of the register are R/O anyway, so it shouldn't
+             * affect RAMPSM either way.
              */
-            if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
-            {
-              if (shared_scb_data == NULL)
-              {
-                shared_scb_data = p->scb_data;
-              }
-            }
-#endif
+            printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
+                   "access.\n");
+            devconfig &= ~(RAMPSM | SCBRAMSEL);
+            pcibios_write_config_dword(pci_bus, pci_device_fn,
+                                       DEVCONFIG, devconfig);
           }
+          found += aic7xxx_register(template, &config);
 
-          index++;
           /*
            * Disable spurious interrupts.
            */
           aic7xxx_spurious_count = 0;
+
+          index++;
         }  /* Found an Adaptec PCI device. */
       }
     }
   }
 #endif CONFIG_PCI
 
+  template->name = aic7xxx_info(NULL);
   return (found);
 }
 
@@ -6266,45 +4958,45 @@ static void
 aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     struct aic7xxx_scb *scb)
 {
+  unsigned int addr; /* must be 32 bits */
   unsigned short mask;
-  struct aic7xxx_hwscb *hscb;
 
   mask = (0x01 << TARGET_INDEX(cmd));
-  hscb = scb->hscb;
-
   /*
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
-  if (p->discenable & mask)
-  {
-    hscb->control |= DISCENB;
 #ifdef AIC7XXX_TAGGED_QUEUEING
-    if (cmd->device->tagged_queue)
+  if (cmd->device->tagged_queue)
+  {
+    cmd->tag = scb->tag;
+    cmd->device->current_tag = scb->tag;
+    scb->control |= TAG_ENB;
+    p->device_status[TARGET_INDEX(cmd)].commands_sent++;
+    if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200)
     {
-      cmd->tag = hscb->tag;
-      p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
-      {
-        hscb->control |= MSG_SIMPLE_Q_TAG;
-      }
-      else
-      {
-        hscb->control |= MSG_ORDERED_Q_TAG;
-        p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
-      }
+      scb->control |= 0x02;
+      p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+    }
+#if 0
+    if (p->orderedtag & mask)
+    {
+      scb->control |= 0x02;
+      p->orderedtag = p->orderedtag & ~mask;
     }
-#endif  /* Tagged queueing */
+#endif
+  }
+#endif
+  if (p->discenable & mask)
+  {
+    scb->control |= DISCENB;
   }
-
   if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
   {
     p->wdtr_pending |= mask;
-    hscb->control |= MK_MESSAGE;
-    scb->flags |= SCB_MSGOUT_WDTR;
+    scb->control |= NEEDWDTR;
 #if 0
-    printk("scsi%d: Sending WDTR request to target %d.\n",
-           p->host_no, cmd->target);
+    printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
 #endif
   }
   else
@@ -6312,20 +5004,19 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
     {
       p->sdtr_pending |= mask;
-      hscb->control |= MK_MESSAGE;
-      scb->flags |= SCB_MSGOUT_SDTR;
+      scb->control |= NEEDSDTR;
 #if 0
-      printk("scsi%d: Sending SDTR request to target %d.\n",
-             p->host_no, cmd->target);
+      printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
 #endif
     }
   }
+
 #if 0
   printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
          "mask(0x%x).\n",
         cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
 #endif
-  hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+  scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
        ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
 
   /*
@@ -6339,8 +5030,9 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
    * XXX - this relies on the host data being stored in a
    *       little-endian format.
    */
-  hscb->SCSI_cmd_length = cmd->cmd_len;
-  hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
+  addr = VIRT_TO_BUS(cmd->cmnd);
+  scb->SCSI_cmd_length = cmd->cmd_len;
+  memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
 
   if (cmd->use_sg)
   {
@@ -6360,16 +5052,15 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
       scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
       scb->sg_list[i].length = (unsigned int) sg[i].length;
     }
-    hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
-    hscb->SG_segment_count = cmd->use_sg;
-    scb->sg_count = hscb->SG_segment_count;
-
-    /* Copy the first SG into the data pointer area. */
-    hscb->data_pointer = scb->sg_list[0].address;
-    hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
+    scb->SG_segment_count = cmd->use_sg;
+    addr = VIRT_TO_BUS(scb->sg_list);
+    memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
+    memcpy(scb->data_pointer, &(scb->sg_list[0].address),
+           sizeof(scb->data_pointer));
+    scb->data_count = scb->sg_list[0].length;
 #if 0
     printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
-           cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
+           cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
 #endif
   }
   else
@@ -6378,23 +5069,28 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
   printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
        (unsigned long) cmd->request_buffer, cmd->request_bufflen);
 #endif
-    if (cmd->request_bufflen)
+    if (cmd->request_bufflen == 0)
     {
-      hscb->SG_segment_count = 1;
-      scb->sg_count = 1;
-      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
-      scb->sg_list[0].length = cmd->request_bufflen;
-      hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
-      hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
-      hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
+      /*
+       * In case the higher level SCSI code ever tries to send a zero
+       * length command, ensure the SCB indicates no data.  The driver
+       * will interpret a zero length command as a Bus Device Reset.
+       */
+      scb->SG_segment_count = 0;
+      memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
+      memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
+      scb->data_count = 0;
     }
     else
     {
-      hscb->SG_segment_count = 0;
-      scb->sg_count = 0;
-      hscb->SG_list_pointer = 0;
-      hscb->data_pointer = 0;
-      hscb->data_count = SCB_LIST_NULL << 24;
+      scb->SG_segment_count = 1;
+      scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+      scb->sg_list[0].length = cmd->request_bufflen;
+      addr = VIRT_TO_BUS(&scb->sg_list[0]);
+      memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
+      scb->data_count = scb->sg_list[0].length;
+      addr = VIRT_TO_BUS(cmd->request_buffer);
+      memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
     }
   }
 }
@@ -6412,6 +5108,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
   long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+  u_char curscb, intstat;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   if (p->host != cmd->host)
@@ -6443,21 +5140,34 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
        cmd->lun & 0x07);
 #endif
 
-  if (p->device_status[TARGET_INDEX(cmd)].active_cmds
-      > cmd->device->queue_depth)
-  {
-    printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
-           p->host_no, cmd->target, cmd->channel);
-  }
+  /*
+   * This is a critical section, since we don't want the interrupt
+   * routine mucking with the host data or the card.  For this reason
+   * it is nice to know that this function can only be called in one
+   * of two ways from scsi.c  First, as part of a routine queue command,
+   * in which case, the irq for our card is disabled before this
+   * function is called.  This doesn't help us if there is more than
+   * one card using more than one IRQ in our system, therefore, we
+   * should disable all interrupts on these grounds alone.  Second,
+   * this can be called as part of the scsi_done routine, in which case
+   * we are in the aic7xxx_isr routine already and interrupts are
+   * disabled, therefore we should saveflags first, then disable the
+   * interrupts, do our work, then restore the CPU flags. If it weren't
+   * for the possibility of more than one card using more than one IRQ
+   * in our system, we wouldn't have to touch the interrupt flags at all.
+   */
+  save_flags(processor_flags);
+  cli();
+
   scb = aic7xxx_allocate_scb(p);
   if (scb == NULL)
   {
-    panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
+    panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
   }
   else
   {
     scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->hscb->tag;
+    aic7xxx_position(cmd) = scb->tag;
 #if 0
     debug_scb(scb);
 #endif;
@@ -6469,14 +5179,14 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
     aic7xxx_buildscb(p, cmd, scb);
 
 #if 0
-    if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
+    if (scb != (p->scb_array[scb->position]))
     {
       printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
              "address.\n");
     }
     printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
-          scb->hscb->tag, (unsigned int) scb->cmd,
-          scb->flags, (unsigned int) p->free_scb);
+          scb->position, (unsigned int) scb->cmd,
+          scb->state, (unsigned int) p->free_scb);
 #endif
 
     /*
@@ -6491,28 +5201,70 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
     cmd->host_scribble = NULL;
     memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
 
-    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+    if (scb->position != SCB_LIST_NULL)
+    {
+      /* We've got a valid slot, yeah! */
+      if (p->flags & IN_ISR)
+      {
+        scbq_insert_tail(&p->assigned_scbs, scb);
+        scb->state |= SCB_ASSIGNEDQ;
+      }
+      else
+      {
+        /*
+         * Pause the sequencer so we can play with its registers -
+         * wait for it to acknowledge the pause.
+         *
+         * XXX - should the interrupts be left on while doing this?
+         */
+        PAUSE_SEQUENCER(p);
+        intstat = inb(INTSTAT + p->base);
+
+        /*
+         * Save the SCB pointer and put our own pointer in - this
+         * selects one of the four banks of SCB registers. Load
+         * the SCB, then write its pointer into the queue in FIFO
+         * and restore the saved SCB pointer.
+         */
+        curscb = inb(SCBPTR + p->base);
+        outb(scb->position, SCBPTR + p->base);
+        aic7xxx_putscb(p, scb);
+        outb(curscb, SCBPTR + p->base);
+        outb(scb->position, QINFIFO + p->base);
+        scb->state |= SCB_ACTIVE;
 
-    save_flags(processor_flags);
-    cli();
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
+        /*
+         * Guard against unpausing the sequencer if there is an interrupt
+         * waiting to happen.
+         */
+        if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
+        {
+          UNPAUSE_SEQUENCER(p);
+        }
+      }
+    }
+    else
     {
-      aic7xxx_run_waiting_queues(p);
+      scb->state |= SCB_WAITINGQ;
+      scbq_insert_tail(&p->waiting_scbs, scb);
+      if (!(p->flags & IN_ISR))
+      {
+        aic7xxx_run_waiting_queues(p);
+      }
     }
 
-    restore_flags(processor_flags);
 #if 0
     printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
-           (long) cmd, (long) scb->cmd, scb->hscb->tag);
+           (long) cmd, (long) scb->cmd, scb->position);
 #endif;
+    restore_flags(processor_flags);
   }
   return (0);
 }
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_bus_device_reset
+ *   aic7xxx_abort_reset
  *
  * Description:
  *   Abort or reset the current SCSI command(s).  If the scb has not
@@ -6524,257 +5276,204 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 static int
 aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
-  struct aic7xxx_scb   *scb;
-  struct aic7xxx_hwscb *hscb;
+  struct aic7xxx_scb  *scb;
   unsigned char bus_state;
-  int result = -1;
+  int base, result = -1;
   char channel;
 
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  hscb = scb->hscb;
-
-  /*
-   * Ensure that the card doesn't do anything behind our back.
-   * Also make sure that we didn't just miss an interrupt that
-   * could affect this abort/reset.
-   */
-  pause_sequencer(p);
-  while (inb(p->base + INTSTAT) & INT_PEND);
-  {
-    aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
-    pause_sequencer(p);
-  } 
-  if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
-  {
-    result = SCSI_RESET_NOT_RUNNING;
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-    return(result);
-  }
-
-
-  printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
-         p->host_no, TC_OF_SCB(scb), scb->flags);
-  bus_state = inb(p->base + LASTPHASE);
+  scb = (p->scb_array[aic7xxx_position(cmd)]);
+  base = p->base;
 
-  switch (bus_state)
+  channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
+  if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
   {
-    case P_DATAOUT:
-      printk("Data-Out phase, ");
-      break;
-    case P_DATAIN:
-      printk("Data-In phase, ");
-      break;
-    case P_COMMAND:
-      printk("Command phase, ");
-      break;
-    case P_MESGOUT:
-      printk("Message-Out phase, ");
-      break;
-    case P_STATUS:
-      printk("Status phase, ");
-      break;
-    case P_MESGIN:
-      printk("Message-In phase, ");
-      break;
-    default:
-      /*
-       * We're not in a valid phase, so assume we're idle.
-       */
-      printk("while idle, LASTPHASE = 0x%x, ", bus_state);
-      break;
-  }
-  printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
-         inb(p->base + SCSISIGI),
-         inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
-         inb(p->base + SSTAT0), inb(p->base + SSTAT1));
 
-  channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
-  /*
-   * Determine our course of action.
-   */
-  if (scb->flags & SCB_ABORT)
-  {
-    /*
-     * Been down this road before; do a full bus reset.
-     */
-    scb->flags |= SCB_RECOVERY_SCB;
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-    result = -1;
-  }
-#if 0
-  else if (hscb->control & TAG_ENB)
+    if (scb->state & SCB_IN_PROGRESS)
     {
       /*
-       * We could be starving this command; try sending and ordered tag
-       * command to the target we come from.
+       * Ensure that the card doesn't do anything
+       * behind our back.
        */
-      scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
-      p->orderedtag = p->orderedtag | 0xFF;
-      result = SCSI_RESET_PENDING;
-      unpause_sequencer(p, /* unpause_always */ TRUE);
-      printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
-             p->host_no);
-    }
-#endif
-  else
-  {
-    unsigned char active_scb_index, saved_scbptr;
-    struct aic7xxx_scb *active_scb;
+      PAUSE_SEQUENCER(p);
 
-    /*
-     * Send an Abort Message:
-     * The target that is holding up the bus may not be the same as
-     * the one that triggered this timeout (different commands have
-     * different timeout lengths).  Our strategy here is to queue an
-     * abort message to the timed out target if it is disconnected.
-     * Otherwise, if we have an active target we stuff the message buffer
-     * with an abort message and assert ATN in the hopes that the target
-     * will let go of the bus and go to the mesgout phase.  If this
-     * fails, we'll get another timeout a few seconds later which will
-     * attempt a bus reset.
-     */
-    saved_scbptr = inb(p->base + SCBPTR);
-    active_scb_index = inb(p->base + SCB_TAG);
-    active_scb = p->scb_data->scb_array[active_scb_index];
+      printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
+      bus_state = inb(LASTPHASE + p->base);
 
-    if (bus_state != P_BUSFREE)
-    {
-      if (active_scb_index >= p->scb_data->numscbs)
-      {
-        /*
-         * Perform a bus reset.
-         *
-         * XXX - We want to queue an abort for the timedout SCB
-         *       instead.
-         */
-        result = -1;
-        printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
-               "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
-      }
-      else
+      switch (bus_state)
       {
-        /* Send the abort message to the active SCB. */
-        outb(1, p->base + MSG_LEN);
-        if (active_scb->hscb->control & TAG_ENB)
-        {
-          outb(MSG_ABORT_TAG, p->base + MSG_OUT);
-        }
-        else
-        {
-          outb(MSG_ABORT, p->base + MSG_OUT);
-        }
-        outb(bus_state | ATNO, p->base + SCSISIGO);
-        printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
-               p->host_no);
-        active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
-        if (active_scb != scb)
-        {
+       case P_DATAOUT:
+          printk("Data-Out phase, ");
+          break;
+       case P_DATAIN:
+          printk("Data-In phase, ");
+          break;
+       case P_COMMAND:
+          printk("Command phase, ");
+          break;
+       case P_MESGOUT:
+          printk("Message-Out phase, ");
+          break;
+       case P_STATUS:
+          printk("Status phase, ");
+          break;
+       case P_MESGIN:
+          printk("Message-In phase, ");
+          break;
+       default:
+          printk("while idle, LASTPHASE = 0x%x, ", bus_state);
           /*
-           * XXX - We would like to increment the timeout on scb, but
-           *       access to that routine is denied because it is hidden
-           *       in scsi.c.  If we were able to do this, it would give
-           *       scb a new lease on life.
+           * We're not in a valid phase, so assume we're idle.
            */
-          result = SCSI_RESET_PENDING;
-          aic7xxx_error(active_scb->cmd) = DID_RESET;
-        }
-        else
-        {
-          aic7xxx_error(scb->cmd) = DID_RESET;
-          result = SCSI_RESET_PENDING;
-        }
-        unpause_sequencer(p, /* unpause_always */ TRUE);
+          bus_state = 0;
+          break;
       }
-    }
-    else
-    {
-      unsigned char hscb_index, linked_next;
-      int disconnected;
+      printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
 
-      disconnected = FALSE;
-      hscb_index = aic7xxx_find_scb(p, scb);
-      if (hscb_index == SCB_LIST_NULL)
-      {
-        disconnected = TRUE;
-        linked_next = (scb->hscb->data_count >> 24) & 0xFF;
-      }
-      else
-      {
-        outb(hscb_index, p->base + SCBPTR);
-        if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
-        {
-          disconnected = TRUE;
-        }
-        linked_next = inb(p->base + SCB_LINKED_NEXT);
-      }
-      if (disconnected)
+      /*
+       * First, determine if we want to do a bus reset or simply a bus device
+       * reset.  If this is the first time that a transaction has timed out
+       * and the SCB is not paged out, just schedule a bus device reset.
+       * Otherwise, we reset the bus and abort all pending I/Os on that bus.
+       */
+      if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
       {
-        /*
-         * Simply set the ABORT_SCB control bit and preserve the
-         * linked next pointer.
-         */
-        scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
-        scb->hscb->data_count &= ~0xFF000000;
-        scb->hscb->data_count |= linked_next << 24;
-        if ((p->flags & PAGE_ENABLED) == 0)
-        {
-          scb->hscb->control &= ~DISCONNECTED;
-        }
-        scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-        if (hscb_index != SCB_LIST_NULL)
-        {
-          unsigned char scb_control;
-
-          scb_control = inb(p->base + SCB_CONTROL);
-          outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
-        }
-        /*
-         * Actually requeue this SCB in case we can select the
-         * device before it reconnects.  If the transaction we
-         * want to abort is not tagged, unbusy it first so that
-         * we don't get held back from sending the command.
-         */
-        if ((scb->hscb->control & TAG_ENB) == 0)
-        {
-          unsigned char target;
-          int lun;
-
-          target = scb->cmd->target;
-          lun = scb->cmd->lun;
-          aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
-              0, /* requeue */ TRUE);
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
-               p->host_no, TC_OF_SCB(scb));
-        scbq_insert_head(&p->waiting_scbs, scb);
-        scb->flags |= SCB_WAITINGQ;
-        outb(saved_scbptr, p->base + SCBPTR);
-        if ((p->flags & IN_ISR) == 0)
-        {
-          /*
-           * Processing the waiting queue may unpause us.
-           */
-          aic7xxx_run_waiting_queues(p);
+#if 0
+       if (scb->control & TAG_ENB)
+       {
           /*
-           * If we are using AAP, aic7xxx_run_waiting_queues() will not
-           * unpause us, so ensure we are unpaused.
+           * We could be starving this command; try sending and ordered tag
+           * command to the target we come from.
            */
-          unpause_sequencer(p, /*unpause_always*/ FALSE);
-        }
-        else
-        {
-          unpause_sequencer(p, /*unpause_always*/ TRUE);
-        }
-        result = SCSI_RESET_PENDING;
-      }
-      else
-      {
-        scb->flags |= SCB_RECOVERY_SCB;
-        unpause_sequencer(p, /* unpause_always */ TRUE);
-        result = -1;
+          scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG;
+          p->orderedtag = p->orderedtag | 0xFF;
+          result = SCSI_RESET_PENDING;
+          UNPAUSE_SEQUENCER(p);
+          printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n");
+       }
+#endif
+       unsigned char active_scb, control;
+       struct aic7xxx_scb *active_scbp;
+
+       /*
+        * Send a Bus Device Reset Message:
+        * The target we select to send the message to may be entirely
+        * different than the target pointed to by the scb that timed
+        * out.  If the command is in the QINFIFO or the waiting for
+        * selection list, its not tying up the bus and isn't responsible
+        * for the delay so we pick off the active command which should
+        * be the SCB selected by SCBPTR.  If its disconnected or active,
+        * we device reset the target scbp points to.  Although it may
+        * be that this target is not responsible for the delay, it may
+        * may also be that we're timing out on a command that just takes
+        * too much time, so we try the bus device reset there first.
+        */
+       active_scb = inb(SCBPTR + base);
+       active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
+       control = inb(SCB_CONTROL + base);
+
+       /*
+        * Test to see if scbp is disconnected
+        */
+       outb(scb->position, SCBPTR + base);
+       if (inb(SCB_CONTROL + base) & DISCONNECTED)
+       {
+#ifdef AIC7XXX_DEBUG_ABORT
+          printk("aic7xxx: (abort_scb) scb %d is disconnected; "
+                 "bus device reset message queued.\n", scb->position);
+#endif
+          if (p->flags & PAGE_ENABLED)
+          {
+            /* Pull this SCB out of the disconnected list. */
+            u_char prev = inb(SCB_PREV + base);
+            u_char next = inb(SCB_NEXT + base);
+            if (prev == SCB_LIST_NULL)
+            {
+              /* Head of list */
+              outb(next, DISCONNECTED_SCBH + base);
+            }
+            else
+            {
+              outb(prev, SCBPTR + base);
+              outb(next, SCB_NEXT + base);
+              if (next != SCB_LIST_NULL)
+              {
+               outb(next, SCBPTR + base);
+               outb(prev, SCB_PREV + base);
+              }
+              outb(scb->position, SCBPTR + base);
+            }
+          }
+         scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
+          scb->control = scb->control & DISCENB;
+          scb->SCSI_cmd_length = 0;
+         scb->SG_segment_count = 0;
+         memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
+         memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
+         scb->data_count = 0;
+         aic7xxx_putscb(p, scb);
+         aic7xxx_add_waiting_scb(base, scb);
+         outb(active_scb, SCBPTR + base);
+          result = SCSI_RESET_PENDING;
+         UNPAUSE_SEQUENCER(p);
+       }
+       else
+       {
+         /*
+          * Is the active SCB really active?
+          */
+         if ((active_scbp->state & SCB_ACTIVE) && bus_state)
+         {
+            /*
+             * Load the message buffer and assert attention.
+             */
+            active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
+            outb(1, MSG_LEN + base);
+            outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
+            outb(bus_state | ATNO, SCSISIGO + base);
+#ifdef AIC7XXX_DEBUG_ABORT
+            printk("aic7xxx: (abort_scb) asserted ATN - "
+                   "bus device reset in message buffer.\n");
+#endif
+            if (active_scbp != scb)
+            {
+              /*
+               * XXX - We would like to increment the timeout on scb, but
+               *       access to that routine is denied because it is hidden
+               *       in scsi.c.  If we were able to do this, it would give
+               *       scb a new lease on life.
+               */
+              ;
+            }
+            aic7xxx_error(scb->cmd) = DID_RESET;
+            /*
+             * Restore the active SCB and unpause the sequencer.
+             */
+            outb(active_scb, SCBPTR + base);
+            if (active_scbp != scb)
+            {
+              /*
+               * The mid-level SCSI code requested us to reset a command
+               * different from the one that we actually reset.  Return
+               * a "not running" indication and hope that the SCSI code
+               * will Do the Right Thing (tm).
+               */
+              result = SCSI_RESET_NOT_RUNNING;
+            }
+            else
+            {
+              result = SCSI_RESET_PENDING;
+            }
+            UNPAUSE_SEQUENCER(p);
+         }
+       }
       }
     }
   }
+  /* Make sure the sequencer is unpaused upon return. */
+  if (result == -1)
+  {
+    UNPAUSE_SEQUENCER(p);
+  }
   return (result);
 }
 
@@ -6792,48 +5491,16 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
   int    base, result;
-  unsigned long processor_flags;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  scb = (p->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
 
-  save_flags(processor_flags);
-  cli();
-
 #ifdef AIC7XXX_DEBUG_ABORT
-  if (scb != NULL)
-  {
-    printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
-  }
-  else
-  {
-    printk("aic7xxx: Abort called with no SCB for cmd.\n");
-  }
+  printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
+         scb->position, TCL_OF_SCB(scb));
 #endif
 
-  if (p->flags & IN_TIMEOUT)
-  {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
-    {
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_PENDING);
-    }
-    else
-    {
-      /*
-       * This is the second time we've tried to abort the recovery
-       * SCB.  We want the mid-level SCSI code to call the reset
-       * function to reset the SCSI bus.
-       */
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_NOT_RUNNING);
-    }
-  }
   if (cmd->serial_number != cmd->serial_number_at_timeout)
   {
     result = SCSI_ABORT_NOT_RUNNING;
@@ -6842,34 +5509,14 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
   {
     result = SCSI_ABORT_NOT_RUNNING;
   }
-  else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
+  else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
   {
     result = SCSI_ABORT_NOT_RUNNING;
   }
   else
   {
-    /*
-     * XXX - Check use of IN_TIMEOUT to see if we're Doing the
-     *       Right Thing with it.
-     */
-    p->flags |= IN_TIMEOUT;
-    result = aic7xxx_bus_device_reset(p, scb->cmd);
-    switch (result)
-    {
-      case SCSI_RESET_NOT_RUNNING:
-        p->flags &= ~IN_TIMEOUT;
-        result = SCSI_ABORT_NOT_RUNNING;
-        break;
-      case SCSI_RESET_PENDING:
-        result = SCSI_ABORT_PENDING;
-        break;
-      default:
-        p->flags &= ~IN_TIMEOUT;
-        result = SCSI_ABORT_SNOOZE;
-        break;
-     }
+    result = SCSI_ABORT_SNOOZE;
   }
-  restore_flags(processor_flags);
   return (result);
 }
 
@@ -6889,27 +5536,18 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
-  int    base, found, tindex, min_target, max_target;
-  int    result = -1;
+  int    base, found, tindex, min_target, max_target, result = -1;
   char   channel = 'A';
   unsigned long processor_flags;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  scb = (p->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
   channel = cmd->channel ? 'B': 'A';
   tindex = (cmd->channel << 4) | cmd->target;
 
-#ifdef 0   /* AIC7XXX_DEBUG_ABORT */
-  if (scb != NULL)
-  {
-    printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
-  }
-  else
-  {
-    printk("aic7xxx: Reset called with no SCB for cmd.\n");
-  }
+#ifdef AIC7XXX_DEBUG_ABORT
+  printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
 #endif
 
   /* 
@@ -6924,45 +5562,34 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
   if (scb->cmd != cmd)
     scb = NULL;
 
-  if (p->flags & IN_TIMEOUT)
+  if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET)) 
+      && (scb != NULL))
   {
     /*
-     * We've already started a recovery operation.
+     * Attempt a bus device reset if commands have completed successfully
+     * since the last bus device reset, or it has been less than 100ms
+     * since the last reset.
      */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
-    {
-      restore_flags(processor_flags);
-      return (SCSI_RESET_PENDING);
-    }
-  }
-  else
-  {
-    if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
-        && (scb != NULL))
+    if ((p->flags & DEVICE_SUCCESS) ||
+        ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
     {
-      /*
-       * Attempt a bus device reset if commands have completed successfully
-       * since the last bus device reset, or it has been less than 100ms
-       * since the last reset.
-       */
-      if ((p->flags & DEVICE_SUCCESS) ||
-          ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+      if (cmd->serial_number != cmd->serial_number_at_timeout)
       {
-       if (cmd->serial_number != cmd->serial_number_at_timeout)
-       {
-          result = SCSI_RESET_NOT_RUNNING;
-       }
-       else if (scb == NULL)
+        result = SCSI_RESET_NOT_RUNNING;
+      }
+      else
+      {
+        if (scb == NULL)
         {
           result = SCSI_RESET_NOT_RUNNING;
         }
         else if (flags & SCSI_RESET_ASYNCHRONOUS)
         {
-          if (scb->flags & SCB_ABORTED)
+          if (scb->state & SCB_ABORTED)
           {
             result = SCSI_RESET_PENDING;
           }
-          else if (!(scb->flags & SCB_ACTIVE))
+          else if (!(scb->state & SCB_IN_PROGRESS))
           {
             result = SCSI_RESET_NOT_RUNNING;
           }
@@ -6973,23 +5600,20 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
           if ((flags & SCSI_RESET_SYNCHRONOUS) &&
               (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
           {
-            scb->flags |= SCB_ABORTED;
+            scb->state |= SCB_ABORTED;
             result = SCSI_RESET_PENDING;
           }
           else
           {
-            p->flags |= IN_TIMEOUT;
             result = aic7xxx_bus_device_reset(p, cmd);
             if (result == 0)
-            {
-              p->flags &= ~IN_TIMEOUT;
               result = SCSI_RESET_PENDING;
-            }
           }
-       }
+        }
       }
     }
   }
+
   if (result == -1)
   {
     /*
@@ -7002,11 +5626,11 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       {
        result = SCSI_RESET_NOT_RUNNING;
       }
-      else if (!(scb->flags & SCB_ACTIVE))
+      else if (!(scb->state & SCB_IN_PROGRESS))
       {
        result = SCSI_RESET_NOT_RUNNING;
       }
-      else if ((scb->flags & SCB_ABORTED) &&
+      else if ((scb->state & SCB_ABORTED) &&
                (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
       {
        result = SCSI_RESET_PENDING;
@@ -7018,9 +5642,8 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       /*
        * The reset channel function assumes that the sequencer is paused.
        */
-      pause_sequencer(p);
+      PAUSE_SEQUENCER(p);
       found = aic7xxx_reset_channel(p, channel, TRUE);
-      p->flags = p->flags & ~IN_TIMEOUT;
 
       /*
        * If this is a synchronous reset and there is no SCB for this
@@ -7066,10 +5689,8 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
       }
 
       result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-      p->flags &= ~IN_TIMEOUT;
     }
   }
-  aic7xxx_run_waiting_queues(p);
   restore_flags(processor_flags);
   return (result);
 }
index 4f1e76c33199fea383f118b42588f4eb1a36e29e..d4de8fd83487769931ace77b9a354325c28b3ec9 100644 (file)
  * 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.3 1997/06/12 03:37:26 deang Exp $
+ * $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  "$Revision: 3.3 $"
+#define AIC7XXX_H_VERSION  "$Revision: 3.2 $"
 
 /*
  * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
@@ -40,7 +40,7 @@
        aic7xxx_info,                                           \
        NULL,                                                   \
        aic7xxx_queue,                                          \
-       NULL,                                                   \
+       aic7xxx_abort,                                          \
        aic7xxx_reset,                                          \
        NULL,                                                   \
        aic7xxx_biosparam,                                      \
@@ -57,6 +57,7 @@ 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_abort(Scsi_Cmnd *);
 extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
diff --git a/drivers/scsi/aic7xxx.seq b/drivers/scsi/aic7xxx.seq
new file mode 100644 (file)
index 0000000..98d4b95
--- /dev/null
@@ -0,0 +1,1127 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ *Modifications/enhancements:
+ *  Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
+ *
+ * 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.
+ *
+ * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other 
+ * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
+ *
+ * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
+ *
+ *-M*************************************************************************/
+
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 4.0 1996/10/13 08:23:42 deang Exp $"
+
+#ifdef linux
+#include "aic7xxx_reg.h"
+#else
+#if defined(__NetBSD__)
+#include "../../../../dev/ic/aic7xxxreg.h"
+#elif defined(__FreeBSD__)
+#include "../../dev/aic7xxx/aic7xxx_reg.h"
+#endif
+#endif
+
+/*
+ * We can't just use ACCUM in the sequencer code because it
+ * must be treated specially by the assembler, and it currently
+ * looks for the symbol 'A'.  This is the only register defined in
+ * the assembler's symbol space.
+ */
+A = ACCUM
+
+/* After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB offsets, 
+ * SCB_LIST_NULL is 0xff which is out of range.  The kernel driver must
+ * add an entry to this list every time a request sense occurs.  The sequencer
+ * will automatically consume the entries.
+ */
+
+/*
+ * We assume that the kernel driver may reset us at any time, even in the
+ * middle of a DMA, so clear DFCNTRL too.
+ */
+reset:
+       clr     DFCNTRL
+       clr     SCSISIGO                /* De-assert BSY */
+/*
+ * We jump to start after every bus free.
+ */
+start:
+       and     FLAGS,0x0f              /* clear target specific flags */
+       mvi     SCSISEQ,ENRSELI         /* Always allow reselection */
+       clr     SCSIRATE                /*
+                                        * We don't know the target we will
+                                        * connect to, so default to narrow
+                                        * transfers to avoid parity problems.
+                                        */
+poll_for_work:
+       /*
+        * Are we a twin channel device?
+        * For fairness, we check the other bus first,
+        * since we just finished a transaction on the
+        * current channel.
+        */
+       test    FLAGS,TWIN_BUS  jz start2
+       xor     SBLKCTL,SELBUSB                 /* Toggle to the other bus */
+       test    SSTAT0,SELDI    jnz reselect
+       xor     SBLKCTL,SELBUSB                 /* Toggle to the original bus */
+start2:
+       test    SSTAT0,SELDI    jnz reselect
+       cmp     WAITING_SCBH,SCB_LIST_NULL jne start_waiting
+       mov     A, QCNTMASK
+       test    QINCNT,A        jz poll_for_work
+
+/*
+ * We have at least one queued SCB now and we don't have any 
+ * SCBs in the list of SCBs awaiting selection.  Set the SCB
+ * pointer from the FIFO so we see the right bank of SCB 
+ * registers.
+ */
+       mov     SCBPTR,QINFIFO
+
+/*
+ * See if there is not already an active SCB for this target.  This code
+ * locks out on a per target basis instead of target/lun.  Although this
+ * is not ideal for devices that have multiple luns active at the same
+ * time, it is faster than looping through all SCB's looking for active
+ * commands.  It may be beneficial to make findscb a more general procedure
+ * to see if the added cost of the search is negligible.  This code also 
+ * assumes that the kernel driver will clear the active flags on board 
+ * initialization, board reset, and a target SELTO.  Tagged commands
+ * don't set the active bits since you can queue more than one command
+ * at a time.  We do, however, look to see if there are any non-tagged
+ * I/Os in progress, and requeue the command if there are.  Tagged and
+ * non-tagged commands cannot be mixed to a single target.
+ */
+
+test_busy:
+       mov     FUNCTION1,SCB_TCL
+       mov     A,FUNCTION1
+       test    SCB_TCL,0x88    jz test_a       /* Id < 8 && A channel */
+
+       test    ACTIVE_B,A      jnz requeue
+       test    SCB_CONTROL,TAG_ENB     jnz start_scb
+       /* Mark the current target as busy */
+       or      ACTIVE_B,A
+       jmp     start_scb
+
+/* Place the currently active SCB back on the queue for later processing */
+requeue:
+       mov     QINFIFO, SCBPTR
+       jmp     poll_for_work
+
+/*
+ * Pull the first entry off of the waiting for selection list
+ * We don't have to "test_busy" because only transactions that
+ * have passed that test can be in the waiting_scb list.
+ */
+start_waiting:
+       mov     SCBPTR,WAITING_SCBH
+       jmp     start_scb2
+
+test_a:
+       test    ACTIVE_A,A jnz requeue
+       test    SCB_CONTROL,TAG_ENB jnz start_scb
+       /* Mark the current target as busy */
+       or      ACTIVE_A,A
+
+start_scb:
+       mov     SCB_NEXT,WAITING_SCBH
+       mov     WAITING_SCBH, SCBPTR
+start_scb2:
+       and     SINDEX,0xf7,SBLKCTL     /* Clear the channel select bit */
+       and     A,0x08,SCB_TCL          /* Get new channel bit */
+       or      SINDEX,A
+       mov     SBLKCTL,SINDEX          /* select channel */
+       mov     SCB_TCL call initialize_scsiid
+
+/*
+ * Enable selection phase as an initiator, and do automatic ATN
+ * after the selection.  We do this now so that we can overlap the
+ * rest of our work to set up this target with the arbitration and
+ * selection bus phases.
+ */
+start_selection:
+       mvi     SCSISEQ,0x58            /* ENSELO|ENAUTOATNO|ENRSELI */
+
+/*
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.  Prepare
+ * the message to send.
+ *
+ * Messages are stored in scratch RAM starting with a length byte
+ * followed by the message itself.
+ */
+       test    SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
+
+/*
+ * The kernel has sent us an SCB with no command attached.  This implies
+ * that the kernel wants to send a message of some sort to this target,
+ * so we interrupt the driver, allow it to fill the message buffer, and
+ * then go back into the arbitration loop
+ */
+       mvi     INTSTAT,AWAITING_MSG
+       jmp     wait_for_selection
+
+mk_identify:
+       and     A,DISCENB,SCB_CONTROL   /* mask off disconnect privledge */
+
+       and     MSG0,0x7,SCB_TCL        /* lun */
+       or      MSG0,A                  /* or in disconnect privledge */
+       or      MSG0,MSG_IDENTIFY
+       mvi     MSG_LEN, 1
+
+       test    SCB_CONTROL,0xb0 jz  !message   /* WDTR, SDTR or TAG?? */
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
+ */
+
+mk_tag:
+       mvi     DINDEX, MSG1
+       test    SCB_CONTROL,TAG_ENB jz mk_tag_done
+       and     DINDIR,0x23,SCB_CONTROL
+       mov     DINDIR,SCB_TAG
+
+       add     MSG_LEN,COMP_MSG0,DINDEX        /* update message length */
+
+mk_tag_done:
+
+       test    SCB_CONTROL,0x90 jz !message    /* NEEDWDTR|NEEDSDTR */
+       mov     DINDEX  call mk_dtr     /* build DTR message if needed */
+
+!message:
+wait_for_selection:
+       test    SSTAT0,SELDO    jnz select 
+       test    SSTAT0,SELDI    jz wait_for_selection
+
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target
+ * yet.
+ */
+reselect:
+       clr     MSG_LEN         /* Don't have anything in the mesg buffer */
+       mov     SELID           call initialize_scsiid
+       or      FLAGS,RESELECTED
+       jmp     select2
+
+/*
+ * After the selection, remove this SCB from the "waiting for selection"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH.  Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select:
+       mov     WAITING_SCBH,SCB_NEXT
+       or      FLAGS,SELECTED
+select2:
+/*
+ * Set CLRCHN here before the target has entered a data transfer mode -
+ * with synchronous SCSI, if you do it later, you blow away some
+ * data in the SCSI FIFO that the target has already sent to you.
+ */
+       or      SXFRCTL0,CLRCHN
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ */
+       call    ndx_dtr
+       mov     SCSIRATE,SINDIR
+
+/*
+ * Initialize Ultra mode setting.
+ */
+       mov     FUNCTION1,SCSIID
+       mov     A,FUNCTION1
+       and     SINDEX,0xdf,SXFRCTL0            /* default to Ultra disabled */
+       test    SCSIID, 0x80     jnz ultra_b    /* Target ID > 7 */
+       test    SBLKCTL, SELBUSB jnz ultra_b    /* Second channel device */
+       test    ULTRA_ENB,A      jz  set_sxfrctl0
+       or      SINDEX, ULTRAEN  jmp set_sxfrctl0
+ultra_b:
+       test    ULTRA_ENB_B,A    jz  set_sxfrctl0
+       or      SINDEX, ULTRAEN
+
+set_sxfrctl0:
+       mov     SXFRCTL0,SINDEX
+
+       mvi     SCSISEQ,ENAUTOATNP              /*
+                                                * ATN on parity errors
+                                                * for "in" phases
+                                                */
+       mvi     CLRSINT1,CLRBUSFREE
+       mvi     CLRSINT0,0x60                   /* CLRSELDI|CLRSELDO */
+/*
+ * Main loop for information transfer phases.  If BSY is false, then
+ * we have a bus free condition, expected or not.  Otherwise, wait
+ * for the target to assert REQ before checking MSG, C/D and I/O
+ * for the bus phase.
+ *
+ */
+ITloop:
+       test    SSTAT1,BUSFREE  jnz p_busfree
+       test    SSTAT1,REQINIT  jz ITloop
+
+       and     A,PHASE_MASK,SCSISIGI
+       mov     LASTPHASE,A
+       mov     SCSISIGO,A
+
+       cmp     ALLZEROS,A      je p_dataout
+       cmp     A,P_DATAIN      je p_datain
+       cmp     A,P_COMMAND     je p_command
+       cmp     A,P_MESGOUT     je p_mesgout
+       cmp     A,P_STATUS      je p_status
+       cmp     A,P_MESGIN      je p_mesgin
+
+       mvi     INTSTAT,BAD_PHASE       /* unknown phase - signal driver */
+       jmp     ITloop                  /* Try reading the bus again. */
+
+p_dataout:
+       mvi     DMAPARAMS,0x7d                  /*
+                                                * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+                                                * DIRECTION|FIFORESET
+                                                */
+       jmp     data_phase_init
+
+/*
+ * 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.
+ */
+data_phase_reinit:
+       mov     STCNT0,SCB_RESID_DCNT0
+       mov     STCNT1,SCB_RESID_DCNT1
+       mov     STCNT2,SCB_RESID_DCNT2
+       jmp     data_phase_loop
+
+p_datain:
+       mvi     DMAPARAMS,0x79          /*
+                                        * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+                                        * !DIRECTION|FIFORESET
+                                        */
+data_phase_init:
+       call    assert
+
+       test    FLAGS, DPHASE   jnz data_phase_reinit
+       call    sg_scb2ram
+       or      FLAGS, DPHASE           /* We have seen a data phase */
+
+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
+       mvi     STCNT0,0xff
+       mvi     STCNT1,0xff
+       mvi     STCNT2,0xff
+
+data_phase_inbounds:
+/* If we are the last SG block, don't set wideodd. */
+       cmp     SG_COUNT,0x01 jne data_phase_wideodd
+       and     DMAPARAMS, 0xbf         /* Turn off WIDEODD */
+data_phase_wideodd:
+       mov     DMAPARAMS  call dma
+
+/* Go tell the host about any overruns */
+       test    SXFRCTL1,BITBUCKET jnz data_phase_overrun
+
+/* Exit if we had an underrun */
+       test    SSTAT0,SDONE    jz data_phase_finish /* underrun STCNT != 0 */
+
+/*
+ * Advance the scatter-gather pointers if needed 
+ */
+sg_advance:
+       dec     SG_COUNT        /* one less segment to go */
+
+       test    SG_COUNT, 0xff  jz data_phase_finish /* Are we done? */
+
+       clr     A                       /* add sizeof(struct scatter) */
+       add     SG_NEXT0,SG_SIZEOF,SG_NEXT0
+       adc     SG_NEXT1,A,SG_NEXT1
+
+/*
+ * 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 a little-endian host data storage.
+ */
+sg_load:
+       clr     HCNT2
+       clr     HCNT1
+       mvi     HCNT0,SG_SIZEOF
+
+       mov     HADDR0,SG_NEXT0
+       mov     HADDR1,SG_NEXT1
+       mov     HADDR2,SG_NEXT2
+       mov     HADDR3,SG_NEXT3
+
+       or      DFCNTRL,0xd                     /* HDMAEN|DIRECTION|FIFORESET */
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+dma_finish:
+       test    DFSTATUS,HDONE  jz dma_finish
+       /* Turn off DMA preserving WIDEODD */
+       and     DFCNTRL,WIDEODD
+dma_finish2:
+       test    DFCNTRL,HDMAENACK jnz dma_finish2
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count.  In
+ * both FreeBSD and Linux, the scatter list entry is 8 bytes.
+ * 
+ * struct ahc_dma_seg {
+ *       physaddr addr;                  four bytes, little-endian order
+ *       long    len;                    four bytes, little endian order
+ * };
+ */
+
+       mov     HADDR0,DFDAT
+       mov     HADDR1,DFDAT
+       mov     HADDR2,DFDAT
+       mov     HADDR3,DFDAT
+       mov     HCNT0,DFDAT
+       mov     HCNT1,DFDAT
+       mov     HCNT2,DFDAT
+
+/* Load STCNT as well.  It is a mirror of HCNT */
+       mov     STCNT0,HCNT0
+       mov     STCNT1,HCNT1
+       mov     STCNT2,HCNT2
+        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.
+ */
+       mov     SCB_RESID_DCNT0,STCNT0
+       mov     SCB_RESID_DCNT1,STCNT1
+       mov     SCB_RESID_DCNT2,STCNT2
+       mov     SCB_RESID_SGCNT, SG_COUNT
+       jmp     ITloop
+
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+       and     SXFRCTL1,0x7f           /* ~BITBUCKET */
+       mvi     INTSTAT,DATA_OVERRUN
+       jmp     ITloop
+
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+       call    assert
+
+/*
+ * Load HADDR and HCNT.
+ */
+       mov     HADDR0, SCB_CMDPTR0
+       mov     HADDR1, SCB_CMDPTR1
+       mov     HADDR2, SCB_CMDPTR2
+       mov     HADDR3, SCB_CMDPTR3
+       mov     HCNT0, SCB_CMDLEN
+       clr     HCNT1
+       clr     HCNT2
+
+       mov     STCNT0, HCNT0
+       mov     STCNT1, HCNT1
+       mov     STCNT2, HCNT2
+
+       mvi     0x3d            call dma        # SCSIEN|SDMAEN|HDMAEN|
+                                               #   DIRECTION|FIFORESET
+       jmp     ITloop
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+       mvi     SCB_TARGET_STATUS       call inb_first
+       jmp     mesgin_done
+
+/*
+ * Message out phase.  If there is not an active message, but the target
+ * took us into this phase anyway, build a no-op message and send it.
+ */
+p_mesgout:
+       test    MSG_LEN, 0xff   jnz  p_mesgout_start
+       mvi     MSG_NOP         call mk_mesg    /* build NOP message */
+
+p_mesgout_start:
+/*
+ * Set up automatic PIO transfer from MSG0.  Bit 3 in
+ * SXFRCTL0 (SPIOEN) is already on.
+ */
+       mvi     SINDEX,MSG0
+       mov     DINDEX,MSG_LEN
+
+/*
+ * When target asks for a byte, drop ATN if it's the last one in
+ * the message.  Otherwise, keep going until the message is exhausted.
+ *
+ * Keep an eye out for a phase change, in case the target issues
+ * a MESSAGE REJECT.
+ */
+p_mesgout_loop:
+       test    SSTAT1,PHASEMIS jnz p_mesgout_phasemis
+       test    SSTAT0,SPIORDY  jz p_mesgout_loop
+       test    SSTAT1,PHASEMIS jnz p_mesgout_phasemis
+       cmp     DINDEX,1        jne p_mesgout_outb      /* last byte? */
+       mvi     CLRSINT1,CLRATNO                        /* drop ATN */
+p_mesgout_outb:
+       dec     DINDEX
+       or      CLRSINT0, CLRSPIORDY
+       mov     SCSIDATL,SINDIR
+       
+p_mesgout4:
+       test    DINDEX,0xff     jnz p_mesgout_loop
+
+/*
+ * If the next bus phase after ATN drops is a message out, it means
+ * that the target is requesting that the last message(s) be resent.
+ */
+p_mesgout_snoop:
+       test    SSTAT1,BUSFREE  jnz p_mesgout_done
+       test    SSTAT1,REQINIT  jz p_mesgout_snoop
+
+       test    SSTAT1,PHASEMIS jnz p_mesgout_done
+
+       or      SCSISIGO,ATNO                   /* turn on ATNO */
+
+       jmp     ITloop
+
+p_mesgout_phasemis:
+       mvi     CLRSINT1,CLRATNO        /* Be sure to turn ATNO off */
+p_mesgout_done:
+       clr     MSG_LEN                 /* no active msg */
+       jmp     ITloop
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+       mvi     A               call inb_first  /* read the 1st message byte */
+       mov     REJBYTE,A                       /* save it for the driver */
+
+       test    A,MSG_IDENTIFY          jnz mesgin_identify
+       cmp     A,MSG_DISCONNECT        je mesgin_disconnect
+       cmp     A,MSG_SDPTRS            je mesgin_sdptrs
+       cmp     ALLZEROS,A              je mesgin_complete
+       cmp     A,MSG_RDPTRS            je mesgin_rdptrs
+       cmp     A,MSG_EXTENDED          je mesgin_extended
+       cmp     A,MSG_REJECT            je mesgin_reject
+
+rej_mesgin:
+/*
+ * We have no idea what this message in is, and there's no way
+ * to pass it up to the kernel, so we issue a message reject and
+ * hope for the best.  Since we're now using manual PIO mode to
+ * read in the message, there should no longer be a race condition
+ * present when we assert ATN.  In any case, rejection should be a
+ * rare occurrence - signal the driver when it happens.
+ */
+       or      SCSISIGO,ATNO                   /* turn on ATNO */
+       mvi     INTSTAT,SEND_REJECT             /* let driver know */
+
+       mvi     MSG_REJECT      call mk_mesg
+
+mesgin_done:
+       call    inb_last                        /*ack & turn auto PIO back on*/
+       jmp     ITloop
+
+
+mesgin_complete:
+/*
+ * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
+ * and trigger a completion interrupt.  Check status for non zero return
+ * and interrupt driver if needed.  This allows the driver to interpret
+ * errors only when they occur instead of always uploading the scb.  If
+ * the status is SCSI_CHECK, the driver will download a new scb requesting
+ * sense to replace the old one, modify the "waiting for selection" SCB list
+ * and set RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE the
+ * sequencer imediately jumps to main loop where it will run down the waiting
+ * SCB list and process the sense request.  If the kernel driver does not
+ * wish to request sense, it need only clear RETURN_1, and the command is
+ * allowed to complete.  We don't bother to post to the QOUTFIFO in the
+ * error case since it would require extra work in the kernel driver to
+ * ensure that the entry was removed before the command complete code tried
+ * processing it.
+ *
+ * First check for residuals
+ */
+       test    SCB_RESID_SGCNT,0xff    jz check_status
+/*
+ * If we have a residual count, interrupt and tell the host.  Other
+ * alternatives are to pause the sequencer on all command completes (yuck),
+ * dma the resid directly to the host (slick, we may have space to do it now)
+ * or have the sequencer pause itself when it encounters a non-zero resid 
+ * (unnecessary pause just to flag the command -yuck-, but takes one instruction
+ * and since it shouldn't happen that often is good enough for our purposes).  
+ */
+resid:
+       mvi     INTSTAT,RESIDUAL
+
+check_status:
+       test    SCB_TARGET_STATUS,0xff  jz status_ok    /* Good Status? */
+       mvi     INTSTAT,BAD_STATUS                      /* let driver know */
+       cmp     RETURN_1, SEND_SENSE    jne status_ok
+       jmp     mesgin_done
+
+status_ok:
+/* First, mark this target as free. */
+       test    SCB_CONTROL,TAG_ENB jnz test_immediate  /*
+                                                        * Tagged commands
+                                                        * don't busy the
+                                                        * target.
+                                                        */
+       mov     FUNCTION1,SCB_TCL
+       mov     A,FUNCTION1
+       test    SCB_TCL,0x88 jz clear_a
+       xor     ACTIVE_B,A
+       jmp     test_immediate
+
+clear_a:
+       xor     ACTIVE_A,A
+
+test_immediate:
+       test    SCB_CMDLEN,0xff jnz complete  /* Immediate message complete */
+/*
+ * Pause the sequencer until the driver gets around to handling the command
+ * complete.  This is so that any action that might require careful timing
+ * with the completion of this command can occur.
+ */
+       mvi     INTSTAT,IMMEDDONE
+       jmp     start
+complete:
+       mov     QOUTFIFO,SCB_TAG
+       mvi     INTSTAT,CMDCMPLT
+       jmp     mesgin_done
+
+
+/*
+ * Is it an extended message?  We only support the synchronous and wide data
+ * transfer request messages, which will probably be in response to
+ * WDTR or SDTR message outs from us.  If it's not SDTR or WDTR, reject it -
+ * apparently this can be done after any message in byte, according
+ * to the SCSI-2 spec.
+ */
+mesgin_extended:
+       mvi     ARG_1           call inb_next   /* extended message length */
+       mvi     REJBYTE_EXT     call inb_next   /* extended message code */
+
+       cmp     REJBYTE_EXT,MSG_SDTR    je p_mesginSDTR
+       cmp     REJBYTE_EXT,MSG_WDTR    je p_mesginWDTR
+       jmp     rej_mesgin
+
+p_mesginWDTR:
+       cmp     ARG_1,2         jne rej_mesgin  /* extended mesg length=2 */
+       mvi     ARG_1           call inb_next   /* Width of bus */
+       mvi     INTSTAT,WDTR_MSG                /* let driver know */
+       test    RETURN_1,0xff jz mesgin_done    /* Do we need to send WDTR? */
+       cmp     RETURN_1,SEND_REJ je rej_mesgin /*
+                                                * Bus width was too large 
+                                                * Reject it.
+                                                */
+
+/* We didn't initiate the wide negotiation, so we must respond to the request */
+       and     RETURN_1,0x7f                   /* Clear the SEND_WDTR Flag */
+       mvi     DINDEX,MSG0
+       mvi     MSG0    call mk_wdtr            /* build WDTR message */
+       or      SCSISIGO,ATNO                   /* turn on ATNO */
+       jmp     mesgin_done
+
+p_mesginSDTR:
+       cmp     ARG_1,3         jne rej_mesgin  /* extended mesg length=3 */
+       mvi     ARG_1           call inb_next   /* xfer period */
+       mvi     A               call inb_next   /* REQ/ACK offset */
+       mvi     INTSTAT,SDTR_MSG                /* call driver to convert */
+
+       test    RETURN_1,0xff   jz mesgin_done  /* Do we need to mk_sdtr/rej */
+       cmp     RETURN_1,SEND_REJ je rej_mesgin /*
+                                                * Requested SDTR too small
+                                                * Reject it.
+                                                */
+       clr     ARG_1                           /* Use the scratch ram rate */
+       mvi     DINDEX, MSG0
+       mvi     MSG0     call mk_sdtr
+       or      SCSISIGO,ATNO                   /* turn on ATNO */
+       jmp     mesgin_done
+
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
+mesgin_disconnect:
+       or      SCB_CONTROL,DISCONNECTED
+       test    FLAGS, PAGESCBS jz mesgin_done
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+       mvi     SCB_PREV, SCB_LIST_NULL
+       mvi     SEQCTL,0x50                     /* PAUSEDIS|FASTMODE */
+       mov     SCB_NEXT, DISCONNECTED_SCBH
+       mov     DISCONNECTED_SCBH, SCBPTR
+       cmp     SCB_NEXT,SCB_LIST_NULL je linkdone
+       mov     SCBPTR,SCB_NEXT
+       mov     SCB_PREV,DISCONNECTED_SCBH
+       mov     SCBPTR,DISCONNECTED_SCBH
+linkdone:
+       mvi     SEQCTL,0x10                     /* !PAUSEDIS|FASTMODE */
+       jmp     mesgin_done
+
+/*
+ * Save data pointers message?  Copy working values into the SCB,
+ * usually in preparation for a disconnect.
+ */
+mesgin_sdptrs:
+       call    sg_ram2scb
+       jmp     mesgin_done
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
+mesgin_rdptrs:
+       and     FLAGS,0xef                      /*
+                                                * !DPHASE we'll reload them
+                                                * the next time through
+                                                */
+       jmp     mesgin_done
+
+/*
+ * Identify message?  For a reconnecting target, this tells us the lun
+ * that the reconnection is for - find the correct SCB and switch to it,
+ * clearing the "disconnected" bit so we don't "find" it by accident later.
+ */
+mesgin_identify:
+       test    A,0x78  jnz rej_mesgin  /*!DiscPriv|!LUNTAR|!Reserved*/
+
+       and     A,0x07                  /* lun in lower three bits */
+       or      SAVED_TCL,A,SELID          
+       and     SAVED_TCL,0xf7
+       and     A,SELBUSB,SBLKCTL       /* B Channel?? */
+       or      SAVED_TCL,A
+       call    inb_last                /* ACK */
+
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to switch to find the proper
+ * SCB.  With SCB paging, this requires using findSCB for both tagged
+ * and non-tagged transactions since the SCB may exist in any slot.
+ * If we're not using SCB paging, we can use the tag as the direct
+ * index to the SCB.
+ */
+       mvi     ARG_1,SCB_LIST_NULL     /* Default to no-tag */
+snoop_tag_loop:
+       test    SSTAT1,BUSFREE  jnz use_findSCB
+       test    SSTAT1,REQINIT  jz snoop_tag_loop
+       test    SSTAT1,PHASEMIS jnz use_findSCB
+       mvi     A               call inb_first
+       cmp     A,MSG_SIMPLE_TAG jne use_findSCB
+get_tag:
+       mvi     ARG_1   call inb_next   /* tag value */
+/*
+ * See if the tag is in range.  The tag is < SCBCOUNT if we add
+ * the complement of SCBCOUNT to the incoming tag and there is
+ * no carry.
+ */
+       mov     A,COMP_SCBCOUNT 
+       add     SINDEX,A,ARG_1
+       jc      abort_tag
+
+/*
+ * Ensure that the SCB the tag points to is for a SCB transaction
+ * to the reconnecting target.
+ */
+       test    FLAGS, PAGESCBS jz index_by_tag
+       call    inb_last                        /* Ack Tag */
+use_findSCB:
+       mov     ALLZEROS        call findSCB      /* Have to search */
+setup_SCB:
+       and     SCB_CONTROL,0xfb          /* clear disconnect bit in SCB */
+       or      FLAGS,IDENTIFY_SEEN       /* make note of IDENTIFY */
+       jmp     ITloop
+index_by_tag:
+       mov     SCBPTR,ARG_1
+       mov     A,SAVED_TCL
+       cmp     SCB_TCL,A               jne abort_tag
+       test    SCB_CONTROL,TAG_ENB     jz  abort_tag
+       call    inb_last                        /* Ack Successful tag */
+       jmp     setup_SCB
+
+abort_tag:
+       or      SCSISIGO,ATNO                   /* turn on ATNO */
+       mvi     INTSTAT,ABORT_TAG               /* let driver know */
+       mvi     MSG_ABORT_TAG   call mk_mesg    /* ABORT TAG message */
+       jmp     mesgin_done
+
+/*
+ * Message reject?  Let the kernel driver handle this.  If we have an 
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from 
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+       mvi     INTSTAT, REJECT_MSG
+       jmp     mesgin_done
+
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * Bus free phase.  It might be useful to interrupt the device
+ * driver if we aren't expecting this.  For now, make sure that
+ * ATN isn't being asserted and look for a new command.
+ */
+p_busfree:
+       mvi     CLRSINT1,CLRATNO
+       clr     LASTPHASE
+
+/*
+ * if this is an immediate command, perform a pseudo command complete to
+ * notify the driver.
+ */
+       test    SCB_CMDLEN,0xff jz status_ok
+       jmp     start
+
+/*
+ * Locking the driver out, build a one-byte message passed in SINDEX
+ * if there is no active message already.  SINDEX is returned intact.
+ */
+mk_mesg:
+       mvi     SEQCTL,0x50                     /* PAUSEDIS|FASTMODE */
+       test    MSG_LEN,0xff    jz mk_mesg1     /* Should always succeed */
+       
+       /*
+        * Hmmm.  For some reason the mesg buffer is in use.
+        * Tell the driver.  It should look at SINDEX to find
+        * out what we wanted to use the buffer for and resolve
+        * the conflict.
+        */
+       mvi     SEQCTL,0x10                     /* !PAUSEDIS|FASTMODE */
+       mvi     INTSTAT,MSG_BUFFER_BUSY
+
+mk_mesg1:
+       mvi     MSG_LEN,1               /* length = 1 */
+       mov     MSG0,SINDEX             /* 1-byte message */
+       mvi     SEQCTL,0x10     ret     /* !PAUSEDIS|FASTMODE */
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
+
+inb_next:
+       or      CLRSINT0, CLRSPIORDY
+       mov     NONE,SCSIDATL                   /*dummy read from latch to ACK*/
+inb_next_wait:
+       test    SSTAT1,PHASEMIS jnz mesgin_phasemis
+       test    SSTAT0,SPIORDY  jz inb_next_wait /* wait for next byte */
+inb_first:
+       mov     DINDEX,SINDEX
+       test    SSTAT1,PHASEMIS jnz mesgin_phasemis
+       mov     DINDIR,SCSIBUSL ret             /*read byte directly from bus*/
+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
+ */
+       mvi     INTSTAT, MSGIN_PHASEMIS
+       jmp     ITloop
+
+/*
+ * DMA data transfer.  HADDR and HCNT must be loaded first, and
+ * SINDEX should contain the value to load DFCNTRL with - 0x3d for
+ * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+ * during initialization.
+ */
+dma:
+       mov     DFCNTRL,SINDEX
+dma1:
+       test    SSTAT0,DMADONE  jnz dma3
+       test    SSTAT1,PHASEMIS jz dma1         /* ie. underrun */
+
+/*
+ * We will be "done" DMAing when the transfer count goes to zero, or
+ * the target changes the phase (in light of this, it makes sense that
+ * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+ * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+ * magically on STCNT=0 or a phase change, so just wait for FIFO empty
+ * status.
+ */
+dma3:
+       test    SINDEX,DIRECTION        jnz dma5
+dma4:
+       test    DFSTATUS,FIFOEMP        jz dma4
+
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are 
+ * actually off first lest we get an ILLSADDR.
+ */
+dma5:
+       /* disable DMA, but maintain WIDEODD */
+       and     DFCNTRL,WIDEODD
+dma6:
+       test    DFCNTRL,0x38    jnz dma6  /* SCSIENACK|SDMAENACK|HDMAENACK */
+
+       ret
+
+/*
+ * Common SCSI initialization for selection and reselection.  Expects
+ * the target SCSI ID to be in the upper four bits of SINDEX, and A's
+ * contents are stomped on return.
+ */
+initialize_scsiid:
+       and     SINDEX,0xf0             /* Get target ID */
+       and     A,0x0f,SCSIID
+       or      SINDEX,A
+       mov     SCSIID,SINDEX ret
+
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * message.
+ */
+assert:
+       test    FLAGS,RESELECTED        jz return       /* reselected? */
+       test    FLAGS,IDENTIFY_SEEN     jnz return      /* seen IDENTIFY? */
+
+       mvi     INTSTAT,NO_IDENT        ret     /* no - cause a kernel panic */
+
+/*
+ * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
+ * value in ARG_1.  If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
+ * SCB.  Have the kernel print a warning message if it can't be found, and
+ * generate an ABORT/ABORT_TAG message to the target.  SINDEX should be
+ * cleared on call.
+ */
+findSCB:
+       mov     A,SAVED_TCL
+       mov     SCBPTR,SINDEX                   /* switch to next SCB */
+       mvi     SEQCTL,0x50                     /* PAUSEDIS|FASTMODE */
+       cmp     SCB_TCL,A       jne findSCB1 /* target ID/channel/lun match? */
+       test    SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
+       test    SCB_CONTROL,TAG_ENB jnz findTaggedSCB
+       cmp     ARG_1,SCB_LIST_NULL je foundSCB
+       jmp     findSCB1
+findTaggedSCB:
+       mov     A, ARG_1                        /* Tag passed in ARG_1 */
+       cmp     SCB_TAG,A       jne findSCB1    /* Found it? */
+foundSCB:
+       test    FLAGS,PAGESCBS  jz foundSCB_ret
+/* Remove this SCB from the disconnection list */
+       cmp     SCB_NEXT,SCB_LIST_NULL je unlink_prev
+       mov     SAVED_LINKPTR, SCB_PREV
+       mov     SCBPTR, SCB_NEXT
+       mov     SCB_PREV, SAVED_LINKPTR
+       mov     SCBPTR, SINDEX
+unlink_prev:
+       cmp     SCB_PREV,SCB_LIST_NULL  je rHead/* At the head of the list */
+       mov     SAVED_LINKPTR, SCB_NEXT
+       mov     SCBPTR, SCB_PREV
+       mov     SCB_NEXT, SAVED_LINKPTR
+       mov     SCBPTR, SINDEX
+       mvi     SEQCTL,0x10     ret             /* !PAUSEDIS|FASTMODE */
+rHead:
+       mov     DISCONNECTED_SCBH,SCB_NEXT
+foundSCB_ret:
+       mvi     SEQCTL,0x10     ret             /* !PAUSEDIS|FASTMODE */
+
+findSCB1:
+       mvi     SEQCTL,0x10                     /* !PAUSEDIS|FASTMODE */
+       inc     SINDEX
+       mov     A,SCBCOUNT
+       cmp     SINDEX,A        jne findSCB
+
+       mvi     INTSTAT,NO_MATCH                /* not found - signal kernel */
+       cmp     RETURN_1,SCB_PAGEDIN je return
+       or      SCSISIGO,ATNO                   /* assert ATNO */
+       cmp     ARG_1,SCB_LIST_NULL jne find_abort_tag
+       mvi     MSG_ABORT       call mk_mesg
+       jmp     ITloop
+find_abort_tag:
+       mvi     MSG_ABORT_TAG   call mk_mesg
+       jmp     ITloop
+
+/*
+ * Make a working copy of the scatter-gather parameters from the SCB.
+ */
+sg_scb2ram:
+       mov     HADDR0, SCB_DATAPTR0
+       mov     HADDR1, SCB_DATAPTR1
+       mov     HADDR2, SCB_DATAPTR2
+       mov     HADDR3, SCB_DATAPTR3
+       mov     HCNT0, SCB_DATACNT0
+       mov     HCNT1, SCB_DATACNT1
+       mov     HCNT2, SCB_DATACNT2
+
+       mov     STCNT0, HCNT0
+       mov     STCNT1, HCNT1
+       mov     STCNT2, HCNT2
+
+       mov     SG_COUNT,SCB_SGCOUNT
+
+       mov     SG_NEXT0, SCB_SGPTR0
+       mov     SG_NEXT1, SCB_SGPTR1
+       mov     SG_NEXT2, SCB_SGPTR2
+       mov     SG_NEXT3, SCB_SGPTR3 ret
+
+/*
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
+sg_ram2scb:
+       test    FLAGS, DPHASE   jz return
+       mov     SCB_SGCOUNT,SG_COUNT
+
+       mov     SCB_SGPTR0,SG_NEXT0
+       mov     SCB_SGPTR1,SG_NEXT1
+       mov     SCB_SGPTR2,SG_NEXT2
+       mov     SCB_SGPTR3,SG_NEXT3
+       
+       mov     SCB_DATAPTR0,SHADDR0
+       mov     SCB_DATAPTR1,SHADDR1
+       mov     SCB_DATAPTR2,SHADDR2
+       mov     SCB_DATAPTR3,SHADDR3
+
+/*
+ * Use the residual number since STCNT is corrupted by any message transfer
+ */
+       mov     SCB_DATACNT0,SCB_RESID_DCNT0
+       mov     SCB_DATACNT1,SCB_RESID_DCNT1
+       mov     SCB_DATACNT2,SCB_RESID_DCNT2 ret
+
+/*
+ * Add the array base TARG_SCRATCH to the target offset (the target address
+ * is in SCSIID), and return the result in SINDEX.  The accumulator
+ * contains the 3->8 decoding of the target ID on return.
+ */
+ndx_dtr:
+       shr     A,SCSIID,4
+       test    SBLKCTL,SELBUSB jz ndx_dtr_2
+       or      A,0x08          /* Channel B entries add 8 */
+ndx_dtr_2:
+       add     SINDEX,TARG_SCRATCH,A ret
+
+/*
+ * If we need to negotiate transfer parameters, build the WDTR or SDTR message
+ * starting at the address passed in SINDEX.  DINDEX is modified on return.
+ * The SCSI-II spec requires that Wide negotiation occur first and you can
+ * only negotiate one or the other at a time otherwise in the event of a message
+ * reject, you wouldn't be able to tell which message was the culprit.
+ */
+mk_dtr:
+       test    SCB_CONTROL,NEEDWDTR jnz  mk_wdtr_16bit
+       mvi     ARG_1, MAXOFFSET        /* Force an offset of 15 or 8 if WIDE */
+
+mk_sdtr:
+       mvi     DINDIR,1                /* extended message */
+       mvi     DINDIR,3                /* extended message length = 3 */
+       mvi     DINDIR,1                /* SDTR code */
+       call    sdtr_to_rate
+       mov     DINDIR,RETURN_1         /* REQ/ACK transfer period */
+       cmp     ARG_1, MAXOFFSET je mk_sdtr_max_offset
+       and     DINDIR,0x0f,SINDIR      /* Sync Offset */
+
+mk_sdtr_done:
+       add     MSG_LEN,COMP_MSG0,DINDEX ret    /* update message length */
+
+mk_sdtr_max_offset:
+/*
+ * We're initiating sync negotiation, so request the max offset we can (15 or 8)
+ */
+       /* Talking to a WIDE device? */
+       test    SCSIRATE, WIDEXFER      jnz wmax_offset 
+       mvi     DINDIR, MAX_OFFSET_8BIT
+       jmp     mk_sdtr_done
+
+wmax_offset:
+       mvi     DINDIR, MAX_OFFSET_16BIT
+       jmp     mk_sdtr_done
+
+mk_wdtr_16bit:
+       mvi     ARG_1,BUS_16_BIT
+mk_wdtr:
+       mvi     DINDIR,1                /* extended message */
+       mvi     DINDIR,2                /* extended message length = 2 */
+       mvi     DINDIR,3                /* WDTR code */
+       mov     DINDIR,ARG_1            /* bus width */
+
+       add     MSG_LEN,COMP_MSG0,DINDEX ret    /* update message length */
+       
+sdtr_to_rate:
+       call    ndx_dtr                 /* index scratch space for target */
+       shr     A,SINDIR,0x4
+       dec     SINDEX                  /* Preserve SINDEX */
+       and     A,0x7
+       clr     RETURN_1
+sdtr_to_rate_loop:
+       test    A,0x0f  jz sdtr_to_rate_done
+       add     RETURN_1,0x19
+       dec     A       
+       jmp     sdtr_to_rate_loop
+sdtr_to_rate_done:
+       shr     RETURN_1,0x2
+       add     RETURN_1,0x19
+       test    SXFRCTL0,ULTRAEN jz return
+       shr     RETURN_1,0x1
+return:
+       ret
diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
deleted file mode 100644 (file)
index 8c0ebaf..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-.SUFFIXES: .c .y .o
-
-PROG=  aic7xxx_asm
-
-CSRCS= aic7xxx_asm.c symbol.c
-GENSRCS=       gram.c scan.c
-GENHDRS=       y.tab.h token.h
-OBJS=  gram.o scan.o symbol.o aic7xxx_asm.o
-
-SRCS=  ${GENSRCS} ${CSRCS}
-CLEANFILES=    ${GENSRCS} ${GENHDRS} y.output ${OBJS}
-LIBS   =       -L/usr/local/lib -ldb
-NOMAN= noman
-
-LEX    =       lex
-LFLAGS =       -t
-YACC   =       yacc
-YFLAGS =       -d
-
-${PROG}: $(OBJS)
-       ${CC} ${CFLAGS} -o ${PROG} ${OBJS} ${LIBS} 
-
-
-
-y.tab.c: gram.y
-       ${YACC} ${YFLAGS} ${.IMPSRC}
-       mv y.tab.c gram.c
-
-gram.o: gram.c
-       ${CC} ${CFLAGS} -c gram.c
-
-
-.y.o:
-       ${YACC} ${YFLAGS} ${.IMPSRC}
-       ${CC} ${CFLAGS} -c y.tab.c
-       rm -f y.tab.c
-       cp y.tab.o $@
-
-.y.c:
-       ${YACC} ${YFLAGS} gram.y 
-       mv y.tab.c gram.c 
-
-.l.c:
-       ${LEX} ${LFLAGS} scan.l > scan.c
-       mv lex.yy.c $@
-
-.l.o:
-       ${LEX} ${LFLAGS} scan.l > scan.c
-       ${CC} ${CFLAGS} -c scan.c
-#      rm -f lex.yy.c
-#      mv lex.yy.o $@
-
-clean_most:
-       rm -f ${CLEANFILES}
-
-clean: clean_most
-       rm -f ${PROG}
-#
-# This is how FreeBSD builds the assembler:
-#
-# bash$ make
-# Warning: Object directory not changed from original /home/deischen/Linux/aic7xxx/Mar24/fbsd
-# yacc -d gram.y
-# mv y.tab.c gram.c
-# cc -O2 -m486 -pipe   -c gram.c
-# lex -t  scan.l > scan.c
-# cc -O2 -m486 -pipe   -c scan.c
-# cc -O2 -m486 -pipe   -c aic7xxx_asm.c
-# cc -O2 -m486 -pipe   -c symbol.c
-# cc -O2 -m486 -pipe    -o aic7xxx_asm gram.o scan.o aic7xxx_asm.o symbol.o  -ll
-# bash$ cc -O2 -m486 -pipe    -o aic7xxx_asm gram.o scan.o aic7xxx_asm.o symbol.o
-# bash$ aic7xxx_asm
-# aic7xxx_asm: No input file specifiled
-# usage: aic7xxx_asm      [-nostdinc] [-I-] [-I directory] [-o output_file]
-#                         [-r register_output_file] [-l program_list_file]
-#                         [-O option_name[|options_name2]] input_file
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
deleted file mode 100644 (file)
index c0cc71c..0000000
+++ /dev/null
@@ -1,1113 +0,0 @@
-/*
- * Aic7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996, 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     $Id: aic7xxx.reg,v 1.3 1997/04/24 16:52:16 gibbs Exp $
- */
-
-/*
- * This file is processed by the aic7xxx_asm utility for use in assembling
- * firmware for the aic7xxx family of SCSI host adapters as well as to generate
- * a C header file for use in the kernel portion of the Aic7xxx driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
-
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-register SCSISEQ {
-       address                 0x000
-       access_mode RW
-       bit     TEMODE          0x80
-       bit     ENSELO          0x40
-       bit     ENSELI          0x20
-       bit     ENRSELI         0x10
-       bit     ENAUTOATNO      0x08
-       bit     ENAUTOATNI      0x04
-       bit     ENAUTOATNP      0x02
-       bit     SCSIRSTO        0x01
-}
-
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-register SXFRCTL0 {
-       address                 0x001
-       access_mode RW
-       bit     DFON            0x80
-       bit     DFPEXP          0x40
-       bit     FAST20          0x20
-       bit     CLRSTCNT        0x10
-       bit     SPIOEN          0x08
-       bit     SCAMEN          0x04
-       bit     CLRCHN          0x02
-}
-
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-register SXFRCTL1 {
-       address                 0x002
-       access_mode RW
-       bit     BITBUCKET       0x80
-       bit     SWRAPEN         0x40
-       bit     ENSPCHK         0x20
-       mask    STIMESEL        0x18
-       bit     ENSTIMER        0x04
-       bit     ACTNEGEN        0x02
-       bit     STPWEN          0x01    /* Powered Termination */
-}
-
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-register SCSISIGI {
-       address                 0x003
-       access_mode RO
-       bit     CDI             0x80
-       bit     IOI             0x40
-       bit     MSGI            0x20
-       bit     ATNI            0x10
-       bit     SELI            0x08
-       bit     BSYI            0x04
-       bit     REQI            0x02
-       bit     ACKI            0x01
-/*
- * Possible phases in SCSISIGI
- */
-       mask    PHASE_MASK      CDI|IOI|MSGI
-       mask    P_DATAOUT       0x00
-       mask    P_DATAIN        IOI
-       mask    P_COMMAND       CDI
-       mask    P_MESGOUT       CDI|MSGI
-       mask    P_STATUS        CDI|IOI
-       mask    P_MESGIN        CDI|IOI|MSGI
-}
-
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus.  Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-register SCSISIGO {
-       address                 0x003
-       access_mode WO
-       bit     CDO             0x80
-       bit     IOO             0x40
-       bit     MSGO            0x20
-       bit     ATNO            0x10
-       bit     SELO            0x08
-       bit     BSYO            0x04
-       bit     REQO            0x02
-       bit     ACKO            0x01
-/*
- * Possible phases to write into SCSISIG0
- */
-       mask    PHASE_MASK      CDI|IOI|MSGI
-       mask    P_DATAOUT       0x00
-       mask    P_DATAIN        IOI
-       mask    P_COMMAND       CDI
-       mask    P_MESGOUT       CDI|MSGI
-       mask    P_STATUS        CDI|IOI
-       mask    P_MESGIN        CDI|IOI|MSGI
-}
-
-/* 
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
- * greater than 0 enables synchronous transfers.
- */
-register SCSIRATE {
-       address                 0x004
-       access_mode RW
-       bit     WIDEXFER        0x80            /* Wide transfer control */
-       mask    SXFR            0x70            /* Sync transfer rate */
-       mask    SOFS            0x0f            /* Sync offset */
-}
-
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-register SCSIID        {
-       address                 0x005
-       access_mode RW
-       mask    TID             0xf0            /* Target ID mask */
-       mask    OID             0x0f            /* Our ID mask */
-}
-
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode.  SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronouse data phase transfer.
- */
-register SCSIDATL {
-       address                 0x006
-       access_mode RW
-}
-
-register SCSIDATH {
-       address                 0x007
-       access_mode RW
-}
-
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transferred
- * across the SCSI bus.  The counter is decremented only once
- * the data has been safely transferred.  SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */ 
-register STCNT {
-       address                 0x008
-       size    3
-       access_mode RW
-}
-
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-register CLRSINT0 {
-       address                 0x00b
-       access_mode WO
-       bit     CLRSELDO        0x40
-       bit     CLRSELDI        0x20
-       bit     CLRSELINGO      0x10
-       bit     CLRSWRAP        0x08
-       bit     CLRSPIORDY      0x02
-}
-
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-register SSTAT0        {
-       address                 0x00b
-       access_mode RO
-       bit     TARGET          0x80            /* Board acting as target */
-       bit     SELDO           0x40            /* Selection Done */
-       bit     SELDI           0x20            /* Board has been selected */
-       bit     SELINGO         0x10            /* Selection In Progress */
-       bit     SWRAP           0x08            /* 24bit counter wrap */
-       bit     SDONE           0x04            /* STCNT = 0x000000 */
-       bit     SPIORDY         0x02            /* SCSI PIO Ready */
-       bit     DMADONE         0x01            /* DMA transfer completed */
-}
-
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-register CLRSINT1 {
-       address                 0x00c
-       access_mode WO
-       bit     CLRSELTIMEO     0x80
-       bit     CLRATNO         0x40
-       bit     CLRSCSIRSTI     0x20
-       bit     CLRBUSFREE      0x08
-       bit     CLRSCSIPERR     0x04
-       bit     CLRPHASECHG     0x02
-       bit     CLRREQINIT      0x01
-}
-
-/*
- * SCSI Status 1 (p. 3-24)
- */
-register SSTAT1        {
-       address                 0x00c
-       access_mode RO
-       bit     SELTO           0x80
-       bit     ATNTARG         0x40
-       bit     SCSIRSTI        0x20
-       bit     PHASEMIS        0x10
-       bit     BUSFREE         0x08
-       bit     SCSIPERR        0x04
-       bit     PHASECHG        0x02
-       bit     REQINIT         0x01
-}
-
-/*
- * SCSI Status 2 (pp. 3-25,26)
- */
-register SSTAT2 {
-       address                 0x00d
-       access_mode RO
-       bit     OVERRUN         0x80
-       mask    SFCNT           0x1f
-}
-
-/*
- * SCSI Status 3 (p. 3-26)
- */
-register SSTAT3 {
-       address                 0x00e
-       access_mode RO
-       mask    SCSICNT         0xf0
-       mask    OFFCNT          0x0f
-}
-
-/*
- * SCSI Test Control (p. 3-27)
- */
-register SCSITEST {
-       address                 0x00f
-       access_mode RW
-       bit     RQAKCNT         0x04
-       bit     CNTRTEST        0x02
-       bit     CMODE           0x01
-}
-
-/*
- * SCSI Interrupt Mode 1 (p. 3-28)
- * Setting any bit will enable the corresponding function
- * in SIMODE0 to interrupt via the IRQ pin.
- */
-register SIMODE0 {
-       address                 0x010
-       access_mode RW
-       bit     ENSELDO         0x40
-       bit     ENSELDI         0x20
-       bit     ENSELINGO       0x10
-       bit     ENSWRAP         0x08
-       bit     ENSDONE         0x04
-       bit     ENSPIORDY       0x02
-       bit     ENDMADONE       0x01
-}
-
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-register SIMODE1 {
-       address                 0x011
-       access_mode RW
-       bit     ENSELTIMO       0x80
-       bit     ENATNTARG       0x40
-       bit     ENSCSIRST       0x20
-       bit     ENPHASEMIS      0x10
-       bit     ENBUSFREE       0x08
-       bit     ENSCSIPERR      0x04
-       bit     ENPHASECHG      0x02
-       bit     ENREQINIT       0x01
-}
-
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-register SCSIBUSL {
-       address                 0x012
-       access_mode RO
-}
-
-register SCSIBUSH {
-       address                 0x013
-       access_mode RO
-}
-
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transferred on the SCSI bus.  They are counted up in the same
- * manner as STCNT is counted down.  SHADDR should always be used
- * to determine the address of the last byte transferred since HADDR
- * can be skewed by write ahead.
- */
-register SHADDR {
-       address                 0x014
-       size    4
-       access_mode RO
-}
-
-/*
- * Selection Timeout Timer (p. 3-30)
- */
-register SELTIMER {
-       address                 0x018
-       access_mode RW
-       bit     STAGE6          0x20
-       bit     STAGE5          0x10
-       bit     STAGE4          0x08
-       bit     STAGE3          0x04
-       bit     STAGE2          0x02
-       bit     STAGE1          0x01
-}
-
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-register SELID {
-       address                 0x019
-       access_mode RW
-       mask    SELID_MASK      0xf0
-       bit     ONEBIT          0x08
-}
-
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection.  In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-register SBLKCTL {
-       address                 0x01f
-       access_mode RW
-       bit     DIAGLEDEN       0x80    /* Aic78X0 only */
-       bit     DIAGLEDON       0x40    /* Aic78X0 only */
-       bit     AUTOFLUSHDIS    0x20
-       bit     SELBUSB         0x08
-       bit     SELWIDE         0x02
-}
-
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-register SEQCTL {
-       address                 0x060
-       access_mode RW
-       bit     PERRORDIS       0x80
-       bit     PAUSEDIS        0x40
-       bit     FAILDIS         0x20
-       bit     FASTMODE        0x10
-       bit     BRKADRINTEN     0x08
-       bit     STEP            0x04
-       bit     SEQRESET        0x02
-       bit     LOADRAM         0x01
-}
-
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
- * four bytes in sucessesion.  The SEQADDRs will increment after the most
- * significant byte is written
- */
-register SEQRAM {
-       address                 0x061
-       access_mode RW
-}
-
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-register SEQADDR0 {
-       address                 0x062
-       access_mode RW
-}
-
-register SEQADDR1 {
-       address                 0x063
-       access_mode RW
-       mask    SEQADDR1_MASK   0x01
-}
-
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-register ACCUM {
-       address                 0x064
-       access_mode RW
-       accumulator
-}
-
-register SINDEX        {
-       address                 0x065
-       access_mode RW
-       sindex
-}
-
-register DINDEX {
-       address                 0x066
-       access_mode RW
-}
-
-register ALLONES {
-       address                 0x069
-       access_mode RO
-       allones
-}
-
-register ALLZEROS {
-       address                 0x06a
-       access_mode RO
-       allzeros
-}
-
-register NONE {
-       address                 0x06a
-       access_mode WO
-       none
-}
-
-register FLAGS {
-       address                 0x06b
-       access_mode RO
-       bit     ZERO            0x02
-       bit     CARRY           0x01
-}
-
-register SINDIR        {
-       address                 0x06c
-       access_mode RO
-}
-
-register DINDIR         {
-       address                 0x06d
-       access_mode WO
-}
-
-register FUNCTION1 {
-       address                 0x06e
-       access_mode RW
-}
-
-register STACK {
-       address                 0x06f
-       access_mode RO
-}
-
-/*
- * Board Control (p. 3-43)
- */
-register BCTL {
-       address                 0x084
-       access_mode RW
-       bit     ACE             0x08
-       bit     ENABLE          0x01
-}
-
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-register DSCOMMAND {
-       address                 0x084
-       access_mode RW
-       bit     CACHETHEN       0x80    /* Cache Threshold enable */
-       bit     DPARCKEN        0x40    /* Data Parity Check Enable */
-       bit     MPARCKEN        0x20    /* Memory Parity Check Enable */
-       bit     EXTREQLCK       0x10    /* External Request Lock */
-}
-
-/*
- * Bus On/Off Time (p. 3-44)
- */
-register BUSTIME {
-       address                 0x085
-       access_mode RW
-       mask    BOFF            0xf0
-       mask    BON             0x0f
-}
-
-/*
- * Bus Speed (p. 3-45)
- */
-register BUSSPD {
-       address                 0x086
-       access_mode RW
-       mask    DFTHRSH         0xc0
-       mask    STBOFF          0x38
-       mask    STBON           0x07
-       mask    DFTHRSH_100     0xc0
-}
-
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-register HCNTRL {
-       address                 0x087
-       access_mode RW
-       bit     POWRDN          0x40
-       bit     SWINT           0x10
-       bit     IRQMS           0x08
-       bit     PAUSE           0x04
-       bit     INTEN           0x02
-       bit     CHIPRST         0x01
-       bit     CHIPRSTACK      0x01
-}
-
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transferred across the host bus.
- */
-register HADDR {
-       address                 0x088
-       size    4
-       access_mode RW
-}
-
-register HCNT {
-       address                 0x08c
-       size    3
-       access_mode RW
-}
-
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-register SCBPTR {
-       address                 0x090
-       access_mode RW
-}
-
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-register INTSTAT {
-       address                 0x091
-       access_mode RW
-       bit     BRKADRINT 0x08
-       bit     SCSIINT   0x04
-       bit     CMDCMPLT  0x02
-       bit     SEQINT    0x01
-       mask    BAD_PHASE       SEQINT          /* unknown scsi bus phase */
-       mask    SEND_REJECT     0x10|SEQINT     /* sending a message reject */
-       mask    NO_IDENT        0x20|SEQINT     /* no IDENTIFY after reconnect*/
-       mask    NO_MATCH        0x30|SEQINT     /* no cmd match for reconnect */
-       mask    EXTENDED_MSG    0x40|SEQINT     /* Extended message received */
-       mask    NO_MATCH_BUSY   0x50|SEQINT     /* Couldn't find BUSY SCB */
-       mask    REJECT_MSG      0x60|SEQINT     /* Reject message received */
-       mask    BAD_STATUS      0x70|SEQINT     /* Bad status from target */
-       mask    RESIDUAL        0x80|SEQINT     /* Residual byte count != 0 */
-       mask    ABORT_CMDCMPLT  0x91            /*
-                                                * Command tagged for abort
-                                                * completed successfully.
-                                                */
-       mask    AWAITING_MSG    0xa0|SEQINT     /*
-                                                * Kernel requested to specify
-                                                 * a message to this target
-                                                 * (command was null), so tell
-                                                 * it that it can fill the
-                                                 * message buffer.
-                                                 */
-       mask    MSG_BUFFER_BUSY 0xc0|SEQINT     /*
-                                                * Sequencer wants to use the
-                                                * message buffer, but it
-                                                * already contains a message
-                                                */
-       mask    MSGIN_PHASEMIS  0xd0|SEQINT     /*
-                                                * Target changed phase on us
-                                                * when we were expecting
-                                                * another msgin byte.
-                                                */
-       mask    DATA_OVERRUN    0xe0|SEQINT     /*
-                                                * Target attempted to write
-                                                * beyond the bounds of its
-                                                * command.
-                                                */
-
-       mask    SEQINT_MASK     0xf0|SEQINT     /* SEQINT Status Codes */
-       mask    INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
-}
-
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors.  You usually cannot recover from
- * these without a full board reset.
- */
-register ERROR {
-       address                 0x092
-       access_mode RO
-       bit     PARERR          0x08
-       bit     ILLOPCODE       0x04
-       bit     ILLSADDR        0x02
-       bit     ILLHADDR        0x01
-}
-
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-register CLRINT {
-       address                 0x092
-       access_mode WO
-       bit     CLRBRKADRINT    0x08
-       bit     CLRSCSIINT      0x04
-       bit     CLRCMDINT       0x02
-       bit     CLRSEQINT       0x01
-}
-
-register DFCNTRL {
-       address                 0x093
-       access_mode RW
-       bit     WIDEODD         0x40
-       bit     SCSIEN          0x20
-       bit     SDMAEN          0x10
-       bit     SDMAENACK       0x10
-       bit     HDMAEN          0x08
-       bit     HDMAENACK       0x08
-       bit     DIRECTION       0x04
-       bit     FIFOFLUSH       0x02
-       bit     FIFORESET       0x01
-}
-
-register DFSTATUS {
-       address                 0x094
-       access_mode RO
-       bit     DWORDEMP        0x20
-       bit     MREQPEND        0x10
-       bit     HDONE           0x08
-       bit     DFTHRESH        0x04
-       bit     FIFOFULL        0x02
-       bit     FIFOEMP         0x01
-}
-
-register DFDAT {
-       address                 0x099
-       access_mode RW
-}
-
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-register SCBCNT {
-       address                 0x09a
-       access_mode RW
-       bit     SCBAUTO         0x80
-       mask    SCBCNT_MASK     0x1f
-}
-
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the seqencer has yet to start)
- */
-register QINFIFO {
-       address                 0x09b
-       access_mode RW
-}
-
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-register QINCNT        {
-       address                 0x09c
-       access_mode RO
-}
-
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-register QOUTFIFO {
-       address                 0x09d
-       access_mode WO
-}
-
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-register QOUTCNT {
-       address                 0x09e
-       access_mode RO
-}
-
-/*
- * SCB Definition (p. 5-4)
- */
-scb {
-       address                 0x0a0
-       SCB_CONTROL {
-               size    1
-               bit     MK_MESSAGE      0x80
-               bit     DISCENB         0x40
-               bit     TAG_ENB         0x20
-               bit     MUST_DMAUP_SCB  0x10
-               bit     ABORT_SCB       0x08
-               bit     DISCONNECTED    0x04
-               mask    SCB_TAG_TYPE    0x03
-       }
-       SCB_TCL {
-               size    1
-               bit     SELBUSB         0x08
-               mask    TID             0xf0
-               mask    LID             0x07
-       }
-       SCB_TARGET_STATUS {
-               size    1
-       }
-       SCB_SGCOUNT {
-               size    1
-       }
-       SCB_SGPTR {
-               size    4
-       }
-       SCB_RESID_SGCNT {
-               size    1
-       }
-       SCB_RESID_DCNT  {
-               size    3
-       }
-       SCB_DATAPTR {
-               size    4
-       }
-       SCB_DATACNT {
-               size    3
-       }
-       SCB_LINKED_NEXT {
-               size    1
-       }
-       SCB_CMDPTR {
-               size    4
-       }
-       SCB_CMDLEN {
-               size    1
-       }
-       SCB_TAG {
-               size    1
-       }
-       SCB_NEXT {
-               size    1
-       }
-       SCB_PREV {
-               size    1
-       }
-       SCB_BUSYTARGETS {
-               size    4
-       }
-}
-
-const  SG_SIZEOF       0x08            /* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-register SEECTL_2840 {
-       address                 0x0c0
-       access_mode RW
-       bit     CS_2840         0x04
-       bit     CK_2840         0x02
-       bit     DO_2840         0x01
-}
-
-register STATUS_2840 {
-       address                 0x0c1
-       access_mode RW
-       bit     EEPROM_TF       0x80
-       mask    BIOS_SEL        0x60
-       mask    ADSEL           0x1e
-       bit     DI_2840         0x01
-}
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-register DSPCISTATUS {
-       address                 0x086
-}
-
-register BRDCTL        {
-       address                 0x01d
-       bit     BRDDAT7         0x80
-       bit     BRDDAT6         0x40
-       bit     BRDDAT5         0x20
-       bit     BRDSTB          0x10
-       bit     BRDCS           0x08
-       bit     BRDRW           0x04
-       bit     BRDCTL1         0x02
-       bit     BRDCTL0         0x01
-}
-
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device.  In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device.  When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM.  When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.  
- *
- * After successful arbitration for the memory port, the SEECS bit of 
- * the SEECTL register is connected to the chip select.  The SEECK, 
- * SEEDO, and SEEDI are connected to the clock, data out, and data in 
- * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
- * gives us an 800 nsec timer.  After a write to the SEECTL register, 
- * the SEERDY goes high 800 nsec later.  The one exception to this is 
- * when we first request access to the memory port.  The SEERDY goes 
- * high to signify that access has been granted and, for this case, has 
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to 
- * read the serial EEPROM.
- */
-register SEECTL {
-       address                 0x01e
-       bit     EXTARBACK       0x80
-       bit     EXTARBREQ       0x40
-       bit     SEEMS           0x20
-       bit     SEERDY          0x10
-       bit     SEECS           0x08
-       bit     SEECK           0x04
-       bit     SEEDO           0x02
-       bit     SEEDI           0x01
-}
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, writing the synchronous negotiation results
- * on top of the BIOS values, so we re-use those for our per-target
- * scratchspace (actually a value that can be copied directly into
- * SCSIRATE).  The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space.  This should work regardless of
- * whether the bios has been installed.
- */
-
-scratch_ram {
-       address                 0x020
-
-       /*
-        * 1 byte per target starting at this address for configuration values
-        */
-       TARG_SCRATCH {
-               size            16
-       }
-       ULTRA_ENB {
-               size            2
-       }
-       /*
-        * Bit vector of targets that have disconnection disabled.
-        */
-       DISC_DSB {
-               size            2
-       }
-       /*
-        * Length of pending message
-        */
-       MSG_LEN {
-               size            1
-       }
-       /* We reserve 8bytes to store outgoing messages */
-       MSG_OUT {
-               size            8
-       }
-       /* Parameters for DMA Logic */
-       DMAPARAMS {
-               size            1
-               bit     WIDEODD         0x40
-               bit     SCSIEN          0x20
-               bit     SDMAEN          0x10
-               bit     SDMAENACK       0x10
-               bit     HDMAEN          0x08
-               bit     HDMAENACK       0x08
-               bit     DIRECTION       0x04
-               bit     FIFOFLUSH       0x02
-               bit     FIFORESET       0x01
-       }
-       /*
-        * Number of SCBs supported by
-        * this card.
-        */
-       SCBCOUNT {
-               size            1
-       }
-       /*
-        * Two's complement of SCBCOUNT
-        */
-       COMP_SCBCOUNT {
-               size            1
-       }
-       /*
-        * Mask of bits to test against
-        * when looking at the Queue Count
-        * registers.  Works around a bug
-        * on aic7850 chips. 
-        */
-       QCNTMASK {
-               size            1
-       }
-       SEQ_FLAGS {
-               size            1
-               bit     RESELECTED      0x80
-               bit     IDENTIFY_SEEN   0x40
-               bit     TAGGED_SCB      0x20
-               bit     DPHASE          0x10
-               bit     PAGESCBS        0x04
-               bit     WIDE_BUS        0x02
-               bit     TWIN_BUS        0x01
-       }
-       /*
-        * Temporary storage for the
-        * target/channel/lun of a
-        * reconnecting target
-        */
-       SAVED_TCL {
-               size            1
-       }
-       SG_COUNT {
-               size            1
-       }
-       /* working value of SG pointer */
-       SG_NEXT {
-               size            4
-       }
-       /*
-        * head of list of SCBs awaiting
-        * selection
-        */
-       WAITING_SCBH {
-               size            1
-       }
-       SAVED_LINKPTR {
-               size            1
-       }
-       SAVED_SCBPTR {
-               size            1
-       }
-       /*
-        * The sequencer will stick the frist byte of any rejected message here
-        * so we can see what is getting thrown away.
-        */
-       REJBYTE {
-               size            1
-       }
-       /*
-        * The last bus phase as seen by the sequencer. 
-        */
-       LASTPHASE {
-               size            1
-               bit     CDI             0x80
-               bit     IOI             0x40
-               bit     MSGI            0x20
-               mask    PHASE_MASK      CDI|IOI|MSGI
-               mask    P_DATAOUT       0x00
-               mask    P_DATAIN        IOI
-               mask    P_COMMAND       CDI
-               mask    P_MESGOUT       CDI|MSGI
-               mask    P_STATUS        CDI|IOI
-               mask    P_MESGIN        CDI|IOI|MSGI
-               mask    P_BUSFREE       0x01
-       }
-       MSGIN_EXT_LEN {
-               size            1
-       }
-       MSGIN_EXT_OPCODE {
-               size            1
-       }
-       /*
-        * location 3, stores the last
-        * byte of an extended message if
-        * it passes the two bytes of space
-        * we allow now.  This byte isn't
-        * used for anything, it just makes
-        * the code shorter for tossing
-        * extra bytes.
-        */
-       MSGIN_EXT_BYTES {
-               size            3
-       }
-       /*
-        * head of list of SCBs that are
-        * disconnected.  Used for SCB
-        * paging.
-        */
-       DISCONNECTED_SCBH {
-               size            1
-       }
-       /*
-        * head of list of SCBs that are
-        * not in use.  Used for SCB paging.
-        */
-       FREE_SCBH {
-               size            1
-       }
-       HSCB_ADDR {
-               size            4
-       }
-       CUR_SCBID {
-               size            1
-       }
-       ARG_1 {
-               size            1
-               mask    SEND_MSG        0x80
-               mask    SEND_SENSE      0x40
-               mask    SEND_REJ        0x20
-               alias   RETURN_1
-       }
-       /*
-        * These are reserved registers in the card's scratch ram.  Some of
-        * the values are specified in the AHA2742 technical reference manual
-        * and are initialized by the BIOS at boot time.
-        */
-       SCSICONF {
-               address         0x05a
-               size            1
-               bit     RESET_SCSI      0x40
-       }
-       HOSTCONF {
-               address         0x05d
-               size            1
-       }
-       HA_274_BIOSCTRL {
-               address         0x05f
-               size            1
-               mask    BIOSMODE                0x30
-               mask    BIOSDISABLED            0x30    
-               bit     CHANNEL_B_PRIMARY       0x08
-       }
-}
-
-const SCB_LIST_NULL    0xff
-
-
-/* WDTR Message values */
-const BUS_8_BIT                0x00
-const BUS_16_BIT               0x01
-const BUS_32_BIT               0x02
-const MAX_OFFSET_8BIT          0x0f
-const MAX_OFFSET_16BIT 0x08
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
deleted file mode 100644 (file)
index faa9e1b..0000000
+++ /dev/null
@@ -1,1150 +0,0 @@
-/*+M***********************************************************************
- *Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
- *
- *Copyright (c) 1994 John Aycock
- *  The University of Calgary Department of Computer Science.
- *  All rights reserved.
- *
- *FreeBSD, Twin, Wide, 2 command per target support, tagged queuing,
- *SCB paging and other optimizations:
- *Copyright (c) 1994, 1995, 1996, 1997 Justin Gibbs. All rights reserved.
- *
- *Redistribution and use in source and binary forms, with or without
- *modification, are permitted provided that the following conditions
- *are met:
- *1. Redistributions of source code must retain the above copyright
- *   notice, this list of conditions, and the following disclaimer.
- *2. Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *3. All advertising materials mentioning features or use of this software
- *   must display the following acknowledgement:
- *     This product includes software developed by the University of Calgary
- *     Department of Computer Science and its contributors.
- *4. Neither the name of the University nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- *ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- *FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- *DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- *LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- *OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- *SUCH DAMAGE.
- *
- *     $Id: aic7xxx.seq,v 1.73 1997/04/24 16:52:18 gibbs Exp $
- *
- *-M************************************************************************/
-
-#include <aic7xxx.reg>
-#include <scsi_message.h>
-
-/*
- * A few words on the waiting SCB list:
- * After starting the selection hardware, we check for reconnecting targets
- * as well as for our selection to complete just in case the reselection wins
- * bus arbitration.  The problem with this is that we must keep track of the
- * SCB that we've already pulled from the QINFIFO and started the selection
- * on just in case the reselection wins so that we can retry the selection at
- * a later time.  This problem cannot be resolved by holding a single entry
- * in scratch ram since a reconnecting target can request sense and this will
- * create yet another SCB waiting for selection.  The solution used here is to 
- * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
- * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
- * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
- * this list everytime a request sense occurs or after completing a non-tagged
- * command for which a second SCB has been queued.  The sequencer will
- * automatically consume the entries.
- */
-
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
-reset:
-       clr     SCSISIGO;               /* De-assert BSY */
-       /* Always allow reselection */
-       mvi     SCSISEQ, ENRSELI|ENAUTOATNP;
-       call    clear_target_state;
-poll_for_work:
-       test    SSTAT0,SELDO    jnz select;
-       test    SSTAT0,SELDI    jnz reselect;
-       test    SCSISEQ, ENSELO jnz poll_for_work;
-.if ( TWIN_CHANNEL )
-       /*
-        * Twin channel devices cannot handle things like SELTO
-        * interrupts on the "background" channel.  So, if we
-        * are selecting, keep polling the current channel util
-        * either a selection or reselection occurs.
-        */
-       xor     SBLKCTL,SELBUSB;        /* Toggle to the other bus */
-       test    SSTAT0,SELDO    jnz select;
-       test    SSTAT0,SELDI    jnz reselect;
-       test    SCSISEQ, ENSELO jnz poll_for_work;
-       xor     SBLKCTL,SELBUSB;        /* Toggle back */
-.endif
-       cmp     WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
-test_queue:
-       /* Has the driver posted any work for us? */
-       mov     A, QCNTMASK;
-       test    QINCNT,A        jz poll_for_work;
-
-/*
- * We have at least one queued SCB now and we don't have any 
- * SCBs in the list of SCBs awaiting selection.  If we have
- * any SCBs available for use, pull the tag from the QINFIFO
- * and get to work on it.
- */
-.if ( SCB_PAGING )
-       mov     ALLZEROS        call    get_free_or_disc_scb;
-       cmp     SINDEX, SCB_LIST_NULL   je poll_for_work;
-.endif
-dequeue_scb:
-       mov     CUR_SCBID,QINFIFO;
-.if !( SCB_PAGING )
-       /* In the non-paging case, the SCBID == hardware SCB index */
-       mov     SCBPTR, CUR_SCBID;
-.endif
-dma_queued_scb:
-/*
- * DMA the SCB from host ram into the current SCB location.
- */
-       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     CUR_SCBID       call dma_scb;
-
-/*
- * See if there is not already an active SCB for this target.  This code
- * locks out on a per target basis instead of target/lun.  Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands.  We also don't have enough spare SCB space for us to store the
- * SCBID of the currently busy transaction for each target/lun making it
- * impossible to link up the SCBs.
- */
-test_busy:
-       test    SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
-       mvi     SEQCTL, PAUSEDIS|FASTMODE;
-       mov     SAVED_SCBPTR, SCBPTR;
-       mov     SCB_TCL         call    index_untagged_scb;
-       mov     ARG_1, SINDIR;                  /*
-                                                * ARG_1 should
-                                                * now have the SCB ID of
-                                                * any active, non-tagged,
-                                                * command for this target.
-                                                */
-       cmp     ARG_1, SCB_LIST_NULL je make_busy;
-.if ( SCB_PAGING )
-       /*
-        * Put this SCB back onto the free list.  It
-        * may be necessary to satisfy the search for
-        * the active SCB.
-        */
-       mov     SCBPTR, SAVED_SCBPTR;
-       call    add_scb_to_free_list;
-       /* Find the active SCB */
-       mov     ALLZEROS        call findSCB;
-       /*
-        * If we couldn't find it, tell the kernel.  This should
-        * never happen.
-        */
-       cmp     SINDEX, SCB_LIST_NULL   jne paged_busy_link;
-       mvi     INTSTAT, NO_MATCH_BUSY;
-paged_busy_link:
-       /* Link us in */
-       mov     SCB_LINKED_NEXT, CUR_SCBID;
-       /* Put it back on the disconnected list */
-       call    add_scb_to_disc_list;
-       mvi     SEQCTL, FASTMODE;
-       jmp     poll_for_work;
-.else
-simple_busy_link:
-       mov     SCBPTR, ARG_1;
-       mov     SCB_LINKED_NEXT, CUR_SCBID;
-       mvi     SEQCTL, FASTMODE;
-       jmp     poll_for_work;
-.endif
-make_busy:
-       mov     DINDIR, CUR_SCBID;
-       mov     SCBPTR, SAVED_SCBPTR;
-       mvi     SEQCTL, FASTMODE;
-
-start_scb:
-       /*
-        * Place us on the waiting list in case our selection
-        * doesn't win during bus arbitration.
-        */
-       mov     SCB_NEXT,WAITING_SCBH;
-       mov     WAITING_SCBH, SCBPTR;
-start_waiting:
-       /*
-        * Pull the first entry off of the waiting SCB list
-        * We don't have to "test_busy" because only transactions that
-        * have passed that test can be in the WAITING_SCB list.
-        */
-       mov     SCBPTR, WAITING_SCBH;
-       call    start_selection;
-       jmp     poll_for_work;
-
-start_selection:
-.if ( TWIN_CHANNEL )
-       and     SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
-       and     A,SELBUSB,SCB_TCL;      /* Get new channel bit */
-       or      SINDEX,A;
-       mov     SBLKCTL,SINDEX;         /* select channel */
-.endif
-initialize_scsiid:
-       and     A, TID, SCB_TCL;        /* Get target ID */
-       and     SCSIID, OID;            /* Clear old target */
-       or      SCSIID, A;
-       mvi     SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
-/*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target yet.
- */
-reselect:
-       clr     MSG_LEN;        /* Don't have anything in the mesg buffer */
-       mvi     CLRSINT0, CLRSELDI;
-       /* XXX test for and handle ONE BIT condition */
-       and     SAVED_TCL, SELID_MASK, SELID;
-       or      SEQ_FLAGS,RESELECTED;
-       jmp     select2;
-
-/*
- * After the selection, remove this SCB from the "waiting SCB"
- * list.  This is achieved by simply moving our "next" pointer into
- * WAITING_SCBH.  Our next pointer will be set to null the next time this
- * SCB is used, so don't bother with it now.
- */
-select:
-       /* Turn off the selection hardware */
-       mvi     SCSISEQ, ENRSELI|ENAUTOATNP;    /*
-                                                * ATN on parity errors
-                                                * for "in" phases
-                                                */
-       mvi     CLRSINT0, CLRSELDO;
-       mov     SCBPTR, WAITING_SCBH;
-       mov     WAITING_SCBH,SCB_NEXT;
-       mov     SAVED_TCL, SCB_TCL;
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted.  Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
-
-mk_identify:
-       and     MSG_OUT,0x7,SCB_TCL;    /* lun */
-       and     A,DISCENB,SCB_CONTROL;  /* mask off disconnect privledge */
-       or      MSG_OUT,A;              /* or in disconnect privledge */
-       or      MSG_OUT,MSG_IDENTIFYFLAG;
-       mvi     MSG_LEN, 1;
-
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-mk_tag:
-       test    SCB_CONTROL,TAG_ENB jz  mk_message;
-       and     MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
-       mov     MSG_OUT[2],SCB_TAG;
-       add     MSG_LEN,2;      /* update message length */
-
-/*
- * Interrupt the driver, and allow it to tweak the message buffer
- * if it asks.
- */
-mk_message:
-       test    SCB_CONTROL,MK_MESSAGE  jz select2;
-       mvi     INTSTAT,AWAITING_MSG;
-
-select2:
-       mvi     CLRSINT1,CLRBUSFREE;
-       or      SIMODE1, ENBUSFREE;             /*
-                                                * We aren't expecting a
-                                                * bus free, so interrupt
-                                                * the kernel driver if it
-                                                * happens.
-                                                */
-/*
- * Initialize Ultra mode setting and clear the SCSI channel.
- */
-       or      SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
-.if ( ULTRA )
-ultra:
-       mvi     SINDEX, ULTRA_ENB+1;
-       test    SAVED_TCL, 0x80         jnz ultra_2;    /* Target ID > 7 */
-       dec     SINDEX;
-ultra_2:
-       mov     FUNCTION1,SAVED_TCL;
-       mov     A,FUNCTION1;
-       test    SINDIR, A       jz ndx_dtr;
-       or      SXFRCTL0, FAST20;
-.endif
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- * The SCSIRATE settings for each target are stored in an array
- * based at TARG_SCRATCH.
- */
-ndx_dtr:
-       shr     A,4,SAVED_TCL;
-       test    SBLKCTL,SELBUSB jz ndx_dtr_2;
-       or      SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
-       or      A,0x08;                 /* Channel B entries add 8 */
-ndx_dtr_2:
-       add     SINDEX,TARG_SCRATCH,A;
-       mov     SCSIRATE,SINDIR;
-
-
-/*
- * Main loop for information transfer phases.  If BSY is false, then
- * we have a bus free condition, expected or not.  Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
- */
-ITloop:
-       test    SSTAT1,REQINIT          jz ITloop;
-       test    SSTAT1, SCSIPERR        jnz ITloop;
-
-       and     A,PHASE_MASK,SCSISIGI;
-       mov     LASTPHASE,A;
-       mov     SCSISIGO,A;
-
-       cmp     ALLZEROS,A      je p_dataout;
-       cmp     A,P_DATAIN      je p_datain;
-       cmp     A,P_COMMAND     je p_command;
-       cmp     A,P_MESGOUT     je p_mesgout;
-       cmp     A,P_STATUS      je p_status;
-       cmp     A,P_MESGIN      je p_mesgin;
-
-       mvi     INTSTAT,BAD_PHASE;      /* unknown phase - signal driver */
-       jmp     ITloop;                 /* Try reading the bus again. */
-
-await_busfree:
-       and     SIMODE1, ~ENBUSFREE;
-       call    clear_target_state;
-       mov     NONE, SCSIDATL;         /* Ack the last byte */
-       test    SSTAT1,REQINIT|BUSFREE  jz .;
-       test    SSTAT1, BUSFREE jnz poll_for_work;
-       mvi     INTSTAT, BAD_PHASE;
-       
-clear_target_state:
-       clr     DFCNTRL;
-       clr     SCSIRATE;               /*
-                                        * We don't know the target we will
-                                        * connect to, so default to narrow
-                                        * transfers to avoid parity problems.
-                                        */
-       and     SXFRCTL0, ~FAST20;      
-       mvi     LASTPHASE, P_BUSFREE;
-       /* clear target specific flags */
-       and     SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
-
-p_dataout:
-       mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
-       jmp     data_phase_init;
-
-/*
- * 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.
- */
-data_phase_reinit:
-       mvi     DINDEX, STCNT;
-       mvi     SCB_RESID_DCNT  call bcopy_3;
-       jmp     data_phase_loop;
-
-p_datain:
-       mvi     DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
-data_phase_init:
-       call    assert;                 /*
-                                        * Ensure entering a data
-                                        * phase is okay - seen identify, etc.
-                                        */
-
-       test    SEQ_FLAGS, DPHASE       jnz data_phase_reinit;
-
-       /*
-        * 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     DINDEX, HADDR;
-       mvi     SCB_DATAPTR     call bcopy_7;
-
-       call    set_stcnt_from_hcnt;
-
-       mov     SG_COUNT,SCB_SGCOUNT;
-
-       mvi     DINDEX, SG_NEXT;
-       mvi     SCB_SGPTR       call bcopy_4;
-
-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;
-       mvi     HCNT[0], 0xff;
-       mvi     HCNT[1], 0xff;
-       mvi     HCNT[2], 0xff;
-       call    set_stcnt_from_hcnt;
-
-data_phase_inbounds:
-/* If we are the last SG block, ensure wideodd is off. */
-       cmp     SG_COUNT,0x01 jne data_phase_wideodd;
-       and     DMAPARAMS, ~WIDEODD;
-data_phase_wideodd:
-       mov     DMAPARAMS  call dma;
-
-/* 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:
-       dec     SG_COUNT;       /* one less segment to go */
-
-       test    SG_COUNT, 0xff  jz data_phase_finish; /* Are we done? */
-
-       clr     A;                      /* add sizeof(struct scatter) */
-       add     SG_NEXT[0],SG_SIZEOF;
-       adc     SG_NEXT[1],A;
-
-/*
- * 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:
-       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;
-
-/* Load STCNT as well.  It is a mirror of HCNT */
-       call    set_stcnt_from_hcnt;
-       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.
- */
-       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;
-
-       /* We have seen a data phase */
-       or      SEQ_FLAGS, DPHASE;
-
-       jmp     ITloop;
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
-       and     SXFRCTL1, ~BITBUCKET;
-       mvi     INTSTAT,DATA_OVERRUN;
-       jmp     ITloop;
-
-/*
- * Command phase.  Set up the DMA registers and let 'er rip.
- */
-p_command:
-       call    assert;
-
-/*
- * Load HADDR and HCNT.
- */
-       mvi     DINDEX, HADDR;
-       mvi     SCB_CMDPTR      call bcopy_5;
-       clr     HCNT[1];
-       clr     HCNT[2];
-
-       call    set_stcnt_from_hcnt;
-
-       mvi     (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
-       jmp     ITloop;
-
-/*
- * Status phase.  Wait for the data byte to appear, then read it
- * and store it into the SCB.
- */
-p_status:
-       call    assert;
-
-       mov     SCB_TARGET_STATUS, SCSIDATL;
-       jmp     ITloop;
-
-/*
- * Message out phase.  If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
- */
-p_mesgout:
-       test    MSG_LEN, 0xff   jnz  p_mesgout_start;
-       mvi     MSG_NOOP        call mk_mesg;   /* build NOP message */
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG_OUT.  Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
-       mvi     SINDEX,MSG_OUT;
-       mov     DINDEX,MSG_LEN;
-
-/*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message.  Otherwise, keep going until the message is exhausted.
- * ATN must be dropped *at least* 90ns before we ack the last byte, so
- * the code is aranged to execute two instructions before the byte is
- * transferred to give a good margin of safety
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
- */
-p_mesgout_loop:
-       test    SSTAT1, REQINIT         jz p_mesgout_loop;
-       test    SSTAT1, SCSIPERR        jnz p_mesgout_loop;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
-       cmp     LASTPHASE, P_MESGOUT jne p_mesgout_done;
-p_mesgout_testretry:
-       test    DINDEX,0xff     jnz p_mesgout_dropatn;
-       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
-       jmp     p_mesgout_start;
-/*
- * If the next bus phase after ATN drops is a message out, it means
- * that the target is requesting that the last message(s) be resent.
- */
-p_mesgout_dropatn:
-       cmp     DINDEX,1        jne p_mesgout_outb;     /* last byte? */
-       mvi     CLRSINT1,CLRATNO;                       /* drop ATN */
-p_mesgout_outb:
-       dec     DINDEX;
-       mov     SCSIDATL,SINDIR;
-       jmp     p_mesgout_loop;
-
-p_mesgout_done:
-       mvi     CLRSINT1,CLRATNO;       /* Be sure to turn ATNO off */
-       clr     MSG_LEN;                /* no active msg */
-       jmp     ITloop;
-
-/*
- * Message in phase.  Bytes are read using Automatic PIO mode.
- */
-p_mesgin:
-       mvi     ACCUM           call inb_first; /* read the 1st message byte */
-       mov     REJBYTE,A;                      /* save it for the driver */
-
-       test    A,MSG_IDENTIFYFLAG      jnz mesgin_identify;
-       cmp     A,MSG_DISCONNECT        je mesgin_disconnect;
-       cmp     A,MSG_SAVEDATAPOINTER   je mesgin_sdptrs;
-       cmp     ALLZEROS,A              je mesgin_complete;
-       cmp     A,MSG_RESTOREPOINTERS   je mesgin_rdptrs;
-       cmp     A,MSG_EXTENDED          je mesgin_extended;
-       cmp     A,MSG_MESSAGE_REJECT    je mesgin_reject;
-       cmp     A,MSG_NOOP              je mesgin_done;
-
-rej_mesgin:
-/*
- * We have no idea what this message in is, so we issue a message reject
- * and hope for the best.  In any case, rejection should be a rare
- * occurrence - signal the driver when it happens.
- */
-       mvi     INTSTAT,SEND_REJECT;            /* let driver know */
-
-       mvi     MSG_MESSAGE_REJECT      call mk_mesg;
-
-mesgin_done:
-       mov     NONE,SCSIDATL;          /*dummy read from latch to ACK*/
-       jmp     ITloop;
-
-
-mesgin_complete:
-/*
- * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
- * and trigger a completion interrupt.  Before doing so, check to see if there
- * is a residual or the status byte is something other than NO_ERROR (0).  In
- * either of these conditions, we upload the SCB back to the host so it can
- * process this information.  In the case of a non zero status byte, we 
- * additionally interrupt the kernel driver synchronously, allowing it to
- * decide if sense should be retrieved.  If the kernel driver wishes to request
- * sense, it will fill the kernel SCB with a request sense command and set
- * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
- * the SCB, and process it as the next command by adding it to the waiting list.
- * If the kernel driver does not wish to request sense, it need only clear
- * RETURN_1, and the command is allowed to complete normally.  We don't bother
- * to post to the QOUTFIFO in the error cases since it would require extra
- * work in the kernel driver to ensure that the entry was removed before the
- * command complete code tried processing it.
- */
-
-/*
- * First check for residuals
- */
-       test    SCB_RESID_SGCNT,0xff    jnz upload_scb;
-       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* Good Status? */
-upload_scb:
-       mvi     DMAPARAMS, FIFORESET;
-       mov     SCB_TAG         call dma_scb;
-check_status:
-       test    SCB_TARGET_STATUS,0xff  jz status_ok;   /* Just a residual? */
-       mvi     INTSTAT,BAD_STATUS;                     /* let driver know */
-       cmp     RETURN_1, SEND_SENSE    jne status_ok;
-       /* This SCB becomes the next to execute as it will retrieve sense */
-       mov     SCB_LINKED_NEXT, SCB_TAG;
-       jmp     dma_next_scb;
-
-status_ok:
-/* First, mark this target as free. */
-       test    SCB_CONTROL,TAG_ENB jnz complete;       /*
-                                                        * Tagged commands
-                                                        * don't busy the
-                                                        * target.
-                                                        */
-       mov     SAVED_SCBPTR, SCBPTR;
-       mov     SAVED_LINKPTR, SCB_LINKED_NEXT;
-       mov     SCB_TCL call index_untagged_scb;
-       mov     DINDIR, SAVED_LINKPTR;
-       mov     SCBPTR, SAVED_SCBPTR;
-
-complete:
-       /* Post the SCB and issue an interrupt */
-       mov     QOUTFIFO,SCB_TAG;
-       mvi     INTSTAT,CMDCMPLT;
-       test    SCB_CONTROL, ABORT_SCB jz dma_next_scb;
-       mvi     INTSTAT, ABORT_CMDCMPLT;
-
-dma_next_scb:
-       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL  je add_to_free_list;
-.if !( SCB_PAGING )
-       /* Only DMA on top of ourselves if we are the SCB to download */
-       mov     A, SCB_LINKED_NEXT;
-       cmp     SCB_TAG, A      je dma_next_scb2;
-       call    add_scb_to_free_list;
-       mov     SCBPTR, A;
-       jmp     add_to_waiting_list;
-.endif
-dma_next_scb2:
-       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     SCB_LINKED_NEXT         call dma_scb;
-add_to_waiting_list:
-       mov     SCB_NEXT,WAITING_SCBH;
-       mov     WAITING_SCBH, SCBPTR;
-       /*
-        * Prepare our selection hardware before the busfree so we have a
-        * high probability of winning arbitration.
-        */
-       call    start_selection;
-       jmp     await_busfree;
-add_to_free_list:
-       call    add_scb_to_free_list;
-       jmp     await_busfree;
-
-/*
- * Is it an extended message?  Copy the message to our message buffer and
- * notify the host.  The host will tell us whether to reject this message,
- * respond to it with the message that the host placed in our message buffer,
- * or simply to do nothing.
- */
-mesgin_extended:
-       mvi     MSGIN_EXT_LEN    call inb_next;
-       mov     A, MSGIN_EXT_LEN;
-mesgin_extended_loop:
-       mov     DINDEX  call    inb_next;
-       dec     A;
-       cmp     DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
-       dec     DINDEX;         /* dump by repeatedly filling the last byte */
-mesgin_extended_loop_test:
-       test    A, 0xFF         jnz mesgin_extended_loop;
-mesgin_extended_intr:
-       mvi     INTSTAT,EXTENDED_MSG;           /* let driver know */
-       cmp     RETURN_1,SEND_REJ je rej_mesgin;
-       cmp     RETURN_1,SEND_MSG jne mesgin_done;
-/* The kernel has setup a message to be sent */
-       or      SCSISIGO,ATNO,LASTPHASE;        /* turn on ATNO */
-       jmp     mesgin_done;
-
-/*
- * Is it a disconnect message?  Set a flag in the SCB to remind us
- * and await the bus going free.
- */
-mesgin_disconnect:
-       or      SCB_CONTROL,DISCONNECTED;
-.if ( SCB_PAGING )
-       call    add_scb_to_disc_list;
-.endif
-       jmp     await_busfree;
-
-/*
- * Save data pointers message:
- * Copying RAM values back to SCB, for Save Data Pointers message, but
- * only if we've actually been into a data phase to change them.  This
- * protects against bogus data in scratch ram and the residual counts
- * since they are only initialized when we go into data_in or data_out.
- */
-mesgin_sdptrs:
-       test    SEQ_FLAGS, DPHASE       jz mesgin_done;
-       mov     SCB_SGCOUNT,SG_COUNT;
-
-       /* The SCB SGPTR becomes the next one we'll download */
-       mvi     DINDEX, SCB_SGPTR;
-       mvi     SG_NEXT call bcopy_4;
-       
-       /* The SCB DATAPTR0 becomes the current SHADDR */
-       mvi     DINDEX, SCB_DATAPTR;
-       mvi     SHADDR          call bcopy_4;
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer.
- */
-       mvi     SCB_RESID_DCNT  call    bcopy_3;
-
-       jmp     mesgin_done;
-
-/*
- * Restore pointers message?  Data pointers are recopied from the
- * SCB anytime we enter a data phase for the first time, so all
- * we need to do is clear the DPHASE flag and let the data phase
- * code do the rest.
- */
-mesgin_rdptrs:
-       and     SEQ_FLAGS, ~DPHASE;             /*
-                                                * We'll reload them
-                                                * the next time through
-                                                * the dataphase.
-                                                */
-       jmp     mesgin_done;
-
-/*
- * Identify message?  For a reconnecting target, this tells us the lun
- * that the reconnection is for - find the correct SCB and switch to it,
- * clearing the "disconnected" bit so we don't "find" it by accident later.
- */
-mesgin_identify:
-       test    A,0x78  jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
-       and     A,0x07;                 /* lun in lower three bits */
-       or      SAVED_TCL,A;            /* SAVED_TCL should be complete now */
-       mov     SAVED_TCL call index_untagged_scb;
-       mov     ARG_1, SINDIR;
-.if ( SCB_PAGING )
-       cmp     ARG_1,SCB_LIST_NULL     jne use_findSCB;
-.else
-       cmp     ARG_1,SCB_LIST_NULL     je snoop_tag;
-       /* Directly index the SCB */
-       mov     SCBPTR,ARG_1;
-       test    SCB_CONTROL,DISCONNECTED jz not_found;
-       jmp     setup_SCB;
-.endif
-/*
- * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to find the proper
- * SCB.  With SCB paging, this requires using findSCB for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
- */
-snoop_tag:
-       mov     NONE,SCSIDATL;          /* ACK Identify MSG */
-snoop_tag_loop:
-       test    SSTAT1,REQINIT          jz snoop_tag_loop;
-       test    SSTAT1, SCSIPERR        jnz snoop_tag_loop;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
-       cmp     LASTPHASE, P_MESGIN     jne not_found;
-       cmp     SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
-get_tag:
-       or      SEQ_FLAGS, TAGGED_SCB;
-       mvi     ARG_1   call inb_next;  /* tag value */
-/*
- * See if the tag is in range.  The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incomming tag and there is
- * no carry.
- */
-       mov     A,COMP_SCBCOUNT;
-       add     SINDEX,A,ARG_1;
-       jc      not_found;
-
-.if ! ( SCB_PAGING )
-index_by_tag:
-       mov     SCBPTR,ARG_1;
-       mov     A, SAVED_TCL;
-       cmp     SCB_TCL,A               jne not_found;
-       test    SCB_CONTROL,TAG_ENB     jz  not_found;
-       test    SCB_CONTROL,DISCONNECTED jz not_found;
-.else
-/*
- * Ensure that the SCB the tag points to is for an SCB transaction
- * to the reconnecting target.
- */
-use_findSCB:
-       mov     ALLZEROS        call findSCB;     /* Have to search */
-       cmp     SINDEX, SCB_LIST_NULL   je not_found;
-.endif
-setup_SCB:
-       and     SCB_CONTROL,~DISCONNECTED;
-       or      SEQ_FLAGS,IDENTIFY_SEEN;          /* make note of IDENTIFY */
-       jmp     mesgin_done;
-
-not_found:
-       mvi     INTSTAT, NO_MATCH;
-       mvi     MSG_BUS_DEV_RESET       call mk_mesg;
-       jmp     mesgin_done;
-
-/*
- * Message reject?  Let the kernel driver handle this.  If we have an 
- * outstanding WDTR or SDTR negotiation, assume that it's a response from 
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
-       mvi     INTSTAT, REJECT_MSG;
-       jmp     mesgin_done;
-
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * Locking the driver out, build a one-byte message passed in SINDEX
- * if there is no active message already.  SINDEX is returned intact.
- */
-mk_mesg:
-       mvi     SEQCTL, PAUSEDIS|FASTMODE;
-       test    MSG_LEN,0xff    jz mk_mesg1;    /* Should always succeed */
-       
-       /*
-        * Hmmm.  For some reason the mesg buffer is in use.
-        * Tell the driver.  It should look at SINDEX to find
-        * out what we wanted to use the buffer for and resolve
-        * the conflict.
-        */
-       mvi     SEQCTL,FASTMODE;
-       mvi     INTSTAT,MSG_BUFFER_BUSY;
-
-mk_mesg1:
-       or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
-       mvi     MSG_LEN,1;              /* length = 1 */
-       mov     MSG_OUT,SINDEX;         /* 1-byte message */
-       mvi     SEQCTL,FASTMODE ret;
-
-/*
- * Functions to read data in Automatic PIO mode.
- *
- * According to Adaptec's documentation, an ACK is not sent on input from
- * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
- * latched (the usual way), then read the data byte directly off the bus
- * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
- * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
- * spec guarantees that the target will hold the data byte on the bus until
- * we send our ACK.
- *
- * The assumption here is that these are called in a particular sequence,
- * and that REQ is already set when inb_first is called.  inb_{first,next}
- * use the same calling convention as inb.
- */
-
-inb_next:
-       mov     NONE,SCSIDATL;          /*dummy read from latch to ACK*/
-inb_next_wait:
-       /*
-        * If there is a parity error, wait for the kernel to
-        * see the interrupt and prepare our message response
-        * before continuing.
-        */
-       test    SSTAT1, REQINIT jz inb_next_wait;
-       test    SSTAT1, SCSIPERR jnz inb_next_wait;
-       and     LASTPHASE, PHASE_MASK, SCSISIGI;
-       cmp     LASTPHASE, P_MESGIN jne mesgin_phasemis;
-inb_first:
-       mov     DINDEX,SINDEX;
-       mov     DINDIR,SCSIBUSL ret;            /*read byte directly from bus*/
-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
- */
-       mvi     INTSTAT, MSGIN_PHASEMIS;
-       jmp     ITloop;
-
-/*
- * DMA data transfer.  HADDR and HCNT must be loaded first, and
- * SINDEX should contain the value to load DFCNTRL with - 0x3d for
- * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
- * during initialization.
- */
-dma:
-       mov     DFCNTRL,SINDEX;
-dma_loop:
-       test    SSTAT0,DMADONE  jnz dma_dmadone;
-       test    SSTAT1,PHASEMIS jz dma_loop;    /* ie. underrun */
-dma_phasemis:
-       test    SSTAT0,SDONE    jnz dma_checkfifo;
-       mov     SINDEX,ALLZEROS;                /* Notify caller of phasemiss */
-
-/*
- * We will be "done" DMAing when the transfer count goes to zero, or
- * the target changes the phase (in light of this, it makes sense that
- * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
- * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
- * magically on STCNT=0 or a phase change, so just wait for FIFO empty
- * status.
- */
-dma_checkfifo:
-       test    DFCNTRL,DIRECTION       jnz dma_fifoempty;
-dma_fifoflush:
-       test    DFSTATUS,FIFOEMP        jz dma_fifoflush;
-
-dma_fifoempty:
-       /* Don't clobber an inprogress host data transfer */
-       test    DFSTATUS, MREQPEND      jnz dma_fifoempty;
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are 
- * actually off first lest we get an ILLSADDR.
- */
-dma_dmadone:
-       and     DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
-dma_halt:
-       test    DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; 
-return:
-       ret;
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
-       test    SEQ_FLAGS,RESELECTED    jz return;      /* reselected? */
-       test    SEQ_FLAGS,IDENTIFY_SEEN jnz return;     /* seen IDENTIFY? */
-
-       mvi     INTSTAT,NO_IDENT        ret;    /* no - tell the kernel */
-
-.if ( SCB_PAGING )
-/*
- * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
- * or by the SCBIDn ARG_1.  The search begins at the SCB index passed in
- * via SINDEX.  If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
- * otherwise, SCBPTR is set to the proper SCB.
- */
-findSCB:
-       mov     SCBPTR,SINDEX;                  /* switch to next SCB */
-       mov     A, ARG_1;                       /* Tag passed in ARG_1 */
-       cmp     SCB_TAG,A       jne findSCB_loop;
-       test    SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
-findSCB_loop:
-       inc     SINDEX;
-       mov     A,SCBCOUNT;
-       cmp     SINDEX,A        jne findSCB;
-/*
- * We didn't find it.  If we're paging, pull an SCB and DMA down the
- * one we want.  If we aren't paging or the SCB we dma down has the
- * abort flag set, return not found.
- */
-       mov     ALLZEROS        call    get_free_or_disc_scb;
-       mvi     DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
-       mov     ARG_1   call dma_scb;
-       test    SCB_RESID_SGCNT, 0xff jz . + 2;
-       or      SCB_CONTROL, MUST_DMAUP_SCB;
-       test    SCB_CONTROL, ABORT_SCB jz return;
-find_error:
-       mvi     SINDEX, SCB_LIST_NULL ret;
-foundSCB:
-       test    SCB_CONTROL, ABORT_SCB jnz find_error;
-rem_scb_from_disc_list:
-/* Remove this SCB from the disconnection list */
-       cmp     SCB_NEXT,SCB_LIST_NULL je unlink_prev;
-       mov     SAVED_LINKPTR, SCB_PREV;
-       mov     SCBPTR, SCB_NEXT;
-       mov     SCB_PREV, SAVED_LINKPTR;
-       mov     SCBPTR, SINDEX;
-unlink_prev:
-       cmp     SCB_PREV,SCB_LIST_NULL  je rHead;/* At the head of the list */
-       mov     SAVED_LINKPTR, SCB_NEXT;
-       mov     SCBPTR, SCB_PREV;
-       mov     SCB_NEXT, SAVED_LINKPTR;
-       mov     SCBPTR, SINDEX ret;
-rHead:
-       mov     DISCONNECTED_SCBH,SCB_NEXT ret;
-.else
-       ret;
-.endif
-
-set_stcnt_from_hcnt:
-       mov     STCNT[0], HCNT[0];
-       mov     STCNT[1], HCNT[1];
-       mov     STCNT[2], HCNT[2] ret;
-
-bcopy_7:
-       mov     DINDIR, SINDIR;
-       mov     DINDIR, SINDIR;
-bcopy_5:
-       mov     DINDIR, SINDIR;
-bcopy_4:
-       mov     DINDIR, SINDIR;
-bcopy_3:
-       mov     DINDIR, SINDIR;
-       mov     DINDIR, SINDIR;
-       mov     DINDIR, SINDIR ret;
-
-dma_scb:
-       /*
-        * SCB index is in SINDEX.  Determine the physical address in
-        * the host where this SCB is located and load HADDR with it.
-        */
-       shr     DINDEX, 3, SINDEX;
-       shl     A, 5, SINDEX;
-       add     HADDR[0], A, HSCB_ADDR[0];
-       mov     A, DINDEX;
-       adc     HADDR[1], A, HSCB_ADDR[1];
-       clr     A;
-       adc     HADDR[2], A, HSCB_ADDR[2];
-       adc     HADDR[3], A, HSCB_ADDR[3];
-       /* Setup Count */
-       mvi     HCNT[0], 28;
-       clr     HCNT[1];
-       clr     HCNT[2];
-       mov     DFCNTRL, DMAPARAMS;
-       test    DMAPARAMS, DIRECTION    jnz dma_scb_fromhost;
-       /* Fill it with the SCB data */
-copy_scb_tofifo:
-       mvi     SINDEX, SCB_CONTROL;
-       add     A, 28, SINDEX;
-copy_scb_tofifo_loop:
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       mov     DFDAT,SINDIR;
-       cmp     SINDEX, A jne copy_scb_tofifo_loop;
-       or      DFCNTRL, HDMAEN|FIFOFLUSH;
-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;
-dfdat_in_7:
-       mov     DINDEX,SINDEX;
-dfdat_in_7_continued:
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT;
-       mov     DINDIR,DFDAT ret;
-
-/*
- * Wait for DMA from host memory to data FIFO to complete, then disable
- * DMA and wait for it to acknowledge that it's off.
- */
-dma_finish:
-       test    DFSTATUS,HDONE  jz dma_finish;
-       /* Turn off DMA */
-       and     DFCNTRL, ~HDMAEN;
-       test    DFCNTRL, HDMAEN jnz .;
-       ret;
-
-index_untagged_scb:
-       mov     DINDEX, SINDEX;
-       shr     DINDEX, 4;
-       and     DINDEX, 0x03;                   /* Bottom two bits of tid */
-       add     DINDEX, SCB_BUSYTARGETS;
-       shr     A, 6, SINDEX;                   /* Target ID divided by 4 */
-       test    SINDEX, SELBUSB jz index_untagged_scb2;
-       add     A, 2;                           /* Add 2 positions */
-index_untagged_scb2:
-       mov     SCBPTR, A;                      /*
-                                                * Select the SCB with this 
-                                                * target's information.
-                                                */
-       mov     SINDEX, DINDEX  ret;
-
-add_scb_to_free_list:
-       mov     SCB_NEXT, FREE_SCBH;
-       mvi     SCB_TAG, SCB_LIST_NULL;
-       mov     FREE_SCBH, SCBPTR ret;
-
-.if ( SCB_PAGING )
-get_free_or_disc_scb:
-       cmp     FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
-       cmp     DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
-return_error:
-       mvi     SINDEX, SCB_LIST_NULL   ret;
-dequeue_disc_scb:
-       mov     SCBPTR, DISCONNECTED_SCBH;
-/*
- * If we have a residual, then we are in the middle of some I/O
- * and we have to send this SCB back up to the kernel so that the
- * saved data pointers and residual information isn't lost.
- */
-       test    SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
-       and     SCB_CONTROL, ~MUST_DMAUP_SCB;
-       jmp     dma_up_scb;
-       test    SCB_RESID_SGCNT,0xff    jnz dma_up_scb;
-       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
-dma_up_scb:
-       mvi     DMAPARAMS, FIFORESET;
-       mov     SCB_TAG         call dma_scb;
-unlink_disc_scb:
-       /* jmp instead of call since we want to return anyway */
-       mov     SCBPTR  jmp rem_scb_from_disc_list;
-dequeue_free_scb:
-       mov     SCBPTR, FREE_SCBH;
-       mov     FREE_SCBH, SCB_NEXT ret;
-
-add_scb_to_disc_list:
-/*
- * Link this SCB into the DISCONNECTED list.  This list holds the
- * candidates for paging out an SCB if one is needed for a new command.
- * Modifying the disconnected list is a critical(pause dissabled) section.
- */
-       mvi     SCB_PREV, SCB_LIST_NULL;
-       mov     SCB_NEXT, DISCONNECTED_SCBH;
-       mov     DISCONNECTED_SCBH, SCBPTR;
-       cmp     SCB_NEXT,SCB_LIST_NULL je return;
-       mov     SCBPTR,SCB_NEXT;
-       mov     SCB_PREV,DISCONNECTED_SCBH;
-       mov     SCBPTR,DISCONNECTED_SCBH ret;
-.endif
diff --git a/drivers/scsi/aic7xxx/aic7xxx_asm.c b/drivers/scsi/aic7xxx/aic7xxx_asm.c
deleted file mode 100644 (file)
index 7dc26c0..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Aic7xxx SCSI host adapter firmware asssembler
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: aic7xxx_asm.c,v 1.16 1997/03/18 19:18:39 gibbs Exp $
- */
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include "aic7xxx_asm.h"
-#include "symbol.h"
-#include "sequencer.h"
-
-static void usage __P((void));
-static void back_patch __P((void));
-static void output_code __P((FILE *ofile));
-static void output_listing __P((FILE *listfile, char *ifilename,
-                               char *options));
-static struct patch *next_patch __P((struct patch *cur_patch, int options,
-                                    int instrptr));
-
-struct path_list search_path;
-int includes_search_curdir;
-char *appname;
-FILE *ofile;
-char *ofilename;
-
-static STAILQ_HEAD(,instruction) seq_program;
-static STAILQ_HEAD(, patch) patch_list;
-symlist_t patch_options;
-
-#if DEBUG
-extern int yy_flex_debug;
-extern int yydebug;
-#endif
-extern FILE *yyin;
-extern int yyparse __P((void));
-
-int
-main(argc, argv)
-       int argc;
-       char *argv[];
-{
-       extern char *optarg;
-       extern int optind;
-       int ch;
-       int  retval;
-       char *inputfilename;
-       char *regfilename;
-       FILE *regfile;
-       char *listfilename;
-       FILE *listfile;
-       char *options;
-
-       SLIST_INIT(&search_path);
-       STAILQ_INIT(&seq_program);
-       STAILQ_INIT(&patch_list);
-       SLIST_INIT(&patch_options);
-       includes_search_curdir = 1;
-       appname = *argv;
-       regfile = NULL;
-       listfile = NULL;
-       options = NULL;
-#if DEBUG
-       yy_flex_debug = 0;
-#endif
-       while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != EOF) {
-               switch(ch) {
-               case 'd':
-#if DEBUG
-                       if (strcmp(optarg, "s") == 0)
-                               yy_flex_debug = 1;
-                       else if (strcmp(optarg, "p") == 0)
-                               yydebug = 1;
-#else
-                       stop("-d: Assembler not built with debugging "
-                            "information", EX_SOFTWARE);
-#endif
-                       break;
-               case 'l':
-                       /* Create a program listing */
-                       if ((listfile = fopen(optarg, "w")) == NULL) {
-                               perror(optarg);
-                               stop(NULL, EX_CANTCREAT);
-                       }
-                       listfilename = optarg;
-                       break;
-               case 'n':
-                       /* Don't complain about the -nostdinc directrive */
-                       if (strcmp(optarg, "ostdinc")) {
-                               fprintf(stderr, "%s: Unknown option -%c%s\n",
-                                       appname, ch, optarg);
-                               usage();
-                               /* NOTREACHED */
-                       }
-                       break;
-               case 'o':
-                       if ((ofile = fopen(optarg, "w")) == NULL) {
-                               perror(optarg);
-                               stop(NULL, EX_CANTCREAT);
-                       }
-                       ofilename = optarg;
-                       break;
-               case 'O':
-                       /* Patches to include in the listing */
-                       options = optarg;
-                       break;
-               case 'r':
-                       if ((regfile = fopen(optarg, "w")) == NULL) {
-                               perror(optarg);
-                               stop(NULL, EX_CANTCREAT);
-                       }
-                       regfilename = optarg;
-                       break;
-               case 'I':
-               {
-                       path_entry_t include_dir;
-
-                       if (strcmp(optarg, "-") == 0) {
-                               if (includes_search_curdir == 0) {
-                                       fprintf(stderr, "%s: Warning - '-I-' "
-                                                       "specified multiple "
-                                                       "times\n", appname);
-                               }
-                               includes_search_curdir = 0;
-                               for (include_dir = search_path.slh_first;
-                                    include_dir != NULL;
-                                    include_dir = include_dir->links.sle_next)
-                                       /*
-                                        * All entries before a '-I-' only
-                                        * apply to includes specified with
-                                        * quotes instead of "<>".
-                                        */
-                                       include_dir->quoted_includes_only = 1;
-                       } else {
-                               include_dir =
-                                   (path_entry_t)malloc(sizeof(*include_dir));
-                               if (include_dir == NULL) {
-                                       perror(optarg);
-                                       stop(NULL, EX_OSERR);
-                               }
-                               include_dir->directory = strdup(optarg);
-                               if (include_dir->directory == NULL) {
-                                       perror(optarg);
-                                       stop(NULL, EX_OSERR);
-                               }
-                               include_dir->quoted_includes_only = 0;
-                               SLIST_INSERT_HEAD(&search_path, include_dir,
-                                                 links);
-                       }
-                       break;
-               }
-               case '?':
-               default:
-                       usage();
-                       /* NOTREACHED */
-               }
-       }
-       argc -= optind;
-       argv += optind;
-
-       if (argc != 1) {
-               fprintf(stderr, "%s: No input file specifiled\n", appname);
-               usage();
-               /* NOTREACHED */
-       }
-
-       symtable_open();
-       inputfilename = *argv;
-       include_file(*argv, SOURCE_FILE);
-       retval = yyparse();
-       if (retval == 0) {
-               back_patch();
-               if (ofile != NULL)
-                       output_code(ofile);
-               if (regfile != NULL)
-                       symtable_dump(regfile);
-               if (listfile != NULL)
-                       output_listing(listfile, inputfilename, options);
-       }
-
-       stop(NULL, 0);
-       /* NOTREACHED */
-       return (0);
-}
-
-static void
-usage()
-{
-
-       (void)fprintf(stderr,
-"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
-                       [-r register_output_file] [-l program_list_file]
-                       [-O option_name[|options_name2]] input_file\n",
-                       appname);
-       exit(EX_USAGE);
-}
-
-static void
-back_patch()
-{
-       struct instruction *cur_instr;
-
-       for(cur_instr = seq_program.stqh_first;
-           cur_instr != NULL;
-           cur_instr = cur_instr->links.stqe_next) {
-               if (cur_instr->patch_label != NULL) {
-                       struct ins_format3 *f3_instr;
-                       u_int address;
-
-                       if (cur_instr->patch_label->type != LABEL) {
-                               char buf[255];
-
-                               snprintf(buf, sizeof(buf),
-                                        "Undefined label %s",
-                                        cur_instr->patch_label->name);
-                               stop(buf, EX_DATAERR);
-                               /* NOTREACHED */
-                       }
-                       f3_instr = &cur_instr->format.format3;
-                       address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8)
-                               | f3_instr->address;
-                       address += cur_instr->patch_label->info.linfo->address;
-                       f3_instr->opcode_addr &= ~ADDR_HIGH_BIT;
-                       f3_instr->opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
-                       f3_instr->address = address & 0xFF;
-               }
-       }
-}
-
-static void
-output_code(ofile)
-       FILE *ofile;
-{
-       struct instruction *cur_instr;
-       patch_t *cur_patch;
-       symbol_node_t *cur_node;
-       int instrcount;
-
-       instrcount = 0;
-       fprintf(ofile,
-"/*
-  * DO NOT EDIT - This file is automatically generated.
-  */\n");
-
-       fprintf(ofile, "static u_int8_t seqprog[] = {\n");
-       for(cur_instr = seq_program.stqh_first;
-           cur_instr != NULL;
-           cur_instr = cur_instr->links.stqe_next) {
-               fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
-                       cur_instr->format.bytes[0],
-                       cur_instr->format.bytes[1],
-                       cur_instr->format.bytes[2],
-                       cur_instr->format.bytes[3]);
-               instrcount++;
-       }
-       fprintf(ofile, "};\n");
-
-       /*
-        *  Output the patch list, option definitions first.
-        */
-       for(cur_node = patch_options.slh_first;
-           cur_node != NULL;
-           cur_node = cur_node->links.sle_next) {
-               fprintf(ofile, "#define\t%-16s\t0x%x\n", cur_node->symbol->name,
-                       cur_node->symbol->info.condinfo->value);
-       }
-
-       fprintf(ofile,
-"struct patch {
-       int     options;
-       int     negative;
-       int     begin;
-       int     end;
-} patches[] = {\n");
-
-       for(cur_patch = patch_list.stqh_first;
-           cur_patch != NULL;
-           cur_patch = cur_patch->links.stqe_next)
-
-               fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x },\n",
-                       cur_patch->options, cur_patch->negative, cur_patch->begin,
-                       cur_patch->end);
-
-       fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x }\n};\n",
-               0, 0, 0, 0);
-       
-       fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
-}
-
-void
-output_listing(listfile, ifilename, patches)
-       FILE *listfile;
-       char *ifilename;
-       char *patches;
-{
-       FILE *ifile;
-       int line;
-       struct instruction *cur_instr;
-       int instrcount;
-       int instrptr;
-       char buf[1024];
-       patch_t *cur_patch;
-       char *option_spec;
-       int options;
-
-       instrcount = 0;
-       instrptr = 0;
-       line = 1;
-       options = 1; /* All code outside of patch blocks */
-       if ((ifile = fopen(ifilename, "r")) == NULL) {
-               perror(ifilename);
-               stop(NULL, EX_DATAERR);
-       }
-
-       /*
-        * Determine which options to apply to this listing.
-        */
-       while ((option_spec = strsep(&patches, "|")) != NULL) {
-               symbol_t *symbol;
-
-               symbol = symtable_get(option_spec);
-               if (symbol->type != CONDITIONAL) {
-                       stop("Invalid option specified in patch list for "
-                            "program listing", EX_USAGE);
-                       /* NOTREACHED */
-               }
-               options |= symbol->info.condinfo->value;
-       }
-
-       cur_patch = patch_list.stqh_first;
-       for(cur_instr = seq_program.stqh_first;
-           cur_instr != NULL;
-           cur_instr = cur_instr->links.stqe_next,instrcount++) {
-
-               cur_patch = next_patch(cur_patch, options, instrcount);
-               if (cur_patch
-                && cur_patch->begin <= instrcount
-                && cur_patch->end > instrcount)
-                       /* Don't count this instruction as it is in a patch
-                        * that was removed.
-                        */
-                        continue;
-
-               while (line < cur_instr->srcline) {
-                       fgets(buf, sizeof(buf), ifile);
-                               fprintf(listfile, "\t\t%s", buf);
-                               line++;
-               }
-               fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
-                       cur_instr->format.bytes[0],
-                       cur_instr->format.bytes[1],
-                       cur_instr->format.bytes[2],
-                       cur_instr->format.bytes[3]);
-               fgets(buf, sizeof(buf), ifile);
-               fprintf(listfile, "\t%s", buf);
-               line++;
-               instrptr++;
-       }
-       /* Dump the remainder of the file */
-       while(fgets(buf, sizeof(buf), ifile) != NULL)
-               fprintf(listfile, "\t\t%s", buf);
-
-       fclose(ifile);
-}
-
-static struct patch *
-next_patch(cur_patch, options, instrptr)
-       struct patch *cur_patch;
-       int     options;
-       int     instrptr;
-{
-       while(cur_patch != NULL) {
-               if (((cur_patch->options & options) != 0
-                  && cur_patch->negative == FALSE)
-                || ((cur_patch->options & options) == 0
-                  && cur_patch->negative == TRUE)
-                || (instrptr >= cur_patch->end)) {
-                       /*
-                        * Either we want to keep this section of code,
-                        * or we have consumed this patch. Skip to the
-                        * next patch.
-                        */
-                       cur_patch = cur_patch->links.stqe_next;
-               } else
-                       /* Found an okay patch */
-                       break;
-       }
-       return (cur_patch);
-}
-
-/*
- * Print out error information if appropriate, and clean up before
- * terminating the program.
- */
-void
-stop(string, err_code)
-       const char *string;
-       int  err_code;
-{
-       if (string != NULL) {
-               fprintf(stderr, "%s: ", appname);
-               if (yyfilename != NULL) {
-                       fprintf(stderr, "Stopped at file %s, line %d - ",
-                               yyfilename, yylineno);
-               }
-               fprintf(stderr, "%s\n", string);
-       }
-
-       if (ofile != NULL) {
-               fclose(ofile);
-               if (err_code != 0) {
-                       fprintf(stderr, "%s: Removing %s due to error\n",
-                               appname, ofilename);
-                       unlink(ofilename);
-               }
-       }
-
-       symlist_free(&patch_options);
-       symtable_close();
-
-       exit(err_code);
-}
-
-struct instruction *
-seq_alloc()
-{
-       struct instruction *new_instr;
-
-       new_instr = (struct instruction *)malloc(sizeof(struct instruction));
-       if (new_instr == NULL)
-               stop("Unable to malloc instruction object", EX_SOFTWARE);
-       memset(new_instr, 0, sizeof(*new_instr));
-       STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
-       new_instr->srcline = yylineno;
-       return new_instr;
-}
-
-patch_t *
-patch_alloc()
-{
-       patch_t *new_patch;
-
-       new_patch = (patch_t *)malloc(sizeof(patch_t));
-       if (new_patch == NULL)
-               stop("Unable to malloc patch object", EX_SOFTWARE);
-       memset(new_patch, 0, sizeof(*new_patch));
-       STAILQ_INSERT_TAIL(&patch_list, new_patch, links);
-       return new_patch;
-}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_asm.h b/drivers/scsi/aic7xxx/aic7xxx_asm.h
deleted file mode 100644 (file)
index 1c9424b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: aic7xxx_asm.h,v 1.2 1997/03/16 07:28:30 gibbs Exp $
- */
-
-#include "bsd_q.h"
-#include <sys/queue.h>
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-typedef struct path_entry {
-       char    *directory;
-       int     quoted_includes_only;
-       SLIST_ENTRY(path_entry) links;
-} *path_entry_t;
-
-typedef enum {  
-       QUOTED_INCLUDE,
-       BRACKETED_INCLUDE,
-       SOURCE_FILE
-} include_type;
-
-SLIST_HEAD(path_list, path_entry);
-
-extern struct path_list search_path;
-extern struct symlist patch_options;
-extern int includes_search_curdir;             /* False if we've seen -I- */
-extern char *appname;
-extern int yylineno;
-extern char *yyfilename;
-
-void stop __P((const char *errstring, int err_code));
-void include_file __P((char *file_name, include_type type));
-struct instruction *seq_alloc __P((void));
-struct patch *patch_alloc __P((void));
diff --git a/drivers/scsi/aic7xxx/bsd_q.h b/drivers/scsi/aic7xxx/bsd_q.h
deleted file mode 100644 (file)
index 5187335..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/* 
- * Copyright (c) 1991, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *     @(#)queue.h     8.3 (Berkeley) 12/13/93
- */
-
-/*
- * Define the BSD singly linked queues which Linux doesn't
- * define (yet).
- */
-
-#include <sys/queue.h>
-
-#if !defined(SLIST_HEAD) && !defined(__BSD_Q__)
-
-#define __BSD_Q__
-
-#define SLIST_HEAD(name, type)                                         \
-struct name {                                                          \
-       struct type *slh_first; /* first element */                     \
-}
-#define SLIST_ENTRY(type)                                              \
-struct {                                                               \
-       struct type *sle_next;  /* next element */                      \
-}
-/*
- * Singly-linked List functions.
- */
-#define        SLIST_EMPTY(head)       ((head)->slh_first == NULL)
-
-#define        SLIST_FIRST(head)       ((head)->slh_first)
-
-#define SLIST_INIT(head) {                                             \
-       (head)->slh_first = NULL;                                       \
-}
-
-#define SLIST_INSERT_AFTER(slistelm, elm, field) {                     \
-       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
-       (slistelm)->field.sle_next = (elm);                             \
-}
-
-#define SLIST_INSERT_HEAD(head, elm, field) {                          \
-       (elm)->field.sle_next = (head)->slh_first;                      \
-       (head)->slh_first = (elm);                                      \
-}
-
-#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
-
-#define SLIST_REMOVE_HEAD(head, field) {                               \
-       (head)->slh_first = (head)->slh_first->field.sle_next;          \
-}
-
-#define SLIST_REMOVE(head, elm, type, field) {                         \
-       if ((head)->slh_first == (elm)) {                               \
-               SLIST_REMOVE_HEAD((head), field);                       \
-       }                                                               \
-       else {                                                          \
-               struct type *curelm = (head)->slh_first;                \
-               while( curelm->field.sle_next != (elm) )                \
-                       curelm = curelm->field.sle_next;                \
-               curelm->field.sle_next =                                \
-                   curelm->field.sle_next->field.sle_next;             \
-       }                                                               \
-}
-
-/*
- * Singly-linked Tail queue definitions.
- */
-#define STAILQ_HEAD(name, type)                                                \
-struct name {                                                          \
-       struct type *stqh_first;/* first element */                     \
-       struct type **stqh_last;/* addr of last next element */         \
-}
-
-#define STAILQ_ENTRY(type)                                             \
-struct {                                                               \
-       struct type *stqe_next; /* next element */                      \
-}
-
-/*
- * Singly-linked Tail queue functions.
- */
-#define        STAILQ_INIT(head) {                                             \
-       (head)->stqh_first = NULL;                                      \
-       (head)->stqh_last = &(head)->stqh_first;                        \
-}
-
-#define STAILQ_INSERT_HEAD(head, elm, field) {                         \
-       if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)      \
-               (head)->stqh_last = &(elm)->field.stqe_next;            \
-       (head)->stqh_first = (elm);                                     \
-}
-
-#define STAILQ_INSERT_TAIL(head, elm, field) {                         \
-       (elm)->field.stqe_next = NULL;                                  \
-       *(head)->stqh_last = (elm);                                     \
-       (head)->stqh_last = &(elm)->field.stqe_next;                    \
-}
-
-#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) {                 \
-       if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\
-               (head)->stqh_last = &(elm)->field.stqe_next;            \
-       (tqelm)->field.stqe_next = (elm);                               \
-}
-
-#define STAILQ_REMOVE_HEAD(head, field) {                              \
-       if (((head)->stqh_first =                                       \
-            (head)->stqh_first->field.stqe_next) == NULL)              \
-               (head)->stqh_last = &(head)->stqh_first;                \
-}
-
-#define STAILQ_REMOVE(head, elm, type, field) {                                \
-       if ((head)->stqh_first == (elm)) {                              \
-               STAILQ_REMOVE_HEAD(head, field);                        \
-       }                                                               \
-       else {                                                          \
-               struct type *curelm = (head)->stqh_first;               \
-               while( curelm->field.stqe_next != (elm) )               \
-                       curelm = curelm->field.stqe_next;               \
-               if((curelm->field.stqe_next =                           \
-                   curelm->field.stqe_next->field.stqe_next) == NULL)  \
-                       (head)->stqh_last = &(curelm)->field.stqe_next; \
-       }                                                               \
-}
-
-#endif
diff --git a/drivers/scsi/aic7xxx/gram.y b/drivers/scsi/aic7xxx/gram.y
deleted file mode 100644 (file)
index 146e8a7..0000000
+++ /dev/null
@@ -1,1305 +0,0 @@
-%{
-/*
- * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: gram.y,v 1.1 1997/03/16 07:08:16 gibbs Exp $
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-
-#include <sys/types.h>
-
-#include "bsd_q.h"
-
-#include "aic7xxx_asm.h"
-#include "symbol.h"
-#include "sequencer.h"
-
-int yylineno;
-char *yyfilename;
-static symbol_t *cur_symbol;
-static symtype cur_symtype;
-static symbol_t *accumulator;
-static symbol_ref_t allones;
-static symbol_ref_t allzeros;
-static symbol_ref_t none;
-static symbol_ref_t sindex;
-static int instruction_ptr;
-static int sram_or_scb_offset;
-static patch_t *cur_patch;
-
-static void process_bitmask __P((int mask_type, symbol_t *sym, int mask));
-static void initialize_symbol __P((symbol_t *symbol));
-static void process_register __P((symbol_t **p_symbol));
-static void format_1_instr __P((int opcode, symbol_ref_t *dest,
-                               expression_t *immed, symbol_ref_t *src,
-                               int ret));
-static void format_2_instr __P((int opcode, symbol_ref_t *dest,
-                               expression_t *places, symbol_ref_t *src,
-                               int ret));
-static void format_3_instr __P((int opcode, symbol_ref_t *src,
-                               expression_t *immed, symbol_ref_t *address));
-static void test_readable_symbol __P((symbol_t *symbol));
-static void test_writable_symbol __P((symbol_t *symbol));
-static void type_check __P((symbol_t *symbol, expression_t *expression,
-                           int and_op));
-static void make_expression __P((expression_t *immed, int value));
-static void add_conditional __P((symbol_t *symbol));
-
-#define YYDEBUG 1
-#define SRAM_SYMNAME "SRAM_BASE"
-#define SCB_SYMNAME "SCB_BASE"
-%}
-
-%union {
-       int             value;
-       char            *str;
-       symbol_t        *sym;
-       symbol_ref_t    sym_ref;
-       expression_t    expression;
-}
-
-%token T_REGISTER
-
-%token <value> T_CONST
-
-%token T_SCB
-
-%token T_SRAM
-
-%token T_ALIAS
-
-%token T_SIZE
-
-%token <value> T_ADDRESS
-
-%token T_ACCESS_MODE
-
-%token <value> T_MODE
-
-%token T_BIT
-
-%token T_MASK
-
-%token <value> T_NUMBER
-
-%token <str> T_PATH
-
-%token T_EOF T_INCLUDE 
-
-%token <value> T_SHR T_SHL T_ROR T_ROL
-
-%token <value> T_MVI T_MOV T_CLR
-
-%token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
-
-%token <value> T_ADD T_ADC
-
-%token <value> T_INC T_DEC
-
-%token <value> T_STC T_CLC
-
-%token <value> T_CMP T_XOR
-
-%token <value> T_TEST T_AND
-
-%token <value> T_OR
-
-%token T_RET
-
-%token T_NOP
-
-%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX
-
-%token T_A
-
-%token <sym> T_SYMBOL
-
-%token T_NL
-
-%token T_IF T_ELSE T_ENDIF
-
-%type <sym_ref> reg_symbol address destination source opt_source
-
-%type <expression> expression immediate immediate_or_a
-
-%type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
-
-%left '|'
-%left '&'
-%left '+' '-'
-%right '~'
-%nonassoc UMINUS
-%%
-
-program:
-       include
-|      program include
-|      register
-|      program register
-|      constant
-|      program constant
-|      scratch_ram
-|      program scratch_ram
-|      scb
-|      program scb
-|      label
-|      program label
-|      conditional
-|      program conditional
-|      code
-|      program code
-;
-
-include:
-       T_INCLUDE '<' T_PATH '>'
-       { include_file($3, BRACKETED_INCLUDE); }
-|      T_INCLUDE '"' T_PATH '"'
-       { include_file($3, QUOTED_INCLUDE); }
-;
-
-register:
-       T_REGISTER { cur_symtype = REGISTER; } reg_definition
-;
-
-reg_definition:
-       T_SYMBOL '{'
-               {
-                       if ($1->type != UNINITIALIZED) {
-                               stop("Register multiply defined", EX_DATAERR);
-                               /* NOTREACHED */
-                       }
-                       cur_symbol = $1; 
-                       cur_symbol->type = cur_symtype;
-                       initialize_symbol(cur_symbol);
-               }
-               reg_attribute_list
-       '}'
-               {                    
-                       /*
-                        * Default to allowing everything in for registers
-                        * with no bit or mask definitions.
-                        */
-                       if (cur_symbol->info.rinfo->valid_bitmask == 0)
-                               cur_symbol->info.rinfo->valid_bitmask = 0xFF;
-
-                       if (cur_symbol->info.rinfo->size == 0)
-                               cur_symbol->info.rinfo->size = 1;
-
-                       /*
-                        * This might be useful for registers too.
-                        */
-                       if (cur_symbol->type != REGISTER) {
-                               if (cur_symbol->info.rinfo->address == 0)
-                                       cur_symbol->info.rinfo->address =
-                                           sram_or_scb_offset;
-                               sram_or_scb_offset +=
-                                   cur_symbol->info.rinfo->size;
-                       }
-                       cur_symbol = NULL;
-               }
-;
-
-reg_attribute_list:
-       reg_attribute
-|      reg_attribute_list reg_attribute
-;
-
-reg_attribute:         
-       reg_address
-|      size
-|      access_mode
-|      bit_defn
-|      mask_defn
-|      alias
-|      accumulator
-|      allones
-|      allzeros
-|      none
-|      sindex
-;
-
-reg_address:
-       T_ADDRESS T_NUMBER
-       {
-               cur_symbol->info.rinfo->address = $2;
-       }
-;
-
-size:
-       T_SIZE T_NUMBER
-       {
-               cur_symbol->info.rinfo->size = $2;
-       }
-;
-
-access_mode:
-       T_ACCESS_MODE T_MODE
-       {
-               cur_symbol->info.rinfo->mode = $2;
-       }
-;
-
-bit_defn:
-       T_BIT T_SYMBOL T_NUMBER
-       {
-               process_bitmask(BIT, $2, $3);
-       }
-;
-
-mask_defn:
-       T_MASK T_SYMBOL expression
-       {
-               process_bitmask(MASK, $2, $3.value);
-       }
-;
-
-alias:
-       T_ALIAS T_SYMBOL
-       {
-               if ($2->type != UNINITIALIZED) {
-                       stop("Re-definition of register alias",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               $2->type = ALIAS;
-               initialize_symbol($2);
-               $2->info.ainfo->parent = cur_symbol;
-       }
-;
-
-accumulator:
-       T_ACCUM
-       {
-               if (accumulator != NULL) {
-                       stop("Only one accumulator definition allowed",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               accumulator = cur_symbol;
-       }
-;
-
-allones:
-       T_ALLONES
-       {
-               if (allones.symbol != NULL) {
-                       stop("Only one definition of allones allowed",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               allones.symbol = cur_symbol;
-       }
-;
-
-allzeros:
-       T_ALLZEROS
-       {
-               if (allzeros.symbol != NULL) {
-                       stop("Only one definition of allzeros allowed",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               allzeros.symbol = cur_symbol;
-       }
-;
-
-none:
-       T_NONE
-       {
-               if (none.symbol != NULL) {
-                       stop("Only one definition of none allowed",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               none.symbol = cur_symbol;
-       }
-;
-
-sindex:
-       T_SINDEX
-       {
-               if (sindex.symbol != NULL) {
-                       stop("Only one definition of sindex allowed",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               sindex.symbol = cur_symbol;
-       }
-;
-
-expression:
-       expression '|' expression
-       {
-                $$.value = $1.value | $3.value;
-                symlist_merge(&$$.referenced_syms,
-                              &$1.referenced_syms,
-                              &$3.referenced_syms);
-       }
-|      expression '&' expression
-       {
-               $$.value = $1.value & $3.value;
-               symlist_merge(&$$.referenced_syms,
-                              &$1.referenced_syms,
-                              &$3.referenced_syms);
-       }
-|      expression '+' expression
-       {
-               $$.value = $1.value + $3.value;
-               symlist_merge(&$$.referenced_syms,
-                              &$1.referenced_syms,
-                              &$3.referenced_syms);
-       }
-|      expression '-' expression
-       {
-               $$.value = $1.value - $3.value;
-               symlist_merge(&($$.referenced_syms),
-                              &($1.referenced_syms),
-                              &($3.referenced_syms));
-       }
-|      '(' expression ')'
-       {
-               $$ = $2;
-       }
-|      '~' expression
-       {
-               $$ = $2;
-               $$.value = (~$$.value) & 0xFF;
-       }
-|      '-' expression %prec UMINUS
-       {
-               $$ = $2;
-               $$.value = -$$.value;
-       }
-|      T_NUMBER
-       {
-               $$.value = $1;
-               SLIST_INIT(&$$.referenced_syms);
-       }
-|      T_SYMBOL
-       {
-               symbol_t *symbol;
-
-               symbol = $1;
-               switch (symbol->type) {
-               case ALIAS:
-                       symbol = $1->info.ainfo->parent;
-               case REGISTER:
-               case SCBLOC:
-               case SRAMLOC:
-                       $$.value = symbol->info.rinfo->address;
-                       break;
-               case MASK:
-               case BIT:
-                       $$.value = symbol->info.minfo->mask;
-                       break;
-               case CONST:
-                       $$.value = symbol->info.cinfo->value;
-                       break;
-               case UNINITIALIZED:
-               default:
-               {
-                       char buf[255];
-
-                       snprintf(buf, sizeof(buf),
-                                "Undefined symbol %s referenced",
-                                symbol->name);
-                       stop(buf, EX_DATAERR);
-                       /* NOTREACHED */
-                       break;
-               }
-               }
-               SLIST_INIT(&$$.referenced_syms);
-               symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
-       }
-;
-
-constant:
-       T_CONST T_SYMBOL T_NUMBER       
-       {
-               if ($2->type != UNINITIALIZED) {
-                       stop("Re-definition of constant variable",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               $2->type = CONST;
-               initialize_symbol($2);
-               $2->info.cinfo->value = $3;
-               $2->info.cinfo->define = $1;
-       }
-;
-
-scratch_ram:
-       T_SRAM '{'
-               {
-                       cur_symbol = symtable_get(SRAM_SYMNAME);
-                       cur_symtype = SRAMLOC;
-                       if (cur_symbol->type != UNINITIALIZED) {
-                               stop("Only one SRAM definition allowed",
-                                    EX_DATAERR);
-                               /* NOTREACHED */
-                       }
-                       cur_symbol->type = SRAMLOC;
-                       initialize_symbol(cur_symbol);
-               }
-               reg_address
-               {
-                       sram_or_scb_offset = cur_symbol->info.rinfo->address;
-               }
-               scb_or_sram_reg_list
-       '}'
-               {
-                       cur_symbol = NULL;
-               }
-;
-
-scb:
-       T_SCB '{'
-               {
-                       cur_symbol = symtable_get(SCB_SYMNAME);
-                       cur_symtype = SCBLOC;
-                       if (cur_symbol->type != UNINITIALIZED) {
-                               stop("Only one SRAM definition allowed",
-                                    EX_SOFTWARE);
-                               /* NOTREACHED */
-                       }
-                       cur_symbol->type = SCBLOC;
-                       initialize_symbol(cur_symbol);
-               }
-               reg_address
-               {
-                       sram_or_scb_offset = cur_symbol->info.rinfo->address;
-               }
-               scb_or_sram_reg_list
-       '}'
-               {
-                       cur_symbol = NULL;
-               }
-;
-
-scb_or_sram_reg_list:
-       reg_definition
-|      scb_or_sram_reg_list reg_definition
-;
-
-reg_symbol:
-       T_SYMBOL
-       {
-               process_register(&$1);
-               $$.symbol = $1;
-               $$.offset = 0;
-       }
-|      T_SYMBOL '[' T_NUMBER ']'
-       {
-               process_register(&$1);
-               if (($3 + 1) > $1->info.rinfo->size) {
-                       stop("Accessing offset beyond range of register",
-                            EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               $$.symbol = $1;
-               $$.offset = $3;
-       }
-|      T_A
-       {
-               if (accumulator == NULL) {
-                       stop("No accumulator has been defined", EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               $$.symbol = accumulator;
-               $$.offset = 0;
-       }
-;
-
-destination:
-       reg_symbol
-       {
-               test_writable_symbol($1.symbol);
-               $$ = $1;
-       }
-;
-
-immediate:
-       expression
-       { $$ = $1; }
-;
-
-immediate_or_a:
-       expression
-       {
-               $$ = $1;
-       }
-|      T_A
-       {
-               SLIST_INIT(&$$.referenced_syms);
-               $$.value = 0;
-       }
-;
-
-source:
-       reg_symbol
-       {
-               test_readable_symbol($1.symbol);
-               $$ = $1;
-       }
-;
-
-opt_source:
-       {
-               $$.symbol = NULL;
-               $$.offset = 0;
-       }
-|      ',' source
-       { $$ = $2; }
-;
-
-ret:
-       { $$ = 0; }
-|      T_RET
-       { $$ = 1; }
-;
-
-label:
-       T_SYMBOL ':'
-       {
-               if ($1->type != UNINITIALIZED) {
-                       stop("Program label multiply defined", EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               $1->type = LABEL;
-               initialize_symbol($1);
-               $1->info.linfo->address = instruction_ptr;
-       }
-;
-
-address:
-       T_SYMBOL
-       {
-               $$.symbol = $1;
-               $$.offset = 0;
-       }
-|      T_SYMBOL '+' T_NUMBER
-       {
-               $$.symbol = $1;
-               $$.offset = $3;
-       }
-|      T_SYMBOL '-' T_NUMBER
-       {
-               $$.symbol = $1;
-               $$.offset = -$3;
-       }
-|      '.'
-       {
-               $$.symbol = NULL;
-               $$.offset = 0;
-       }
-|      '.' '+' T_NUMBER
-       {
-               $$.symbol = NULL;
-               $$.offset = $3;
-       }
-|      '.' '-' T_NUMBER
-       {
-               $$.symbol = NULL;
-               $$.offset = -$3;
-       }
-;
-
-conditional:
-       T_IF
-       {
-               if (cur_patch != NULL) {
-                       stop("Nested .if directive", EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               cur_patch = patch_alloc();
-               cur_patch->begin = instruction_ptr;
-       }
-       option_list
-;
-
-conditional:
-       T_ELSE
-       {
-               patch_t *next_patch;
-
-               if (cur_patch == NULL) {
-                       stop(".else outsize of .if", EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               cur_patch->end = instruction_ptr;
-               next_patch = patch_alloc();
-               next_patch->options = cur_patch->options;
-               next_patch->negative = cur_patch->negative ? FALSE : TRUE;
-               cur_patch = next_patch;
-               cur_patch->begin = instruction_ptr;
-       }
-;
-
-conditional:
-       T_ENDIF
-       {
-               if (cur_patch == NULL) {
-                       stop(".endif outsize of .if", EX_DATAERR);
-                       /* NOTREACHED */
-               }
-               cur_patch->end = instruction_ptr;
-               cur_patch = NULL;
-       }
-;
-
-option_list:
-       '(' option_symbol_list ')'
-|      '!' option_list
-       {
-               cur_patch->negative = cur_patch->negative ? FALSE : TRUE;
-       }
-;
-
-option_symbol_list:
-       T_SYMBOL
-       {
-               add_conditional($1);
-       }
-|      option_list '|' T_SYMBOL
-       {
-               add_conditional($3);
-       }
-;
-
-f1_opcode:
-       T_AND { $$ = AIC_OP_AND; }
-|      T_XOR { $$ = AIC_OP_XOR; }
-|      T_ADD { $$ = AIC_OP_ADD; }
-|      T_ADC { $$ = AIC_OP_ADC; }
-;
-
-code:
-       f1_opcode destination ',' immediate_or_a opt_source ret ';'
-       {
-               format_1_instr($1, &$2, &$4, &$5, $6);
-       }
-;
-
-code:
-       T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
-       {
-               format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
-       }
-;
-
-code:
-       T_INC destination opt_source ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 1);
-               format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
-       }
-;
-
-code:
-       T_DEC destination opt_source ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, -1);
-               format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
-       }
-;
-
-code:
-       T_CLC ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, -1);
-               format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
-       }
-|      T_CLC T_MVI destination ',' immediate_or_a ret ';'
-       {
-               format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
-       }
-;
-
-code:
-       T_STC ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 1);
-               format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
-       }
-|      T_STC destination ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 1);
-               format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
-       }
-;
-
-code:
-       T_MOV destination ',' source ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 0xff);
-               format_1_instr(AIC_OP_AND, &$2, &immed, &$4, $5);
-       }
-;
-
-code:
-       T_MVI destination ',' immediate_or_a ret ';'
-       {
-               format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
-       }
-;
-
-code:
-       T_CLR destination ret ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 0xff);
-               format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
-       }
-;
-
-code:
-       T_NOP ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 0xff);
-               format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, FALSE);
-       }
-;
-
-code:
-       T_RET ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 0xff);
-               format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
-       }
-;
-
-       /*
-        * This grammer differs from the one in the aic7xxx
-        * reference manual since the grammer listed there is
-        * ambiguous and causes a shift/reduce conflict.
-        * It also seems more logical as the "immediate"
-        * argument is listed as the second arg like the
-        * other formats.
-        */
-
-f2_opcode:
-       T_SHL { $$ = AIC_OP_SHL; }
-|      T_SHR { $$ = AIC_OP_SHR; }
-|      T_ROL { $$ = AIC_OP_ROL; }
-|      T_ROR { $$ = AIC_OP_ROR; }
-;
-
-code:
-       f2_opcode destination ',' expression opt_source ret ';'
-       {
-               format_2_instr($1, &$2, &$4, &$5, $6);
-       }
-;
-
-jmp_jc_jnc_call:
-       T_JMP   { $$ = AIC_OP_JMP; }
-|      T_JC    { $$ = AIC_OP_JC; }
-|      T_JNC   { $$ = AIC_OP_JNC; }
-|      T_CALL  { $$ = AIC_OP_CALL; }
-;
-
-jz_jnz:
-       T_JZ    { $$ = AIC_OP_JZ; }
-|      T_JNZ   { $$ = AIC_OP_JNZ; }
-;
-
-je_jne:
-       T_JE    { $$ = AIC_OP_JE; }
-|      T_JNE   { $$ = AIC_OP_JNE; }
-;
-
-code:
-       jmp_jc_jnc_call address ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 0);
-               format_3_instr($1, &sindex, &immed, &$2);
-       }
-;
-
-code:
-       T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
-       {
-               format_3_instr($5, &$2, &$4, &$6);
-       }
-;
-
-code:
-       T_TEST source ',' immediate_or_a jz_jnz address ';'
-       {
-               format_3_instr($5, &$2, &$4, &$6);
-       }
-;
-
-code:
-       T_CMP source ',' immediate_or_a je_jne address ';'
-       {
-               format_3_instr($5, &$2, &$4, &$6);
-       }
-;
-
-code:
-       T_MOV source jmp_jc_jnc_call address ';'
-       {
-               expression_t immed;
-
-               make_expression(&immed, 0);
-               format_3_instr($3, &$2, &immed, &$4);
-       }
-;
-
-code:
-       T_MVI immediate jmp_jc_jnc_call address ';'
-       {
-               format_3_instr($3, &allzeros, &$2, &$4);
-       }
-;
-
-%%
-
-static void
-process_bitmask(mask_type, sym, mask)
-       int             mask_type;
-       symbol_t        *sym;
-       int             mask;
-{
-       /*
-        * Add the current register to its
-        * symbol list, if it already exists,
-        * warn if we are setting it to a
-        * different value, or in the bit to
-        * the "allowed bits" of this register.
-        */
-       if (sym->type == UNINITIALIZED) {
-               sym->type = mask_type;
-               initialize_symbol(sym);
-               if (mask_type == BIT) {
-                       if (mask == 0) {
-                               stop("Bitmask with no bits set", EX_DATAERR);
-                               /* NOTREACHED */
-                       }
-                       if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) {
-                               stop("Bitmask with more than one bit set",
-                                    EX_DATAERR);
-                               /* NOTREACHED */
-                       }
-               }
-               sym->info.minfo->mask = mask;
-       } else if (sym->type != mask_type) {
-               stop("Bit definition mirrors a definition of the same "
-                    " name, but a different type", EX_DATAERR);
-               /* NOTREACHED */
-       } else if (mask != sym->info.minfo->mask) {
-               stop("Bitmask redefined with a conflicting value", EX_DATAERR);
-               /* NOTREACHED */
-       }
-       /* Fail if this symbol is already listed */
-       if (symlist_search(&(sym->info.minfo->symrefs),
-                          cur_symbol->name) != NULL) {
-               stop("Bitmask defined multiple times for register", EX_DATAERR);
-               /* NOTREACHED */
-       }
-       symlist_add(&(sym->info.minfo->symrefs), cur_symbol,
-                   SYMLIST_INSERT_HEAD);
-       cur_symbol->info.rinfo->valid_bitmask |= mask;
-       cur_symbol->info.rinfo->typecheck_masks = TRUE;
-}
-
-static void
-initialize_symbol(symbol)
-       symbol_t *symbol;
-{
-       switch (symbol->type) {
-        case UNINITIALIZED:
-               stop("Call to initialize_symbol with type field unset",
-                    EX_SOFTWARE);
-               /* NOTREACHED */
-               break;
-        case REGISTER:
-        case SRAMLOC:
-        case SCBLOC:
-               symbol->info.rinfo =
-                   (struct reg_info *)malloc(sizeof(struct reg_info));
-               if (symbol->info.rinfo == NULL) {
-                       stop("Can't create register info", EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-               memset(symbol->info.rinfo, 0,
-                      sizeof(struct reg_info));
-               break;
-        case ALIAS:
-               symbol->info.ainfo =
-                   (struct alias_info *)malloc(sizeof(struct alias_info));
-               if (symbol->info.ainfo == NULL) {
-                       stop("Can't create alias info", EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-               memset(symbol->info.ainfo, 0,
-                      sizeof(struct alias_info));
-               break;
-        case MASK:
-        case BIT:
-               symbol->info.minfo =
-                   (struct mask_info *)malloc(sizeof(struct mask_info));
-               if (symbol->info.minfo == NULL) {
-                       stop("Can't create bitmask info", EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-               memset(symbol->info.minfo, 0, sizeof(struct mask_info));
-               SLIST_INIT(&(symbol->info.minfo->symrefs));
-               break;
-        case CONST:
-               symbol->info.cinfo =
-                   (struct const_info *)malloc(sizeof(struct const_info));
-               if (symbol->info.cinfo == NULL) {
-                       stop("Can't create alias info", EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-               memset(symbol->info.cinfo, 0,
-                      sizeof(struct const_info));
-               break;
-       case LABEL:
-               symbol->info.linfo =
-                   (struct label_info *)malloc(sizeof(struct label_info));
-               if (symbol->info.linfo == NULL) {
-                       stop("Can't create label info", EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-               memset(symbol->info.linfo, 0,
-                      sizeof(struct label_info));
-               break;
-       case CONDITIONAL:
-               symbol->info.condinfo =
-                   (struct cond_info *)malloc(sizeof(struct cond_info));
-               if (symbol->info.condinfo == NULL) {
-                       stop("Can't create conditional info", EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-               memset(symbol->info.condinfo, 0,
-                      sizeof(struct cond_info));
-               break;
-       default:
-               stop("Call to initialize_symbol with invalid symbol type",
-                    EX_SOFTWARE);
-               /* NOTREACHED */
-               break;
-       }
-}
-
-static void
-process_register(p_symbol)
-       symbol_t **p_symbol;
-{
-       char buf[255];
-       symbol_t *symbol = *p_symbol;
-
-       if (symbol->type == UNINITIALIZED) {
-               snprintf(buf, sizeof(buf), "Undefined register %s",
-                        symbol->name);
-               stop(buf, EX_DATAERR);
-               /* NOTREACHED */
-       } else if (symbol->type == ALIAS) {
-               *p_symbol = symbol->info.ainfo->parent;
-       } else if ((symbol->type != REGISTER)
-               && (symbol->type != SCBLOC)
-               && (symbol->type != SRAMLOC)) {
-               snprintf(buf, sizeof(buf),
-                        "Specified symbol %s is not a register",
-                        symbol->name);
-               stop(buf, EX_DATAERR);
-       }
-}
-
-static void
-format_1_instr(opcode, dest, immed, src, ret)
-       int          opcode;
-       symbol_ref_t *dest;
-       expression_t *immed;
-       symbol_ref_t *src;
-       int          ret;
-{
-       struct instruction *instr;
-       struct ins_format1 *f1_instr;
-
-       if (src->symbol == NULL)
-               src = dest;
-
-       /* Test register permissions */
-       test_writable_symbol(dest->symbol);
-       test_readable_symbol(src->symbol);
-
-       /* Ensure that immediate makes sense for this destination */
-       type_check(dest->symbol, immed, opcode);
-
-       /* Allocate sequencer space for the instruction and fill it out */
-       instr = seq_alloc();
-       f1_instr = &instr->format.format1;
-       f1_instr->opcode_ret = (opcode << 1) | (ret ? RETURN_BIT : 0);
-       f1_instr->destination = dest->symbol->info.rinfo->address
-                             + dest->offset;
-       f1_instr->source = src->symbol->info.rinfo->address
-                        + src->offset;
-       f1_instr->immediate = immed->value;
-       symlist_free(&immed->referenced_syms);
-       instruction_ptr++;
-}
-
-static void
-format_2_instr(opcode, dest, places, src, ret)
-       int          opcode;
-       symbol_ref_t *dest;
-       expression_t *places;
-       symbol_ref_t *src;
-       int          ret;
-{
-       struct instruction *instr;
-       struct ins_format2 *f2_instr;
-       u_int8_t shift_control;
-
-       if (src->symbol == NULL)
-               src = dest;
-
-       /* Test register permissions */
-       test_writable_symbol(dest->symbol);
-       test_readable_symbol(src->symbol);
-
-       /* Allocate sequencer space for the instruction and fill it out */
-       instr = seq_alloc();
-       f2_instr = &instr->format.format2;
-       f2_instr->opcode_ret = (AIC_OP_ROL << 1) | (ret ? RETURN_BIT : 0);
-       f2_instr->destination = dest->symbol->info.rinfo->address
-                             + dest->offset;
-       f2_instr->source = src->symbol->info.rinfo->address
-                        + src->offset;
-       if (places->value > 8 || places->value <= 0) {
-               stop("illegal shift value", EX_DATAERR);
-               /* NOTREACHED */
-       }
-       switch (opcode) {
-       case AIC_OP_SHL:
-               if (places->value == 8)
-                       shift_control = 0xf0;
-               else
-                       shift_control = (places->value << 4) | places->value;
-               break;
-       case AIC_OP_SHR:
-               if (places->value == 8) {
-                       shift_control = 0xf8;
-               } else {
-                       shift_control = (places->value << 4)
-                                     | (8 - places->value)
-                                     | 0x08;
-               }
-               break;
-       case AIC_OP_ROL:
-               shift_control = places->value & 0x7;
-               break;
-       case AIC_OP_ROR:
-               shift_control = (8 - places->value) | 0x08;
-               break;
-       default:
-               shift_control = 0; /* Quiet Compiler */
-               stop("Invalid shift operation specified", EX_SOFTWARE);
-               /* NOTREACHED */
-               break;
-       };
-       f2_instr->shift_control = shift_control;
-       symlist_free(&places->referenced_syms);
-       instruction_ptr++;
-}
-
-static void
-format_3_instr(opcode, src, immed, address)
-       int          opcode;
-       symbol_ref_t *src;
-       expression_t *immed;
-       symbol_ref_t *address;
-{
-       struct instruction *instr;
-       struct ins_format3 *f3_instr;
-       int addr;
-
-       /* Test register permissions */
-       test_readable_symbol(src->symbol);
-
-       /* Ensure that immediate makes sense for this source */
-       type_check(src->symbol, immed, opcode);
-
-       /* Allocate sequencer space for the instruction and fill it out */
-       instr = seq_alloc();
-       f3_instr = &instr->format.format3;
-       if (address->symbol == NULL) {
-               /* 'dot' referrence.  Use the current instruction pointer */
-               addr = instruction_ptr + address->offset;
-       } else if (address->symbol->type == UNINITIALIZED) {
-               /* forward reference */
-               addr = address->offset;
-               instr->patch_label = address->symbol;
-       } else
-               addr = address->symbol->info.linfo->address + address->offset;
-       f3_instr->opcode_addr = (opcode << 1)
-                             | ((addr >> 8) & 0x01);
-       f3_instr->address = addr & 0xff;
-       f3_instr->source = src->symbol->info.rinfo->address
-                        + src->offset;
-       f3_instr->immediate = immed->value;
-       symlist_free(&immed->referenced_syms);
-       instruction_ptr++;
-}
-
-static void
-test_readable_symbol(symbol)
-       symbol_t *symbol;
-{
-       if (symbol->info.rinfo->mode == WO) {
-               stop("Write Only register specified as source",
-                    EX_DATAERR);
-               /* NOTREACHED */
-       }
-}
-
-static void
-test_writable_symbol(symbol)
-       symbol_t *symbol;
-{
-       if (symbol->info.rinfo->mode == RO) {
-               stop("Read Only register specified as destination",
-                    EX_DATAERR);
-               /* NOTREACHED */
-       }
-}
-
-static void
-type_check(symbol, expression, opcode)
-       symbol_t     *symbol;
-       expression_t *expression;
-       int          opcode;
-{
-       symbol_node_t *node;
-       int and_op;
-       char buf[255];
-
-       and_op = FALSE;
-       if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
-               and_op = TRUE;
-       /*
-        * Make sure that we aren't attempting to write something
-        * that hasn't been defined.  If this is an and operation,
-        * this is a mask, so "undefined" bits are okay.
-        */
-       if (and_op == FALSE
-        && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
-               snprintf(buf, sizeof(buf),
-                        "Invalid bit(s) 0x%x in immediate written to %s",
-                        expression->value & ~symbol->info.rinfo->valid_bitmask,
-                        symbol->name);
-               stop(buf, EX_DATAERR);
-               /* NOTREACHED */
-       }
-
-       /*
-        * Now make sure that all of the symbols referenced by the
-        * expression are defined for this register.
-        */
-       if(symbol->info.rinfo->typecheck_masks != FALSE) {
-               for(node = expression->referenced_syms.slh_first;
-                   node != NULL;
-                   node = node->links.sle_next) {
-                       if ((node->symbol->type == MASK
-                         || node->symbol->type == BIT)
-                        && symlist_search(&node->symbol->info.minfo->symrefs,
-                                          symbol->name) == NULL) {
-                               snprintf(buf, sizeof(buf),
-                                        "Invalid bit or mask %s "
-                                        "for register %s",
-                                        node->symbol->name, symbol->name);
-                               stop(buf, EX_DATAERR);
-                               /* NOTREACHED */
-                       }
-               }
-       }
-}
-
-static void
-make_expression(immed, value)
-       expression_t *immed;
-       int          value;
-{
-       SLIST_INIT(&immed->referenced_syms);
-       immed->value = value & 0xff;
-}
-
-static void
-add_conditional(symbol)
-       symbol_t *symbol;
-{
-       static int numoptions = 1;
-
-       if (symbol->type == UNINITIALIZED) {
-               symbol->type = CONDITIONAL;
-               initialize_symbol(symbol);
-               symbol->info.condinfo->value = 0x01 << numoptions++;
-               symlist_add(&patch_options, symbol, SYMLIST_INSERT_HEAD);
-       } else if (symbol->type != CONDITIONAL) {
-               stop("Conditional symbol mirrors other symbol",
-                    EX_DATAERR);
-               /* NOTREACHED */
-       }
-       cur_patch->options |= symbol->info.condinfo->value;
-}
-
-void
-yyerror(string)
-       const char *string;
-{
-       stop(string, EX_DATAERR);
-}
diff --git a/drivers/scsi/aic7xxx/scan.l b/drivers/scsi/aic7xxx/scan.l
deleted file mode 100644 (file)
index 640d383..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-%{
-/*
- * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: scan.l,v 1.2 1997/03/16 17:31:59 bde Exp $
- */
-
-#include <sys/types.h>
-
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <sysexits.h>
-#include <sys/queue.h>
-
-#include "bsd_q.h"
-#include "aic7xxx_asm.h"
-#include "symbol.h"
-#include "y.tab.h"
-%}
-
-PATH           [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]*
-WORD           [A-Za-z_][-A-Za-z_0-9]*
-SPACE          [ \t]+
-
-%x COMMENT
-
-%%
-\n                     { ++yylineno; }
-"/*"                   { BEGIN COMMENT;  /* Enter comment eating state */ }
-<COMMENT>"/*"          { fprintf(stderr, "Warning! Comment within comment."); }
-<COMMENT>\n            { ++yylineno; }
-<COMMENT>[^*/\n]*      ;
-<COMMENT>"*"+[^*/\n]*  ;
-<COMMENT>"/"+[^*/\n]*  ;
-<COMMENT>"*"+"/"       { BEGIN INITIAL; }
-
-{SPACE}                        ;
-
-       /* Register/SCB/SRAM definition keywords */
-register               { return T_REGISTER; }
-const                  { yylval.value = FALSE; return T_CONST; }
-address                        { return T_ADDRESS; }
-access_mode            { return T_ACCESS_MODE; }
-RW|RO|WO               {
-                                if (strcmp(yytext, "RW") == 0)
-                                       yylval.value = RW;
-                                else if (strcmp(yytext, "RO") == 0)
-                                       yylval.value = RO;
-                                else
-                                       yylval.value = WO;
-                                return T_MODE;
-                       }
-bit                    { return T_BIT; }
-mask                   { return T_MASK; }
-alias                  { return T_ALIAS; }
-size                   { return T_SIZE; }
-scb                    { return T_SCB; }
-scratch_ram            { return T_SRAM; }
-accumulator            { return T_ACCUM; }
-allones                        { return T_ALLONES; }
-allzeros               { return T_ALLZEROS; }
-none                   { return T_NONE; }
-sindex                 { return T_SINDEX; }
-A                      { return T_A; }
-
-       /* Opcodes */
-shl                    { return T_SHL; }
-shr                    { return T_SHR; }
-ror                    { return T_ROR; }
-rol                    { return T_ROL; }
-mvi                    { return T_MVI; }
-mov                    { return T_MOV; }
-clr                    { return T_CLR; }
-jmp                    { return T_JMP; }
-jc                     { return T_JC;  }
-jnc                    { return T_JNC; }
-je                     { return T_JE;  }
-jne                    { return T_JNE; }
-jz                     { return T_JZ;  }
-jnz                    { return T_JNZ; }
-call                   { return T_CALL; }
-add                    { return T_ADD; }
-adc                    { return T_ADC; }
-inc                    { return T_INC; }
-dec                    { return T_DEC; }
-stc                    { return T_STC; }
-clc                    { return T_CLC; }
-cmp                    { return T_CMP; }
-xor                    { return T_XOR; }
-test                   { return T_TEST;}
-and                    { return T_AND; }
-or                     { return T_OR;  }
-ret                    { return T_RET; }
-nop                    { return T_NOP; }
-.if                    { return T_IF;  }
-.else                  { return T_ELSE; }
-.endif                 { return T_ENDIF; }
-
-       /* Allowed Symbols */
-[-+,:()~|&."{};<>[\]!]         { return yytext[0]; }
-
-       /* Number processing */
-0[0-7]*                        {
-                               yylval.value = strtol(yytext, NULL, 8);
-                               return T_NUMBER;
-                       }
-
-0[xX][0-9a-fA-F]+      {
-                               yylval.value = strtoul(yytext + 2, NULL, 16);
-                               return T_NUMBER;
-                       }
-
-[1-9][0-9]*            {
-                               yylval.value = strtol(yytext, NULL, 10);
-                               return T_NUMBER;
-                       }
-
-       /* Include Files */
-#include               { return T_INCLUDE; }
-
-       /* For parsing C include files with #define foo */
-#define                        { yylval.value = TRUE; return T_CONST; }
-       /* Throw away macros */
-#define[^\n]*[()]+[^\n]* ;
-{PATH}                 { yylval.str = strdup(yytext); return T_PATH; }
-
-{WORD}                 { yylval.sym = symtable_get(yytext);  return T_SYMBOL; }
-
-.                      { 
-                               char buf[255];
-
-                               snprintf(buf, sizeof(buf), "Invalid character "
-                                        "'%c'", yytext[0]);
-                               stop(buf, EX_DATAERR);
-                       }
-%%
-
-typedef struct include {
-        YY_BUFFER_STATE  buffer;
-        int              lineno;
-        char            *filename;
-       SLIST_ENTRY(include) links;
-}include_t;
-
-SLIST_HEAD(, include) include_stack;
-
-void
-include_file(file_name, type)
-       char    *file_name;
-       include_type type;
-{
-       FILE *newfile;
-       include_t *include;
-
-       newfile = NULL;
-       /* Try the current directory first */
-       if (includes_search_curdir != 0 || type == SOURCE_FILE)
-               newfile = fopen(file_name, "r");
-
-       if (newfile == NULL && type != SOURCE_FILE) {
-                path_entry_t include_dir;
-                for (include_dir = search_path.slh_first;
-                     include_dir != NULL;                
-                     include_dir = include_dir->links.sle_next) {
-                       char fullname[PATH_MAX];
-
-                       if ((include_dir->quoted_includes_only == TRUE)
-                        && (type != QUOTED_INCLUDE))
-                               continue;
-
-                       snprintf(fullname, sizeof(fullname),
-                                "%s/%s", include_dir->directory, file_name);
-
-                       if ((newfile = fopen(fullname, "r")) != NULL)
-                               break;
-                }
-        }
-
-       if (newfile == NULL) {
-               perror(file_name);
-               stop("Unable to open input file", EX_SOFTWARE);
-               /* NOTREACHED */
-       }
-       include = (include_t *)malloc(sizeof(include_t));
-       if (include == NULL) {
-               stop("Unable to allocate include stack entry", EX_SOFTWARE);
-               /* NOTREACHED */
-       }
-       if (type != SOURCE_FILE) {
-               include->buffer = YY_CURRENT_BUFFER;
-               include->lineno = yylineno;
-               include->filename = yyfilename;
-               SLIST_INSERT_HEAD(&include_stack, include, links);
-       }
-       yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
-       yylineno = 1;
-       yyfilename = strdup(file_name);
-}
-
-int
-yywrap()
-{
-       include_t *include;
-
-       yy_delete_buffer(YY_CURRENT_BUFFER);
-       (void)fclose(yyin);
-       if (yyfilename != NULL)
-               free(yyfilename);
-       yyfilename = NULL;
-       include = include_stack.slh_first;
-       if (include != NULL) {
-               yy_switch_to_buffer(include->buffer);
-               yylineno = include->lineno;
-               yyfilename = include->filename;
-               SLIST_REMOVE_HEAD(&include_stack, links);
-               free(include);
-               return (0);
-       }
-       return (1);
-}
diff --git a/drivers/scsi/aic7xxx/scsi_message.h b/drivers/scsi/aic7xxx/scsi_message.h
deleted file mode 100644 (file)
index 267a015..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * SCSI messages definitions.
- */
-
-/* Messages (1 byte) */                     /* I/T (M)andatory or (O)ptional */
-#define MSG_CMDCOMPLETE                0x00 /* M/M */
-#define MSG_EXTENDED           0x01 /* O/O */
-#define MSG_SAVEDATAPOINTER    0x02 /* O/O */
-#define MSG_RESTOREPOINTERS    0x03 /* O/O */
-#define MSG_DISCONNECT         0x04 /* O/O */
-#define MSG_INITIATOR_DET_ERR  0x05 /* M/M */
-#define MSG_ABORT              0x06 /* O/M */
-#define MSG_MESSAGE_REJECT     0x07 /* M/M */
-#define MSG_NOOP               0x08 /* M/M */
-#define MSG_PARITY_ERROR       0x09 /* M/M */
-#define MSG_LINK_CMD_COMPLETE  0x0a /* O/O */
-#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
-#define MSG_BUS_DEV_RESET      0x0c /* O/M */
-#define MSG_ABORT_TAG          0x0d /* O/O */
-#define MSG_CLEAR_QUEUE                0x0e /* O/O */
-#define MSG_INIT_RECOVERY      0x0f /* O/O */
-#define MSG_REL_RECOVERY       0x10 /* O/O */
-#define MSG_TERM_IO_PROC       0x11 /* O/O */
-
-/* Messages (2 byte) */
-#define MSG_SIMPLE_Q_TAG       0x20 /* O/O */
-#define MSG_HEAD_OF_Q_TAG      0x21 /* O/O */
-#define MSG_ORDERED_Q_TAG      0x22 /* O/O */
-#define MSG_IGN_WIDE_RESIDUE   0x23 /* O/O */
-
-/* Identify message */              /* M/M */  
-#define MSG_IDENTIFYFLAG       0x80 
-#define MSG_IDENTIFY(lun, disc)        (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
-#define MSG_ISIDENTIFY(m)      ((m) & MSG_IDENTIFYFLAG)
-
-/* Extended messages (opcode and length) */
-#define MSG_EXT_SDTR           0x01
-#define MSG_EXT_SDTR_LEN       0x03
-
-#define MSG_EXT_WDTR           0x03
-#define MSG_EXT_WDTR_LEN       0x02
diff --git a/drivers/scsi/aic7xxx/sequencer.h b/drivers/scsi/aic7xxx/sequencer.h
deleted file mode 100644 (file)
index 2f94075..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Instruction formats for the sequencer program downloaded to
- * Aic7xxx SCSI host adapters
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: sequencer.h,v 1.1 1997/03/16 07:08:18 gibbs Exp $
- */
-#include "bsd_q.h"
-
-struct ins_format1 {
-       u_int8_t immediate;
-       u_int8_t source;
-       u_int8_t destination;
-       u_int8_t opcode_ret;
-};
-
-struct ins_format2 {
-       u_int8_t shift_control;
-       u_int8_t source;
-       u_int8_t destination;
-       u_int8_t opcode_ret;
-#define RETURN_BIT 0x01
-};
-
-struct ins_format3 {
-       u_int8_t immediate;
-       u_int8_t source;
-       u_int8_t address;
-       u_int8_t opcode_addr;
-#define ADDR_HIGH_BIT 0x01
-};
-
-struct instruction {
-       union {
-               struct ins_format1 format1;
-               struct ins_format2 format2;
-               struct ins_format3 format3;
-               u_int8_t           bytes[4];
-       } format;
-       u_int   srcline;
-       struct symbol *patch_label;
-       STAILQ_ENTRY(instruction) links;
-};
-
-#define        AIC_OP_OR       0x0
-#define        AIC_OP_AND      0x1
-#define AIC_OP_XOR     0x2
-#define        AIC_OP_ADD      0x3
-#define        AIC_OP_ADC      0x4
-#define        AIC_OP_ROL      0x5
-
-#define        AIC_OP_JMP      0x8
-#define AIC_OP_JC      0x9
-#define AIC_OP_JNC     0xa
-#define AIC_OP_CALL    0xb
-#define        AIC_OP_JNE      0xc
-#define        AIC_OP_JNZ      0xd
-#define        AIC_OP_JE       0xe
-#define        AIC_OP_JZ       0xf
-
-/* Pseudo Ops */
-#define        AIC_OP_SHL      0x10
-#define        AIC_OP_SHR      0x20
-#define        AIC_OP_ROR      0x30
diff --git a/drivers/scsi/aic7xxx/symbol.c b/drivers/scsi/aic7xxx/symbol.c
deleted file mode 100644 (file)
index 5842932..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: symbol.c,v 1.1 1997/03/16 07:08:18 gibbs Exp $
- */
-
-
-#include <sys/types.h>
-
-#include <db.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-
-#include "symbol.h"
-#include "aic7xxx_asm.h"
-
-static DB *symtable;
-
-symbol_t *
-symbol_create(name)
-       char *name;
-{
-       symbol_t *new_symbol;
-
-       new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
-       if (new_symbol == NULL) {
-               perror("Unable to create new symbol");
-               exit(EX_SOFTWARE);
-       }
-       memset(new_symbol, 0, sizeof(*new_symbol));
-       new_symbol->name = strdup(name);
-       new_symbol->type = UNINITIALIZED;
-       return (new_symbol);
-}
-
-void
-symbol_delete(symbol)
-       symbol_t *symbol;
-{
-       if (symtable != NULL) {
-               DBT      key;
-
-               key.data = symbol->name;
-               key.size = strlen(symbol->name);
-               symtable->del(symtable, &key, /*flags*/0);
-       }
-       switch(symbol->type) {
-       case SCBLOC:
-       case SRAMLOC:
-       case REGISTER:
-               if (symbol->info.rinfo != NULL)
-                       free(symbol->info.rinfo);
-               break;
-       case ALIAS:
-               if (symbol->info.ainfo != NULL)
-                       free(symbol->info.ainfo);
-               break;
-       case MASK:
-       case BIT:
-               if (symbol->info.minfo != NULL) {
-                       symlist_free(&symbol->info.minfo->symrefs);
-                       free(symbol->info.minfo);
-               }
-               break;
-       case CONST:
-               if (symbol->info.cinfo != NULL)
-                       free(symbol->info.cinfo);
-               break;
-       case LABEL:
-               if (symbol->info.linfo != NULL)
-                       free(symbol->info.linfo);
-               break;
-       case UNINITIALIZED:
-       default:
-               break;
-       }
-       free(symbol->name);
-       free(symbol);
-}
-
-void
-symtable_open()
-{
-       symtable = dbopen(/*filename*/NULL,
-                         O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
-                         /*openinfo*/NULL);
-
-       if (symtable == NULL) {
-               perror("Symbol table creation failed");
-               exit(EX_SOFTWARE);
-               /* NOTREACHED */
-       }
-}
-
-void
-symtable_close()
-{
-       if (symtable != NULL) {
-               DBT      key;
-               DBT      data;
-
-               while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
-                       symbol_t *cursym;
-
-                       cursym = *(symbol_t **)data.data;
-                       symbol_delete(cursym);
-               }
-               symtable->close(symtable);
-       }
-}
-
-/*
- * The semantics of get is to return an uninitialized symbol entry
- * if a lookup fails.
- */
-symbol_t *
-symtable_get(name)
-       char *name;
-{
-       DBT     key;
-       DBT     data;
-       int     retval;
-
-       key.data = (void *)name;
-       key.size = strlen(name);
-
-       if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
-               if (retval == -1) {
-                       perror("Symbol table get operation failed");
-                       exit(EX_SOFTWARE);
-                       /* NOTREACHED */
-               } else if (retval == 1) {
-                       /* Symbol wasn't found, so create a new one */
-                       symbol_t *new_symbol;
-
-                       new_symbol = symbol_create(name);
-                       data.data = &new_symbol;
-                       data.size = sizeof(new_symbol);
-                       if (symtable->put(symtable, &key, &data,
-                                         /*flags*/0) !=0) {
-                               perror("Symtable put failed");
-                               exit(EX_SOFTWARE);
-                       }
-                       return (new_symbol);
-               } else {
-                       perror("Unexpected return value from db get routine");
-                       exit(EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-       }
-       return (*(symbol_t **)data.data);
-}
-
-symbol_node_t *
-symlist_search(symlist, symname)
-       symlist_t *symlist;
-       char      *symname;
-{
-       symbol_node_t *curnode;
-
-       curnode = symlist->slh_first;
-       while(curnode != NULL) {
-               if (strcmp(symname, curnode->symbol->name) == 0)
-                       break;
-               curnode = curnode->links.sle_next;
-       }
-       return (curnode);
-}
-
-void
-symlist_add(symlist, symbol, how)
-       symlist_t *symlist;
-       symbol_t  *symbol;
-       int       how;
-{
-       symbol_node_t *newnode;
-
-       newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
-       if (newnode == NULL) {
-               stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
-               /* NOTREACHED */
-       }
-       newnode->symbol = symbol;
-       if (how == SYMLIST_SORT) {
-               symbol_node_t *curnode;
-               int mask;
-
-               mask = FALSE;
-               switch(symbol->type) {
-               case REGISTER:
-               case SCBLOC:
-               case SRAMLOC:
-                       break;
-               case BIT:
-               case MASK:
-                       mask = TRUE;
-                       break;
-               default:
-                       stop("symlist_add: Invalid symbol type for sorting",
-                            EX_SOFTWARE);
-                       /* NOTREACHED */
-               }
-
-               curnode = symlist->slh_first;
-               if (curnode == NULL
-                || (mask && (curnode->symbol->info.minfo->mask >
-                             newnode->symbol->info.minfo->mask))
-                || (!mask && (curnode->symbol->info.rinfo->address >
-                              newnode->symbol->info.rinfo->address))) {
-                       SLIST_INSERT_HEAD(symlist, newnode, links);
-                       return;
-               }
-
-               while (1) {
-                       if (curnode->links.sle_next == NULL) {
-                               SLIST_INSERT_AFTER(curnode, newnode,
-                                                  links);
-                               break;
-                       } else {
-                               symbol_t *cursymbol;
-
-                               cursymbol = curnode->links.sle_next->symbol;
-                               if ((mask && (cursymbol->info.minfo->mask >
-                                             symbol->info.minfo->mask))
-                                || (!mask &&(cursymbol->info.rinfo->address >
-                                             symbol->info.rinfo->address))){
-                                       SLIST_INSERT_AFTER(curnode, newnode,
-                                                          links);
-                                       break;
-                               }
-                       }
-                       curnode = curnode->links.sle_next;
-               }
-       } else {
-               SLIST_INSERT_HEAD(symlist, newnode, links);
-       }
-}
-
-void
-symlist_free(symlist)
-       symlist_t *symlist;
-{
-       symbol_node_t *node1, *node2;
-
-       node1 = symlist->slh_first;
-       while (node1 != NULL) {
-               node2 = node1->links.sle_next;
-               free(node1);
-               node1 = node2;
-       }
-       SLIST_INIT(symlist);
-}
-
-void
-symlist_merge(symlist_dest, symlist_src1, symlist_src2)
-       symlist_t *symlist_dest;
-       symlist_t *symlist_src1;
-       symlist_t *symlist_src2;
-{
-       symbol_node_t *node;
-
-       *symlist_dest = *symlist_src1;
-       while((node = symlist_src2->slh_first) != NULL) {
-               SLIST_REMOVE_HEAD(symlist_src2, links);
-               SLIST_INSERT_HEAD(symlist_dest, node, links);
-       }
-
-       /* These are now empty */
-       SLIST_INIT(symlist_src1);
-       SLIST_INIT(symlist_src2);
-}
-
-void
-symtable_dump(ofile)
-       FILE *ofile;
-{
-       /*
-        * Sort the registers by address with a simple insertion sort.
-        * Put bitmasks next to the first register that defines them.
-        * Put constants at the end.
-        */
-       symlist_t registers;
-       symlist_t masks;
-       symlist_t constants;
-       symlist_t aliases;
-
-       SLIST_INIT(&registers);
-       SLIST_INIT(&masks);
-       SLIST_INIT(&constants);
-       SLIST_INIT(&aliases);
-
-       if (symtable != NULL) {
-               DBT      key;
-               DBT      data;
-               int      flag = R_FIRST;
-
-               while (symtable->seq(symtable, &key, &data, flag) == 0) {
-                       symbol_t *cursym;
-
-                       cursym = *(symbol_t **)data.data;
-                       switch(cursym->type) {
-                       case REGISTER:
-                       case SCBLOC:
-                       case SRAMLOC:
-                               symlist_add(&registers, cursym, SYMLIST_SORT);
-                               break;
-                       case MASK:
-                       case BIT:
-                               symlist_add(&masks, cursym, SYMLIST_SORT);
-                               break;
-                       case CONST:
-                               if (cursym->info.cinfo->define == FALSE) {
-                                       symlist_add(&constants, cursym,
-                                                   SYMLIST_INSERT_HEAD);
-                               }
-                               break;
-                       case ALIAS:
-                               symlist_add(&aliases, cursym,
-                                           SYMLIST_INSERT_HEAD);
-                       default:
-                               break;
-                       }
-                       flag = R_NEXT;
-               }
-
-               /* Put in the masks and bits */
-               while (masks.slh_first != NULL) {
-                       symbol_node_t *curnode;
-                       symbol_node_t *regnode;
-                       char *regname;
-
-                       curnode = masks.slh_first;
-                       SLIST_REMOVE_HEAD(&masks, links);
-
-                       regnode =
-                           curnode->symbol->info.minfo->symrefs.slh_first;
-                       regname = regnode->symbol->name;
-                       regnode = symlist_search(&registers, regname);
-                       SLIST_INSERT_AFTER(regnode, curnode, links);
-               }
-
-               /* Add the aliases */
-               while (aliases.slh_first != NULL) {
-                       symbol_node_t *curnode;
-                       symbol_node_t *regnode;
-                       char *regname;
-
-                       curnode = aliases.slh_first;
-                       SLIST_REMOVE_HEAD(&aliases, links);
-
-                       regname = curnode->symbol->info.ainfo->parent->name;
-                       regnode = symlist_search(&registers, regname);
-                       SLIST_INSERT_AFTER(regnode, curnode, links);
-               }
-
-               /* Output what we have */
-               fprintf(ofile,
-"/*
-  * DO NOT EDIT - This file is automatically generated.
-  */\n");
-               while (registers.slh_first != NULL) {
-                       symbol_node_t *curnode;
-                       u_int8_t value;
-                       char *tab_str;
-                       char *tab_str2;
-
-                       curnode = registers.slh_first;
-                       SLIST_REMOVE_HEAD(&registers, links);
-                       switch(curnode->symbol->type) {
-                       case REGISTER:
-                       case SCBLOC:
-                       case SRAMLOC:
-                               fprintf(ofile, "\n");
-                               value = curnode->symbol->info.rinfo->address;
-                               tab_str = "\t";
-                               tab_str2 = "\t\t";
-                               break;
-                       case ALIAS:
-                       {
-                               symbol_t *parent;
-
-                               parent = curnode->symbol->info.ainfo->parent;
-                               value = parent->info.rinfo->address;
-                               tab_str = "\t";
-                               tab_str2 = "\t\t";
-                               break;
-                       }
-                       case MASK:
-                       case BIT:
-                               value = curnode->symbol->info.minfo->mask;
-                               tab_str = "\t\t";
-                               tab_str2 = "\t";
-                               break;
-                       default:
-                               value = 0; /* Quiet compiler */
-                               tab_str = NULL;
-                               tab_str2 = NULL;
-                               stop("symtable_dump: Invalid symbol type "
-                                    "encountered", EX_SOFTWARE);
-                               break;
-                       }
-                       fprintf(ofile, "#define%s%-16s%s0x%02x\n",
-                               tab_str, curnode->symbol->name, tab_str2,
-                               value);
-                       free(curnode);
-               }
-               fprintf(ofile, "\n\n");
-
-               while (constants.slh_first != NULL) {
-                       symbol_node_t *curnode;
-
-                       curnode = constants.slh_first;
-                       SLIST_REMOVE_HEAD(&constants, links);
-                       fprintf(ofile, "#define\t%-8s\t0x%02x\n",
-                               curnode->symbol->name,
-                               curnode->symbol->info.cinfo->value);
-                       free(curnode);
-               }
-       }
-}
-
diff --git a/drivers/scsi/aic7xxx/symbol.h b/drivers/scsi/aic7xxx/symbol.h
deleted file mode 100644 (file)
index 59aa657..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
- *
- * Copyright (c) 1997 Justin T. Gibbs.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice immediately at the beginning of the file, without modification,
- *    this list of conditions, and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- *      $Id: symbol.h,v 1.1 1997/03/16 07:08:19 gibbs Exp $
- */
-#if defined(linux)
-#include "bsd_q.h"
-#else
-#include <sys/queue.h>
-#endif
-
-
-typedef enum {
-       UNINITIALIZED,
-       REGISTER,
-       ALIAS,
-       SCBLOC,
-       SRAMLOC,
-       MASK,
-       BIT,
-       CONST,
-       LABEL,
-       CONDITIONAL
-}symtype;
-
-typedef enum {
-       RO = 0x01,
-       WO = 0x02,
-       RW = 0x03
-}amode_t;
-
-struct reg_info {
-       u_int8_t address;
-       int      size;
-       amode_t  mode;
-       u_int8_t valid_bitmask;
-       int      typecheck_masks;
-};
-
-typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
-
-struct mask_info {
-       symlist_t symrefs;
-       u_int8_t mask;
-};
-
-struct const_info {
-       u_int8_t value;
-       int      define;
-};
-
-struct alias_info {
-       struct symbol *parent;
-};
-
-struct label_info {
-       int     address;
-};
-
-struct cond_info {
-       int     value;
-};
-
-typedef struct expression_info {
-        symlist_t       referenced_syms;
-        int             value;
-} expression_t;
-
-typedef struct symbol {
-       char    *name;
-       symtype type;
-       union   {
-               struct reg_info *rinfo;
-               struct mask_info *minfo;
-               struct const_info *cinfo;
-               struct alias_info *ainfo;
-               struct label_info *linfo;
-               struct cond_info *condinfo;
-       }info;
-} symbol_t;
-
-typedef struct symbol_ref {
-       symbol_t *symbol;
-       int      offset;
-} symbol_ref_t;
-
-typedef struct symbol_node {
-       SLIST_ENTRY(symbol_node) links;
-       symbol_t *symbol;
-}symbol_node_t;
-
-typedef struct patch {
-        STAILQ_ENTRY(patch) links;
-       int       negative;
-       int       begin;
-        int      end;  
-       int       options;
-} patch_t;
-
-void   symbol_delete __P((symbol_t *symbol));
-
-void   symtable_open __P((void));
-
-void   symtable_close __P((void));
-
-symbol_t *
-       symtable_get __P((char *name));
-
-symbol_node_t *
-       symlist_search __P((symlist_t *symlist, char *symname));
-
-void
-       symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
-#define SYMLIST_INSERT_HEAD    0x00
-#define SYMLIST_SORT           0x01
-
-void   symlist_free __P((symlist_t *symlist));
-
-void   symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
-                          symlist_t *symlist_src2));
-void   symtable_dump __P((FILE *ofile));
diff --git a/drivers/scsi/aic7xxx_asm.c b/drivers/scsi/aic7xxx_asm.c
new file mode 100644 (file)
index 0000000..544edf0
--- /dev/null
@@ -0,0 +1,734 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx sequencer code assembler.
+ *
+ * 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.
+ *
+ * Comments are started by `#' and continue to the end of the line; lines
+ * may be of the form:
+ *      <label>*
+ *      <label>*  <undef-sym> = <value>
+ *      <label>*  <opcode> <operand>*
+ *
+ * A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
+ * are token separators.
+ *-M*************************************************************************/
+static const char id[] = "$Id: aic7xxx_asm.c,v 3.0 1996/04/16 08:52:23 deang Exp $";
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define MEMORY         448
+#define MAXLINE                1024
+#define MAXTOKEN       32
+#define ADOTOUT                "a.out"
+#define NOVALUE                -1
+
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+#define MAX_ARGS       16
+static const char *cpp[] = {
+  "/lib/cpp -P - -",
+  "/usr/lib/cpp -P - -",
+  "/usr/bin/cpp -P - -",
+  "/usr/bin/gcc -E -P -",
+  "/usr/bin/cc -E -P -"
+};
+
+#define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
+
+/*
+ * AIC-7770/AIC-7870 register definitions
+ */
+#define R_SINDEX       0x65
+#define R_ALLONES      0x69
+#define R_ALLZEROS     0x6a
+#define R_NONE         0x6a
+
+int debug;
+int lineno, LC;
+char *filename;
+unsigned char M[MEMORY][4];
+
+void 
+error(const char *s)
+{
+       fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
+       exit(EXIT_FAILURE);
+}
+
+void *
+Malloc(size_t size)
+{
+       void *p = malloc(size);
+       if (!p)
+               error("out of memory");
+       return(p);
+}
+
+void *
+Realloc(void *ptr, size_t size)
+{
+       void *p = realloc(ptr, size);
+       if (!p)
+               error("out of memory");
+       return(p);
+}
+
+char *
+Strdup(char *s)
+{
+       char *p = (char *)Malloc(strlen(s) + 1);
+       strcpy(p, s);
+       return(p);
+}
+
+typedef struct sym_t {
+       struct sym_t    *next;          /* MUST BE FIRST */
+       char            *name;
+       int             value;
+       int             npatch; 
+       int             *patch;
+} sym_t;
+
+sym_t *head;
+
+void
+define(char *name, int value)
+{
+       sym_t *p, *q;
+
+       for (p = head, q = (sym_t *)&head; p; p = p->next) {
+               if (!strcmp(p->name, name))
+                       error("redefined symbol");
+               q = p;
+       }
+
+       p = q->next = (sym_t *)Malloc(sizeof(sym_t));
+       p->next = NULL;
+       p->name = Strdup(name);
+       p->value = value;
+       p->npatch = 0;
+       p->patch = NULL;
+
+       if (debug) {
+               fprintf(stderr, "\"%s\" ", p->name);
+               if (p->value != NOVALUE)
+                       fprintf(stderr, "defined as 0x%x\n", p->value);
+               else
+                       fprintf(stderr, "undefined\n");
+       }
+}
+
+sym_t *
+lookup(char *name)
+{
+       sym_t *p;
+
+       for (p = head; p; p = p->next)
+               if (!strcmp(p->name, name))
+                       return(p);
+       return(NULL);
+}
+
+void 
+patch(sym_t *p, int location)
+{
+       p->npatch += 1;
+       p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
+
+       p->patch[p->npatch - 1] = location;
+}
+
+void backpatch(void)
+{
+       int i;
+       sym_t *p;
+
+       for (p = head; p; p = p->next) {
+
+               if (p->value == NOVALUE) {
+                       fprintf(stderr,
+                               "%s: undefined symbol \"%s\"\n",
+                               filename, p->name);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (p->npatch) {
+                       if (debug)
+                               fprintf(stderr,
+                                       "\"%s\" (0x%x) patched at",
+                                       p->name, p->value);
+
+                       for (i = 0; i < p->npatch; i++) {
+                               M[p->patch[i]][0] &= ~1;
+                               M[p->patch[i]][0] |= ((p->value >> 8) & 1);
+                               M[p->patch[i]][1] = p->value & 0xff;
+
+                               if (debug)
+                                       fprintf(stderr, " 0x%x", p->patch[i]);
+                       }
+
+                       if (debug)
+                               fputc('\n', stderr);
+               }
+       }
+}
+
+/*
+ *  Output words in byte-reversed order (least significant first)
+ *  since the sequencer RAM is loaded that way.
+ */
+void
+output(FILE *fp)
+{
+       int i;
+
+       for (i = 0; i < LC; i++)
+               fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+                       M[i][3],
+                       M[i][2],
+                       M[i][1],
+                       M[i][0]);
+       printf("%d out of %d instructions used.\n", LC, MEMORY);
+}
+
+char **
+getl(int *n)
+{
+       int i;
+       char *p, *quote;
+       static char buf[MAXLINE];
+       static char *a[MAXTOKEN];
+
+       i = 0;
+
+       while (fgets(buf, sizeof(buf), stdin)) {
+
+               lineno += 1;
+
+               if (buf[strlen(buf)-1] != '\n')
+                       error("line too long");
+
+               p = strchr(buf, '#');
+               if (p)
+                       *p = '\0';
+               p = buf;
+rescan:
+               quote = strchr(p, '\"');
+               if (quote)
+                       *quote = '\0';
+               for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
+                       if (i < MAXTOKEN-1)
+                               a[i++] = p;
+                       else
+                               error("too many tokens");
+               if (quote) {
+                       quote++; 
+                       p = strchr(quote, '\"');
+                       if (!p)
+                               error("unterminated string constant");
+                       else if (i < MAXTOKEN-1) {
+                               a[i++] = quote;
+                               *p = '\0';
+                               p++;
+                       }
+                       else
+                               error("too many tokens");
+                       goto rescan;
+               }               
+               if (i) {
+                       *n = i;
+                       return(a);
+               }
+       }
+       return(NULL);
+}
+
+#define A      0x8000          /* `A'ccumulator ok */
+#define I      0x4000          /* use as immediate value */
+#define SL     0x2000          /* shift left */
+#define SR     0x1000          /* shift right */
+#define RL     0x0800          /* rotate left */
+#define RR     0x0400          /* rotate right */
+#define LO     0x8000          /* lookup: ori-{jmp,jc,jnc,call} */
+#define LA     0x4000          /* lookup: and-{jz,jnz} */
+#define LX     0x2000          /* lookup: xor-{je,jne} */
+#define NA     -1              /* not applicable */
+
+struct {
+       const char *name;
+       int n;                  /* number of operands, including opcode */
+       unsigned int op;        /* immediate or L?|pos_from_0 */
+       unsigned int dest;      /* NA, pos_from_0, or I|immediate */
+       unsigned int src;       /* NA, pos_from_0, or I|immediate */
+       unsigned int imm;       /* pos_from_0, A|pos_from_0, or I|immediate */
+       unsigned int addr;      /* NA or pos_from_0 */
+       int fmt;                /* instruction format - 1, 2, or 3 */
+} instr[] = {
+/*
+ *               N  OP    DEST         SRC             IMM     ADDR    FMT
+ */
+       { "mov",  3, 1,    1,           2,              I|0xff, NA,     1 },
+       { "mov",  4, LO|2, NA,          1,              I|0,    3,      3 },
+       { "mvi",  3, 0,    1,           I|R_ALLZEROS,   A|2,    NA,     1 },
+       { "mvi",  4, LO|2, NA,          I|R_ALLZEROS,   1,      3,      3 },
+       { "not",  2, 2,    1,           1,              I|0xff, NA,     1 },
+       { "and",  3, 1,    1,           1,              A|2,    NA,     1 },
+       { "and",  4, 1,    1,           3,              A|2,    NA,     1 },
+       { "or",   3, 0,    1,           1,              A|2,    NA,     1 },
+       { "or",   4, 0,    1,           3,              A|2,    NA,     1 },
+       { "or",   5, LO|3, NA,          1,              2,      4,      3 },
+       { "xor",  3, 2,    1,           1,              A|2,    NA,     1 },
+       { "xor",  4, 2,    1,           3,              A|2,    NA,     1 },
+       { "nop",  1, 1,    I|R_NONE,    I|R_ALLZEROS,   I|0xff, NA,     1 },
+       { "inc",  2, 3,    1,           1,              I|1,    NA,     1 },
+       { "inc",  3, 3,    1,           2,              I|1,    NA,     1 },
+       { "dec",  2, 3,    1,           1,              I|0xff, NA,     1 },
+       { "dec",  3, 3,    1,           2,              I|0xff, NA,     1 },
+       { "jmp",  2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "jc",   2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "jnc",  2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "call", 2, LO|0,   NA,        I|R_SINDEX,     I|0,    1,      3 },
+       { "test", 5, LA|3,   NA,        1,              A|2,    4,      3 },
+       { "cmp",  5, LX|3,   NA,        1,              A|2,    4,      3 },
+       { "ret",  1, 1,  I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,     1 },
+       { "ret",  1, 1,  I|R_NONE,      I|R_ALLZEROS,   I|0xff, NA,     1 },
+       { "clc",  1, 3,  I|R_NONE,      I|R_ALLZEROS,   I|1,    NA,     1 },
+       { "clc",  4, 3,  2,             I|R_ALLZEROS,   A|3,    NA,     1 },
+       { "stc",  2, 3,  1,             I|R_ALLONES,    I|1,    NA,     1 },
+       { "add",  3, 3,  1,             1,              A|2,    NA,     1 },
+       { "add",  4, 3,  1,             3,              A|2,    NA,     1 },
+       { "adc",  3, 4,  1,             1,              A|2,    NA,     1 },
+       { "adc",  4, 4,  1,             3,              A|2,    NA,     1 },
+       { "shl",  3, 5,  1,             1,              SL|2,   NA,     2 },
+       { "shl",  4, 5,  1,             2,              SL|3,   NA,     2 },
+       { "shr",  3, 5,  1,             1,              SR|2,   NA,     2 },
+       { "shr",  4, 5,  1,             2,              SR|3,   NA,     2 },
+       { "rol",  3, 5,  1,             1,              RL|2,   NA,     2 },
+       { "rol",  4, 5,  1,             2,              RL|3,   NA,     2 },
+       { "ror",  3, 5,  1,             1,              RR|2,   NA,     2 },
+       { "ror",  4, 5,  1,             2,              RR|3,   NA,     2 },
+       /*
+        *  Extensions (note also that mvi allows A)
+        */
+       { "clr",  2, 1,  1,     I|R_ALLZEROS,           I|0xff, NA,     1 },
+       { 0,      0, 0,  0,     0,                      0,      0,      0 }
+};
+
+int 
+eval_operand(char **a, int spec)
+{
+       int i;
+       unsigned int want = spec & (LO|LA|LX);
+
+       static struct {
+               unsigned int what;
+               const char *name;
+               int value;
+       } jmptab[] = {
+               { LO,   "jmp",          8  },
+               { LO,   "jc",           9  },
+               { LO,   "jnc",          10 },
+               { LO,   "call",         11 },
+               { LA,   "jz",           15 },
+               { LA,   "jnz",          13 },
+               { LX,   "je",           14 },
+               { LX,   "jne",          12 },
+       };
+
+       spec &= ~(LO|LA|LX);
+
+       for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
+               if (jmptab[i].what == want &&
+                   !strcmp(jmptab[i].name, a[spec]))
+               {
+                       return(jmptab[i].value);
+               }
+
+       if (want)
+               error("invalid jump");
+
+       return(spec);           /* "case 0" - no flags set */
+}
+
+int
+eval_sdi(char **a, int spec)
+{
+       sym_t *p;
+       unsigned val;
+
+       if (spec == NA)
+               return(NA);
+
+       switch (spec & (A|I|SL|SR|RL|RR)) {
+           case SL:
+           case SR:
+           case RL:
+           case RR:
+               if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
+                       val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
+               else {
+                       p = lookup(a[spec &~ (SL|SR|RL|RR)]);
+                       if (!p)
+                               error("undefined symbol used");
+                       val = p->value;
+               }
+
+               switch (spec & (SL|SR|RL|RR)) {         /* blech */
+                   case SL:
+                       if (val > 7)
+                               return(0xf0);
+                       return(((val % 8) << 4) |
+                              (val % 8));
+                   case SR:
+                       if (val > 7)
+                               return(0xf0);
+                       return(((val % 8) << 4) |
+                              (1 << 3) |
+                              ((8 - (val % 8)) % 8));
+                   case RL:
+                       return(val % 8);
+                   case RR:
+                       return((8 - (val % 8)) % 8);
+               }
+           case I:
+               return(spec &~ I);
+           case A:
+               /*
+                *  An immediate field of zero selects
+                *  the accumulator.  Vigorously object
+                *  if zero is given otherwise - it's
+                *  most likely an error.
+                */
+               spec &= ~A;
+               if (!strcmp("A", a[spec]))
+                       return(0);
+               if (isdigit(*a[spec]) &&
+                   strtol(a[spec], NULL, 0) == 0)
+               {
+                       error("immediate value of zero selects accumulator");
+               }
+               /* falls through */
+           case 0:
+               if (isdigit(*a[spec]))
+                       return(strtol(a[spec], NULL, 0));
+               p = lookup(a[spec]);
+               if (p)
+                       return(p->value);
+               error("undefined symbol used");
+       }
+
+       return(NA);             /* shut the compiler up */
+}
+
+int
+eval_addr(char **a, int spec)
+{
+       sym_t *p;
+
+       if (spec == NA)
+               return(NA);
+       if (isdigit(*a[spec]))
+               return(strtol(a[spec], NULL, 0));
+
+       p = lookup(a[spec]);
+
+       if (p) {
+               if (p->value != NOVALUE)
+                       return(p->value);
+               patch(p, LC);
+       } else {
+               define(a[spec], NOVALUE);
+               p = lookup(a[spec]);
+               patch(p, LC);
+       }
+
+       return(NA);             /* will be patched in later */
+}
+
+int
+crack(char **a, int n)
+{
+       int i;
+       int I_imm, I_addr;
+       int I_op, I_dest, I_src, I_ret;
+
+       /*
+        *  Check for "ret" at the end of the line; remove
+        *  it unless it's "ret" alone - we still want to
+        *  look it up in the table.
+        */
+       I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
+       if (I_ret && n > 1)
+               n -= 1;
+
+       for (i = 0; instr[i].name; i++) {
+               /*
+                *  Look for match in table given constraints,
+                *  currently just the name and the number of
+                *  operands.
+                */
+               if (!strcmp(instr[i].name, *a) && instr[i].n == n)
+                       break;
+       }
+       if (!instr[i].name)
+               error("unknown opcode or wrong number of operands");
+
+       I_op    = eval_operand(a, instr[i].op);
+       I_src   = eval_sdi(a, instr[i].src);
+       I_imm   = eval_sdi(a, instr[i].imm);
+       I_dest  = eval_sdi(a, instr[i].dest);
+       I_addr  = eval_addr(a, instr[i].addr);
+
+       if( LC >= MEMORY )
+               error("Memory exhausted!\n");
+
+       switch (instr[i].fmt) {
+           case 1:
+           case 2:
+               M[LC][0] = (I_op << 1) | I_ret;
+               M[LC][1] = I_dest;
+               M[LC][2] = I_src;
+               M[LC][3] = I_imm;
+               break;
+           case 3:
+               if (I_ret)
+                       error("illegal use of \"ret\"");
+               M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
+               M[LC][1] = I_addr & 0xff;
+               M[LC][2] = I_src;
+               M[LC][3] = I_imm;
+               break;
+       }
+
+       return (1);             /* no two-byte instructions yet */
+}
+
+#undef SL
+#undef SR
+#undef RL
+#undef RR
+#undef LX
+#undef LA
+#undef LO
+#undef I
+#undef A
+
+void
+assemble(FILE *ofile)
+{
+       int n;
+       char **a;
+       sym_t *p;
+
+       while ((a = getl(&n))) {
+
+               while (a[0][strlen(*a)-1] == ':') {
+                       a[0][strlen(*a)-1] = '\0';
+                       p = lookup(*a);
+                       if (p)
+                               p->value = LC;
+                       else
+                               define(*a, LC);
+                       a += 1;
+                       n -= 1;
+               }
+
+               if (!n)                 /* line was all labels */
+                       continue;
+
+               if (n == 3 && !strcmp("VERSION", *a))
+                       fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
+               else {
+                       if (n == 3 && !strcmp("=", a[1]))
+                               define(*a, strtol(a[2], NULL, 0));
+                       else
+                               LC += crack(a, n);
+               }
+       }
+
+       backpatch();
+       output(ofile);
+
+       if (debug)
+               output(stderr);
+}
+
+int
+main(int argc, char **argv)
+{
+       int c;
+       int pid;
+       int ifile;
+       int status;
+       FILE *ofile;
+       char *ofilename;
+       int fd[2];
+
+       ofile = NULL;
+       ofilename = NULL;
+       while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
+               switch (c) {
+                   case 'd':
+                       debug = !0;
+                       break;
+                   case 'D':
+                   {
+                       char *p;
+                       if ((p = strchr(optarg, '=')) != NULL) {
+                               *p = '\0';
+                               define(optarg, strtol(p + 1, NULL, 0));
+                       }
+                       else
+                               define(optarg, 1);
+                       break;
+                   }
+                   case 'o':
+                       ofilename = optarg;
+                       if ((ofile = fopen(ofilename, "w")) == NULL) {
+                               perror(optarg);
+                               exit(EXIT_FAILURE);
+                       }
+                       break;
+                   case 'h':
+                       printf("usage: %s [-d] [-Dname] [-ooutput] input\n", 
+                               *argv);
+                       exit(EXIT_SUCCESS);
+                       break;
+                   case 'v':
+                       printf("%s\n", id);
+                       exit(EXIT_SUCCESS);
+                       break;
+                   default:
+                       exit(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (argc - optind != 1) {
+               fprintf(stderr, "%s: must have one input file\n", *argv);
+               exit(EXIT_FAILURE);
+       }
+       filename = argv[optind];
+
+       
+       if ((ifile = open(filename, O_RDONLY)) < 0) {
+               perror(filename);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!ofilename) {
+               ofilename = ADOTOUT;
+               if ((ofile = fopen(ofilename, "w")) < 0) {
+                       perror(ofilename);
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       if (pipe(fd) < 0) {
+               perror("pipe failed");
+               exit(1);
+       }
+
+       if ((pid = fork()) < 0 ) {
+               perror("fork failed");
+               exit(1);
+       }
+       else if (pid > 0) {             /* Parent */
+               close(fd[1]);           /* Close write end */
+               if (fd[0] != STDIN_FILENO) {
+                       if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
+                               perror("dup2 error on stdin");
+                               exit(EXIT_FAILURE);
+                       }
+                       close(fd[0]);
+               }
+               assemble(ofile);
+               if (wait(&status) < 0) {
+                       perror("wait error");
+               }
+
+               if (status != 0) {
+                       unlink(ofilename);
+               }
+               exit(status);
+       } else {                                /* Child */
+                int i, arg_cnt, found;
+               char *args[MAX_ARGS];
+               char *buf;
+
+                arg_cnt = 0;
+                found = FALSE;
+                for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
+                       char *bp;
+
+                       buf = strdup(cpp[i]);
+
+                       for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
+                             bp != NULL;
+                             bp = strtok(NULL, " \t\n"), arg_cnt++) {
+                               if (arg_cnt == 0) {
+                                       if (access(bp, X_OK) == 0) {
+                                               found = TRUE;
+                                       }
+                               }
+
+                               args[arg_cnt] = bp;
+                       }
+
+                        if (!found) {
+                               free(buf);
+                        }
+                }
+               args[arg_cnt] = NULL;
+
+                if (found) {
+                       close(fd[0]);           /* Close Read end */
+                       if (fd[1] != STDOUT_FILENO) {
+                               if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
+                                       perror("dup2 error on stdout");
+                                       exit(EXIT_FAILURE);
+                               }
+                               close(fd[1]);
+                       }
+                       if (ifile != STDIN_FILENO) {
+                               if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
+                                       perror("dup2 error on stdin");
+                                       exit(EXIT_FAILURE);
+                               }
+                               close(ifile);
+                       }
+
+                       if (execvp(args[0], args) < 0) {
+                               perror("execvp() error");
+                               exit(EXIT_FAILURE);
+                       }
+               } else {
+                       fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
+                       exit(EXIT_FAILURE);
+               }
+       }
+       return(EXIT_SUCCESS);
+}
index 1092d4862c6bc73e3301b9fc6dbb868375830915..a968c324f929cb264b23cc8e76a1cc880eb29ec1 100644 (file)
@@ -24,7 +24,7 @@
  *
  *  Dean W. Gehnert, deang@teleport.com, 05/01/96
  *
- *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
+ *  $Id: aic7xxx_proc.c,v 4.0 1996/10/13 08:23:42 deang Exp $
  *-M*************************************************************************/
 
 #define BLS buffer + len + size
@@ -77,18 +77,16 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
   struct Scsi_Host *HBAptr;
   struct aic7xxx_host *p;
   static u8 buff[512];
-  int   i;
-  int   found = FALSE;
+  int   i; 
   int   size = 0;
   int   len = 0;
   off_t begin = 0;
   off_t pos = 0;
   static char *bus_names[] = { "Single", "Twin", "Wide" };
-  static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
-      "AIC-787x", "AIC-788x" };
+  static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-787x", "AIC-788x" };
 
   HBAptr = NULL;
-  for (i=0; i < NUMBER(aic7xxx_boards); i++)
+  for (i = 0; i < NUMBER(aic7xxx_boards); i++)
   {
     if ((HBAptr = aic7xxx_boards[i]) != NULL)
     {
@@ -97,23 +95,16 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
         break;
       }
 
-      while ((HBAptr->hostdata != NULL) && !found &&
+      while ((HBAptr->hostdata != NULL) &&
           ((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
       {
         if (HBAptr->host_no == hostno)
         {
-          found = TRUE;
+          break; break;
         }
       }
 
-      if (!found)
-      {
-        HBAptr = NULL;
-      }
-      else
-      {
-        break;
-      }
+      HBAptr = NULL;
     }
   }
 
@@ -138,10 +129,8 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
 
   size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
   size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
-  size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
-#if 0
+  size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_H_VERSION));
   size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
-#endif
   len += size; pos = begin + len; size = 0;
 
   size += sprintf(BLS, "\n");
@@ -152,6 +141,11 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
 #ifdef AIC7XXX_CMDS_PER_LUN
   size += sprintf(BLS, "  AIC7XXX_CMDS_PER_LUN   : %d\n", AIC7XXX_CMDS_PER_LUN);
 #endif
+#ifdef AIC7XXX_TWIN_SUPPORT
+  size += sprintf(BLS, "  AIC7XXX_TWIN_SUPPORT   : Enabled\n");
+#else
+  size += sprintf(BLS, "  AIC7XXX_TWIN_SUPPORT   : Disabled\n");
+#endif
 #ifdef AIC7XXX_TAGGED_QUEUEING
   size += sprintf(BLS, "  AIC7XXX_TAGGED_QUEUEING: Enabled\n");
 #else
@@ -171,18 +165,16 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
 
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
-  size += sprintf(BLS, "          SCSI Adapter: %s\n",
-      board_names[p->chip_type]);
+  size += sprintf(BLS, "          SCSI Adapter: %s\n", board_names[p->type]);
   size += sprintf(BLS, "                        (%s chipset)\n",
-      chip_names[p->chip_class]);
+      chip_names[p->chip_type]);
   size += sprintf(BLS, "              Host Bus: %s\n", bus_names[p->bus_type]);
   size += sprintf(BLS, "               Base IO: %#.4x\n", p->base);
-  size += sprintf(BLS, "        Base IO Memory: 0x%x\n", p->mbase);
   size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
   size += sprintf(BLS, "                  SCBs: Used %d, HW %d, Page %d\n",
-      p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
+      p->scb_link->numscbs, p->maxhscbs, p->maxscbs);
   size += sprintf(BLS, "            Interrupts: %d", p->isr_count);
-  if (p->chip_class == AIC_777x)
+  if (p->chip_type == AIC_777x)
   {
     size += sprintf(BLS, " %s\n",
         (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
index f3b8c349ced4e6264b4eb411923a8bbb45dcf6e1..d26a0c20e6749ee694a76dc1703639b8c437e03c 100644 (file)
-/*
-  * 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                    0x70
-#define                SOFS                    0x0f
-
-#define        SCSIID                          0x05
-#define                OID                     0x0f
-
-#define        SCSIDATL                        0x06
-
-#define        SCSIDATH                        0x07
-
-#define        STCNT                           0x08
-
-#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                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                SFCNT                   0x1f
-
-#define        SSTAT3                          0x0e
-#define                SCSICNT                 0xf0
-#define                OFFCNT                  0x0f
-
-#define        SCSITEST                        0x0f
-#define                RQAKCNT                 0x04
-#define                CNTRTEST                0x02
-#define                CMODE                   0x01
-
-#define        SIMODE0                         0x10
-#define                ENSELDO                 0x40
-#define                ENSELDI                 0x20
-#define                ENSELINGO               0x10
-#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        BRDCTL                          0x1d
-#define                BRDDAT7                 0x80
-#define                BRDDAT6                 0x40
-#define                BRDDAT5                 0x20
-#define                BRDSTB                  0x10
-#define                BRDCS                   0x08
-#define                BRDRW                   0x04
-#define                BRDCTL1                 0x02
-#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                SELWIDE                 0x02
-
-#define        SRAM_BASE                       0x20
-
-#define        TARG_SCRATCH                    0x20
-
-#define        ULTRA_ENB                       0x30
-
-#define        DISC_DSB                        0x32
-
-#define        MSG_LEN                         0x34
-
-#define        MSG_OUT                         0x35
-
-#define        DMAPARAMS                       0x3d
-#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        SCBCOUNT                        0x3e
-
-#define        COMP_SCBCOUNT                   0x3f
-
-#define        QCNTMASK                        0x40
-
-#define        SEQ_FLAGS                       0x41
-#define                RESELECTED              0x80
-#define                IDENTIFY_SEEN           0x40
-#define                TAGGED_SCB              0x20
-#define                DPHASE                  0x10
-#define                PAGESCBS                0x04
-#define                WIDE_BUS                0x02
-#define                TWIN_BUS                0x01
-
-#define        SAVED_TCL                       0x42
-
-#define        SG_COUNT                        0x43
-
-#define        SG_NEXT                         0x44
-
-#define        WAITING_SCBH                    0x48
-
-#define        SAVED_LINKPTR                   0x49
-
-#define        SAVED_SCBPTR                    0x4a
-
-#define        REJBYTE                         0x4b
-
-#define        LASTPHASE                       0x4c
-#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        MSGIN_EXT_LEN                   0x4d
-
-#define        MSGIN_EXT_OPCODE                0x4e
-
-#define        MSGIN_EXT_BYTES                 0x4f
-
-#define        DISCONNECTED_SCBH               0x52
-
-#define        FREE_SCBH                       0x53
-
-#define        HSCB_ADDR                       0x54
-
-#define        CUR_SCBID                       0x58
-
-#define        ARG_1                           0x59
-#define        RETURN_1                        0x59
-#define                SEND_MSG                0x80
-#define                SEND_SENSE              0x40
-#define                SEND_REJ                0x20
+/*+M*************************************************************************
+ * Adaptec AIC7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h
+ *
+ * $Id: aic7xxx_reg.h,v 4.0 1996/10/13 08:23:42 deang Exp $
+ *-M*************************************************************************/
 
-#define        SCSICONF                        0x5a
-#define                RESET_SCSI              0x40
-
-#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
+/*
+ * This header is shared by the sequencer code and the kernel level driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
 
-#define        STACK                           0x6f
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+#define SCSISEQ                        0x000
+#define                TEMODEO         0x80
+#define                ENSELO          0x40
+#define                ENSELI          0x20
+#define                ENRSELI         0x10
+#define                ENAUTOATNO      0x08
+#define                ENAUTOATNI      0x04
+#define                ENAUTOATNP      0x02
+#define                SCSIRSTO        0x01
 
-#define        BCTL                            0x84
-#define                ACE                     0x08
-#define                ENABLE                  0x01
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+#define        SXFRCTL0                0x001
+#define                DFON            0x80
+#define                DFPEXP          0x40
+#define                ULTRAEN         0x20
+#define                CLRSTCNT        0x10
+#define                SPIOEN          0x08
+#define                SCAMEN          0x04
+#define                CLRCHN          0x02
+/*  UNUSED                     0x01 */
 
-#define        DSCOMMAND                       0x84
-#define                CACHETHEN               0x80
-#define                DPARCKEN                0x40
-#define                MPARCKEN                0x20
-#define                EXTREQLCK               0x10
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+#define        SXFRCTL1                0x002
+#define                BITBUCKET       0x80
+#define                SWRAPEN         0x40
+#define                ENSPCHK         0x20
+#define                STIMESEL        0x18
+#define                ENSTIMER        0x04
+#define                ACTNEGEN        0x02
+#define                STPWEN          0x01    /* Powered Termination */
 
-#define        BUSTIME                         0x85
-#define                BOFF                    0xf0
-#define                BON                     0x0f
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+#define SCSISIGI               0x003
+#define                CDI             0x80
+#define                IOI             0x40
+#define                MSGI            0x20
+#define                ATNI            0x10
+#define                SELI            0x08
+#define                BSYI            0x04
+#define                REQI            0x02
+#define                ACKI            0x01
 
-#define        BUSSPD                          0x86
-#define                DFTHRSH_100             0xc0
-#define                DFTHRSH                 0xc0
-#define                STBOFF                  0x38
-#define                STBON                   0x07
+/*
+ * Possible phases in SCSISIGI
+ */
+#define                PHASE_MASK      0xe0
+#define                P_DATAOUT       0x00
+#define                P_DATAIN        0x40
+#define                P_COMMAND       0x80
+#define                P_MESGOUT       0xa0
+#define                P_STATUS        0xc0
+#define                P_MESGIN        0xe0
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+#define SCSISIGO               0x003
+#define                CDO             0x80
+#define                IOO             0x40
+#define                MSGO            0x20
+#define                ATNO            0x10
+#define                SELO            0x08
+#define                BSYO            0x04
+#define                REQO            0x02
+#define                ACKO            0x01
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+#define SCSIRATE               0x004
+#define                WIDEXFER        0x80            /* Wide transfer control */
+#define                SXFR            0x70            /* Sync transfer rate */
+#define                SOFS            0x0f            /* Sync offset */
 
-#define        DSPCISTATUS                     0x86
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+#define SCSIID                 0x005
+#define                TID             0xf0            /* Target ID mask */
+#define                OID             0x0f            /* Our ID mask */
 
-#define        HCNTRL                          0x87
-#define                POWRDN                  0x40
-#define                SWINT                   0x10
-#define                IRQMS                   0x08
-#define                PAUSE                   0x04
-#define                INTEN                   0x02
-#define                CHIPRST                 0x01
-#define                CHIPRSTACK              0x01
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronous data phase transfer.
+ */
+#define SCSIDATL               0x006
+#define SCSIDATH               0x007
 
-#define        HADDR                           0x88
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transfered
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transfered.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+#define STCNT                  0x008
+#define STCNT0                 0x008
+#define STCNT1                 0x009
+#define STCNT2                 0x00a
 
-#define        HCNT                            0x8c
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+#define        CLRSINT0                0x00b
+#define                CLRSELDO        0x40
+#define                CLRSELDI        0x20
+#define                CLRSELINGO      0x10
+#define                CLRSWRAP        0x08
+/*  UNUSED                     0x04 */
+#define                CLRSPIORDY      0x02
+/*  UNUSED                     0x01 */
 
-#define        SCBPTR                          0x90
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+#define SSTAT0                 0x00b
+#define                TARGET          0x80            /* Board acting as target */
+#define                SELDO           0x40            /* Selection Done */
+#define                SELDI           0x20            /* Board has been selected */
+#define                SELINGO         0x10            /* Selection In Progress */
+#define                SWRAP           0x08            /* 24bit counter wrap */
+#define                SDONE           0x04            /* STCNT = 0x000000 */
+#define                SPIORDY         0x02            /* SCSI PIO Ready */
+#define                DMADONE         0x01            /* DMA transfer completed */
 
-#define        INTSTAT                         0x91
-#define                SEQINT_MASK             0xf1
-#define                DATA_OVERRUN            0xe1
-#define                MSGIN_PHASEMIS          0xd1
-#define                MSG_BUFFER_BUSY         0xc1
-#define                AWAITING_MSG            0xa1
-#define                ABORT_CMDCMPLT          0x91
-#define                RESIDUAL                0x81
-#define                BAD_STATUS              0x71
-#define                REJECT_MSG              0x61
-#define                NO_MATCH_BUSY           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
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+#define CLRSINT1               0x00c
+#define                CLRSELTIMEO     0x80
+#define                CLRATNO         0x40
+#define                CLRSCSIRSTI     0x20
+/*  UNUSED                     0x10 */
+#define                CLRBUSFREE      0x08
+#define                CLRSCSIPERR     0x04
+#define                CLRPHASECHG     0x02
+#define                CLRREQINIT      0x01
 
-#define        CLRINT                          0x92
-#define                CLRBRKADRINT            0x08
-#define                CLRSCSIINT              0x04
-#define                CLRCMDINT               0x02
-#define                CLRSEQINT               0x01
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+#define SSTAT1                 0x00c
+#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        ERROR                           0x92
-#define                PARERR                  0x08
-#define                ILLOPCODE               0x04
-#define                ILLSADDR                0x02
-#define                ILLHADDR                0x01
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+#define        SIMODE1                 0x011
+#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        DFCNTRL                         0x93
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+#define        SCSIBUSL                0x012
+#define        SCSIBUSH                0x013
 
-#define        DFSTATUS                        0x94
-#define                DWORDEMP                0x20
-#define                MREQPEND                0x10
-#define                HDONE                   0x08
-#define                DFTHRESH                0x04
-#define                FIFOFULL                0x02
-#define                FIFOEMP                 0x01
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transfered on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transfered since HADDR
+ * can be skewed by write ahead.
+ */
+#define        SHADDR                  0x014
+#define        SHADDR0                 0x014
+#define        SHADDR1                 0x015
+#define        SHADDR2                 0x016
+#define        SHADDR3                 0x017
 
-#define        DFDAT                           0x99
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+#define SELID                  0x019
+#define                SELID_MASK      0xf0
+#define                ONEBIT          0x08
+/*  UNUSED                     0x07 */
 
-#define        SCBCNT                          0x9a
-#define                SCBAUTO                 0x80
-#define                SCBCNT_MASK             0x1f
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection.  In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+#define SBLKCTL                        0x01f
+#define                DIAGLEDEN       0x80    /* Aic78X0 only */
+#define                DIAGLEDON       0x40    /* Aic78X0 only */
+#define                AUTOFLUSHDIS    0x20
+/*  UNUSED                     0x10 */
+#define                SELBUS_MASK     0x0a
+#define                SELBUSB         0x08
+/*  UNUSED                     0x04 */
+#define                SELWIDE         0x02
+/*  UNUSED                     0x01 */
+#define                SELNARROW       0x00
 
-#define        QINFIFO                         0x9b
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+#define SEQCTL                 0x060
+#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        QINCNT                          0x9c
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in succession.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+#define SEQRAM                 0x061
 
-#define        QOUTFIFO                        0x9d
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+#define SEQADDR0               0x062
+#define SEQADDR1               0x063
+#define        SEQADDR1_MASK   0x01
 
-#define        QOUTCNT                         0x9e
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+#define ACCUM                  0x064
+
+#define SINDEX                 0x065
+#define DINDEX                 0x066
+#define ALLZEROS               0x06a
+#define NONE                   0x06a
+#define SINDIR                 0x06c
+#define DINDIR                 0x06d
+#define FUNCTION1              0x06e
 
-#define        SCB_CONTROL                     0xa0
-#define                MK_MESSAGE              0x80
-#define                DISCENB                 0x40
-#define                TAG_ENB                 0x20
-#define                MUST_DMAUP_SCB          0x10
-#define                ABORT_SCB               0x08
-#define                DISCONNECTED            0x04
-#define                SCB_TAG_TYPE            0x03
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transfered across the host bus.
+ */
+#define HADDR                  0x088
+#define HADDR0                 0x088
+#define HADDR1                 0x089
+#define HADDR2                 0x08a
+#define HADDR3                 0x08b
+
+#define HCNT                   0x08c
+#define HCNT0                  0x08c
+#define HCNT1                  0x08d
+#define HCNT2                  0x08e
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+#define SCBPTR                 0x090
 
-#define        SCB_BASE                        0xa0
+/*
+ * Board Control (p. 3-43)
+ */
+#define BCTL                   0x084
+/*   RSVD                      0xf0 */
+#define                ACE             0x08    /* Support for external processors */
+/*   RSVD                      0x06 */
+#define                ENABLE          0x01
 
-#define        SCB_TCL                         0xa1
-#define                TID                     0xf0
-#define                SELBUSB                 0x08
-#define                LID                     0x07
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+#define        DSCOMMAND               0x084
+#define                CACHETHEN       0x80    /* Cache Threshold enable */
+#define                DPARCKEN        0x40    /* Data Parity Check Enable */
+#define                MPARCKEN        0x20    /* Memory Parity Check Enable */
+#define                EXTREQLCK       0x10    /* External Request Lock */
 
-#define        SCB_TARGET_STATUS               0xa2
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+#define BUSTIME                        0x085
+#define                BOFF            0xf0
+#define                BON             0x0f
 
-#define        SCB_SGCOUNT                     0xa3
+/*
+ * Bus Speed (p. 3-45)
+ */
+#define        BUSSPD                  0x086
+#define                DFTHRSH         0xc0
+#define                STBOFF          0x38
+#define                STBON           0x07
+#define                DFTHRSH_100     0xc0
 
-#define        SCB_SGPTR                       0xa4
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+#define HCNTRL                 0x087
+/*    UNUSED                   0x80 */
+#define                POWRDN          0x40
+/*    UNUSED                   0x20 */
+#define                SWINT           0x10
+#define                IRQMS           0x08
+#define                PAUSE           0x04
+#define                INTEN           0x02
+#define                CHIPRST         0x01
+#define                CHIPRSTACK      0x01
 
-#define        SCB_RESID_SGCNT                 0xa8
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+#define INTSTAT                        0x091
+#define                SEQINT_MASK     0xf1            /* SEQINT Status Codes */
+#define                        BAD_PHASE       0x01    /* unknown scsi bus phase */
+#define                        SEND_REJECT     0x11    /* sending a message reject */
+#define                        NO_IDENT        0x21    /* no IDENTIFY after reconnect*/
+#define                        NO_MATCH        0x31    /* no cmd match for reconnect */
+#define                        SDTR_MSG        0x41    /* SDTR message received */
+#define                        WDTR_MSG        0x51    /* WDTR message received */
+#define                        REJECT_MSG      0x61    /* Reject message received */
+#define                        BAD_STATUS      0x71    /* Bad status from target */
+#define                        RESIDUAL        0x81    /* Residual byte count != 0 */
+#define                        ABORT_TAG       0x91    /* Sent an ABORT_TAG message */
+#define                        AWAITING_MSG    0xa1    /*
+                                                * Kernel requested to specify
+                                                 * a message to this target
+                                                 * (command was null), so tell
+                                                 * it that it can fill the
+                                                 * message buffer.
+                                                 */
+#define                        IMMEDDONE       0xb1    /*
+                                                * An immediate command has
+                                                * completed
+                                                */
+#define                        MSG_BUFFER_BUSY 0xc1    /*
+                                                * Sequencer wants to use the
+                                                * message buffer, but it
+                                                * already contains a message
+                                                */
+#define                        MSGIN_PHASEMIS  0xd1    /*
+                                                * Target changed phase on us
+                                                * when we were expecting
+                                                * another msgin byte.
+                                                */
+#define                        DATA_OVERRUN    0xe1    /*
+                                                * Target attempted to write
+                                                * beyond the bounds of its
+                                                * command.
+                                                */
+#define        BRKADRINT 0x08
+#define                SCSIINT   0x04
+#define                CMDCMPLT  0x02
+#define                SEQINT    0x01
+#define                INT_PEND  (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
 
-#define        SCB_RESID_DCNT                  0xa9
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+#define ERROR                  0x092
+/*    UNUSED                   0xf0 */
+#define                PARERR          0x08
+#define                ILLOPCODE       0x04
+#define                ILLSADDR        0x02
+#define                ILLHADDR        0x01
 
-#define        SCB_DATAPTR                     0xac
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+#define CLRINT                 0x092
+#define                CLRBRKADRINT    0x08
+#define                CLRSCSIINT      0x04
+#define                CLRCMDINT       0x02
+#define                CLRSEQINT       0x01
+
+#define        DFCNTRL                 0x093
+#define                WIDEODD         0x40
+#define                SCSIEN          0x20
+#define                SDMAEN          0x10
+#define                SDMAENACK       0x10
+#define                HDMAEN          0x08
+#define                HDMAENACK       0x08
+#define                DIRECTION       0x04
+#define                FIFOFLUSH       0x02
+#define                FIFORESET       0x01
+
+#define        DFSTATUS                0x094
+#define                HDONE           0x08
+#define                FIFOEMP         0x01
+
+#define        DFDAT                   0x099
 
-#define        SCB_DATACNT                     0xb0
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+#define SCBCNT                 0x09a
+#define                SCBAUTO         0x80
+#define                SCBCNT_MASK     0x1f
 
-#define        SCB_LINKED_NEXT                 0xb3
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the sequencer has yet to start)
+ */
+#define QINFIFO                        0x09b
 
-#define        SCB_CMDPTR                      0xb4
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+#define QINCNT                 0x09c
 
-#define        SCB_CMDLEN                      0xb8
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+#define QOUTFIFO               0x09d
 
-#define        SCB_TAG                         0xb9
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+#define QOUTCNT                        0x09e
 
-#define        SCB_NEXT                        0xba
+/*
+ * SCB Definition (p. 5-4)
+ * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
+ * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
+ * whether or not to DMA an SCB from host ram. This flag prevents the
+ * "re-fetching" of transactions that are requeued because the target is
+ * busy with another command. We also use bits 6 & 7 to indicate whether
+ * or not to initiate SDTR or WDTR respectively when starting this command.
+ */
+#define SCBARRAY               0x0a0
+#define        SCB_CONTROL             0x0a0
+#define                NEEDWDTR        0x80
+#define                DISCENB         0x40
+#define                TAG_ENB         0x20
+#define                NEEDSDTR        0x10
+#define                DISCONNECTED    0x04
+#define                SCB_TAG_TYPE    0x03
+#define        SCB_TCL                 0x0a1
+#define        SCB_TARGET_STATUS       0x0a2
+#define        SCB_SGCOUNT             0x0a3
+#define        SCB_SGPTR               0x0a4
+#define                SCB_SGPTR0      0x0a4
+#define                SCB_SGPTR1      0x0a5
+#define                SCB_SGPTR2      0x0a6
+#define                SCB_SGPTR3      0x0a7
+#define        SCB_RESID_SGCNT         0x0a8
+#define SCB_RESID_DCNT         0x0a9
+#define                SCB_RESID_DCNT0 0x0a9
+#define                SCB_RESID_DCNT1 0x0aa
+#define                SCB_RESID_DCNT2 0x0ab
+#define SCB_DATAPTR            0x0ac
+#define                SCB_DATAPTR0    0x0ac
+#define                SCB_DATAPTR1    0x0ad
+#define                SCB_DATAPTR2    0x0ae
+#define                SCB_DATAPTR3    0x0af
+#define        SCB_DATACNT             0x0b0
+#define                SCB_DATACNT0    0x0b0
+#define                SCB_DATACNT1    0x0b1
+#define                SCB_DATACNT2    0x0b2
+/* UNUSED - QUAD PADDING       0x0b3 */
+#define SCB_CMDPTR             0x0b4
+#define                SCB_CMDPTR0     0x0b4
+#define                SCB_CMDPTR1     0x0b5
+#define                SCB_CMDPTR2     0x0b6
+#define                SCB_CMDPTR3     0x0b7
+#define        SCB_CMDLEN              0x0b8
+#define SCB_TAG                        0x0b9
+#define        SCB_NEXT                0x0ba
+#define        SCB_PREV                0x0bb
+
+#define        SG_SIZEOF               0x08            /* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+#define        SEECTL_2840             0x0c0
+/*     UNUSED                  0xf8 */
+#define                CS_2840         0x04
+#define                CK_2840         0x02
+#define                DO_2840         0x01
+
+#define        STATUS_2840             0x0c1
+#define                EEPROM_TF       0x80
+#define                BIOS_SEL        0x60
+#define                ADSEL           0x1e
+#define                DI_2840         0x01
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+#define DSPCISTATUS            0x086
 
-#define        SCB_PREV                        0xbb
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+#define SEECTL                 0x01e
+#define                EXTARBACK       0x80
+#define                EXTARBREQ       0x40
+#define                SEEMS           0x20
+#define                SEERDY          0x10
+#define                SEECS           0x08
+#define                SEECK           0x04
+#define                SEEDO           0x02
+#define                SEEDI           0x01
+
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
 
-#define        SCB_BUSYTARGETS                 0xbc
+/*
+ * 1 byte per target starting at this address for configuration values
+ */
+#define TARG_SCRATCH           0x020
 
-#define        SEECTL_2840                     0xc0
-#define                CS_2840                 0x04
-#define                CK_2840                 0x02
-#define                DO_2840                 0x01
+/*
+ * The sequencer will stick the frist byte of any rejected message here so
+ * we can see what is getting thrown away.  Extended messages put the
+ * extended message type in REJBYTE_EXT.
+ */
+#define REJBYTE                        0x030
+#define REJBYTE_EXT            0x031
 
-#define        STATUS_2840                     0xc1
-#define                EEPROM_TF               0x80
-#define                BIOS_SEL                0x60
-#define                ADSEL                   0x1e
-#define                DI_2840                 0x01
+/*
+ * Bit vector of targets that have disconnection disabled.
+ */
+#define        DISC_DSB                0x032
+#define                DISC_DSB_A      0x032
+#define                DISC_DSB_B      0x033
 
+/*
+ * Length of pending message
+ */
+#define MSG_LEN                        0x034
+
+/* We reserve 8bytes to store outgoing messages */
+#define MSG0                   0x035
+#define                COMP_MSG0       0xcb      /* 2's complement of MSG0 */
+#define MSG1                   0x036
+#define MSG2                   0x037
+#define MSG3                   0x038
+#define MSG4                   0x039
+#define MSG5                   0x03a
+#define MSG6                   0x03b
+#define MSG7                   0x03c
 
-#define        BUS_8_BIT       0x00
-#define        MAX_OFFSET_8BIT 0x0f
-#define        BUS_16_BIT      0x01
-#define        MAX_OFFSET_16BIT        0x08
-#define        SCB_LIST_NULL   0xff
-#define        SG_SIZEOF       0x08
-#define        BUS_32_BIT      0x02
+/*
+ * These are offsets into the card's scratch ram.  Some of the values are
+ * specified in the AHA2742 technical reference manual and are initialized
+ * by the BIOS at boot time.
+ */
+#define LASTPHASE              0x03d
+#define ARG_1                  0x03e
+#define                MAXOFFSET       0x01
+#define RETURN_1               0x03f
+#define                SEND_WDTR       0x80
+#define                SEND_SDTR       0x60
+#define                SEND_SENSE      0x40
+#define                SEND_REJ        0x20
+#define                SCB_PAGEDIN     0x10
+
+#define SIGSTATE               0x040
+
+#define DMAPARAMS              0x041   /* Parameters for DMA Logic */
+
+#define        SG_COUNT                0x042
+#define        SG_NEXT                 0x043   /* working value of SG pointer */
+#define                SG_NEXT0        0x043
+#define                SG_NEXT1        0x044
+#define                SG_NEXT2        0x045
+#define                SG_NEXT3        0x046
+
+#define        SCBCOUNT                0x047   /*
+                                        * Number of SCBs supported by
+                                        * this card.
+                                        */
+#define        COMP_SCBCOUNT           0x048   /*
+                                        * Two's compliment of SCBCOUNT
+                                        */
+#define QCNTMASK               0x049   /*
+                                        * Mask of bits to test against
+                                        * when looking at the Queue Count
+                                        * registers.  Works around a bug
+                                        * on aic7850 chips. 
+                                        */
+#define FLAGS                  0x04a
+#define                SINGLE_BUS      0x00
+#define                TWIN_BUS        0x01
+#define                WIDE_BUS        0x02
+#define                PAGESCBS        0x04
+#define                DPHASE          0x10
+#define                SELECTED        0x20
+#define                IDENTIFY_SEEN   0x40
+#define                RESELECTED      0x80
+
+#define        SAVED_TCL               0x04b   /*
+                                        * Temporary storage for the
+                                        * target/channel/lun of a
+                                        * reconnecting target
+                                        */
+#define        ACTIVE_A                0x04c
+#define        ACTIVE_B                0x04d
+#define WAITING_SCBH           0x04e   /*
+                                        * head of list of SCBs awaiting
+                                        * selection
+                                        */
+#define DISCONNECTED_SCBH      0x04f   /*
+                                        * head of list of SCBs that are
+                                        * disconnected.  Used for SCB
+                                        * paging.
+                                        */
+#define                SCB_LIST_NULL   0xff
+
+#define SAVED_LINKPTR          0x050
+#define SAVED_SCBPTR           0x051
+#define ULTRA_ENB              0x052
+#define ULTRA_ENB_B            0x053
+
+#define SCSICONF               0x05a
+#define                RESET_SCSI      0x40
+
+#define HOSTCONF               0x05d
+
+#define HA_274_BIOSCTRL                0x05f
+#define BIOSMODE               0x30
+#define BIOSDISABLED           0x30
+#define CHANNEL_B_PRIMARY      0x08
+
+/* Message codes */
+#define MSG_EXTENDED           0x01
+#define                MSG_SDTR        0x01
+#define                MSG_WDTR        0x03
+#define MSG_SDPTRS             0x02
+#define MSG_RDPTRS             0x03
+#define MSG_DISCONNECT         0x04
+#define MSG_INITIATOR_DET_ERROR        0x05
+#define MSG_ABORT              0x06
+#define        MSG_REJECT              0x07
+#define MSG_NOP                        0x08
+#define MSG_MSG_PARITY_ERROR   0x09
+#define MSG_BUS_DEVICE_RESET   0x0c
+#define MSG_ABORT_TAG          0x0d
+#define MSG_SIMPLE_TAG         0x20
+#define MSG_IDENTIFY           0x80
+
+/* WDTR Message values */
+#define        BUS_8_BIT               0x00
+#define BUS_16_BIT             0x01
+#define BUS_32_BIT             0x02
+
+#define MAX_OFFSET_8BIT                0x0f
+#define MAX_OFFSET_16BIT       0x08
index 38b7af59750252486f5868974a960bc258e8de79..54523d88f176c332e4deb199892a0acb56c967db 100644 (file)
@@ -802,6 +802,8 @@ DMAbuf_space_in_queue (int dev)
    */
 
   max = dmap->max_fragments;
+  if (max > dmap->nbufs)
+     max = dmap->nbufs;
   len = dmap->qlen;
 
   if (audio_devs[dev]->d->local_qlen)
index e5fc64b6a90dcba5abc150f7da25aebfdc47aa0b..bd06972f3ac4ff6978aa54ebf88cc4ff4dc36296 100644 (file)
@@ -1110,10 +1110,10 @@ static inline void after_unlock_page (struct page * page)
 {
        if (test_and_clear_bit(PG_decr_after, &page->flags))
                atomic_dec(&nr_async_pages);
+       if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
+               swap_after_unlock_page(page->pg_swap_entry);
        if (test_and_clear_bit(PG_free_after, &page->flags))
                __free_page(page);
-       if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
-               swap_after_unlock_page(page->swap_unlock_entry);
 }
 
 /*
index 748eb0ba854d7363d395afadb8af126a0308cfd0..0472487e0f624e74bd320dbd76a5041b8188bc27 100644 (file)
@@ -479,50 +479,6 @@ static inline struct dentry ** d_base_qstr(struct ddir * pdir,
 }
 
 
-static /*inline*/ blocking void recursive_clear(struct ddir * ddir, int flags)
-{
-       int i, retry = 0;
-
-       flags = (flags | D_RECURSIVE) & ~D_NO_CLEAR_INODE;
-again:
-       /* Clear those separately that are not in the hashtable. */
-       while(ddir->dd_zombielist)
-               d_del(ddir->dd_zombielist, flags);
-
-       if(!ddir->dd_hashed)
-               return; /* shortcut */
-
-       for(i=0; i < D_HASHSIZE; i++) {
-               struct dentry ** base = &ddir->dd_hashtable[i];
-               struct dentry * tmp;
-
-               while((tmp = *base)) {
-#ifdef DEBUG
-                       TST("__clear",tmp);
-                       if(!(tmp->d_flag & D_HASHED)) {
-                               printk("VFS: dcache entry not hashed!\n");
-                               printpath(*base); printk("\n");
-                               printpath(tmp);
-                       }
-#endif
-                       /* printk("["); */
-                       d_del(tmp, flags);
-                       /* printk("]"); */
-               }
-       }
-
-       /* New entries may have been added during blocking. */
-       if(ddir->dd_hashed && ++retry < 10)
-               goto again;
-
-#ifdef DEBUG
-       if(ddir->dd_hashed || ddir->dd_true_hashed) {
-               printk("remained %d/%d in hashtable\n",
-                      ddir->dd_true_hashed, ddir->dd_hashed);
-       }
-#endif
-}
-
 static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry,
                                                      struct ddir * pdir,
                                                      struct inode * inode,
@@ -589,6 +545,11 @@ static /*inline*/ void _d_handle_zombie(struct dentry * entry,
                        entry->d_flag |= D_ZOMBIE;
                        insert_hash(&pdir->dd_zombielist, entry);
 
+                       /* This condition is no longer a bug, with the removal
+                        * of recursive_clear() this happens naturally during
+                        * an unmount attempt of a filesystem which is busy.
+                        */
+#if 0
                        /* Not sure when this message should show up... */
                        if(!IS_ROOT(entry)) {
                                printk("VFS: clearing dcache directory "
@@ -602,6 +563,7 @@ static /*inline*/ void _d_handle_zombie(struct dentry * entry,
                                       ddir->dd_basketlist, ddir->dd_zombielist);
 #endif
                        }
+#endif
                }
        }
 }
@@ -638,33 +600,23 @@ static /*inline*/ blocking void _d_del(struct dentry * entry,
 
        /* This may block, be careful! _d_remove_from_parent() is
         * thus called before.
-        *
-        * And there is also another problem, for FS_NO_DCACHE filesystems,
-        * when a recursive_clear hits a directory and performs a dec_ddir()
-        * on that parent (what 'entry' is right now) this could call __iput().
-        * This is ok for the most part, but FS_NO_DCACHE will cause a
-        * redundant call to d_del() for what is now 'entry'.  We do not want
-        * this because this disturbs our state.  So we use a special flag
-        * to notify __iput() of this situation.  -DaveM
         */
-       if(entry->d_flag & D_DIR) {
-               entry->d_flag |= D_DDELIP;
+       if(entry->d_flag & D_DIR)
                ddir = d_dir(entry);
-               recursive_clear(ddir, flags);
-               entry->d_flag &= ~D_DDELIP;
-       }
        if(IS_ROOT(entry))
                return;
 
-       if(!has_true_sons(pdir))
-               dec_ddir(entry->d_parent, entry->d_parent->u.d_inode);
-
        if(flags & D_NO_FREE) {
                /* Make it re-d_add()able */
                pdir->dd_alloced++;
                entry->d_flag &= D_DIR;
        } else
                _d_handle_zombie(entry, ddir, pdir);
+
+       /* This dec_ddir() must occur after zombie handling. */
+       if(!has_true_sons(pdir))
+               dec_ddir(entry->d_parent, entry->d_parent->u.d_inode);
+
        entry->u.d_inode = NULL;
        if(inode) {
                remove_alias(&inode->i_dentry, entry);
@@ -820,21 +772,8 @@ static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry,
                pdir->dd_negs++;
 
                /* Don't allow the negative list to grow too much ... */
-
-               /* XXX There is a bad bug here.  We remove the dentry from
-                * XXX the alias list, but later on recursive_clear() and
-                * XXX d_del() have no way of knowing this, they thus try
-                * XXX to remove it again from the alias linked list and we
-                * XXX get a crash.  -DaveM
-                */
-#if 0 /* FIXME */
-               while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5) {
-                       struct dentry *removal = pdir->dd_neglist->d_prev;
-
-                       remove_alias(&pdir->dd_neglist, removal);
-                       pdir->dd_negs--;
-               }
-#endif
+               while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5)
+                       d_del(pdir->dd_neglist->d_prev, D_REMOVE);
        }
 }
 
index 36fb68bd09dd9d1ca0d7d372641756f585c977c4..7215e12049fbf26f6fa977b79f8062caeaf8b26a 100644 (file)
@@ -496,13 +496,10 @@ xcheck("_iput",inode);
        }
        if((sb = inode->i_sb)) {
                if(sb->s_type && (sb->s_type->fs_flags & FS_NO_DCACHE)) {
-                       /* See dcache.c:_d_del() for the details...  -DaveM */
-                       if(inode->i_dentry && !(inode->i_dentry->d_flag & D_DDELIP)) {
-                               while(inode->i_dentry)
-                                       d_del(inode->i_dentry, D_NO_CLEAR_INODE);
-                               if(atomic_read(&inode->i_count) + inode->i_ddir_count)
-                                       goto done;
-                       }
+                       while(inode->i_dentry)
+                               d_del(inode->i_dentry, D_NO_CLEAR_INODE);
+                       if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+                               goto done;
                }
                if(sb->s_op) {
                        if(inode->i_nlink <= 0 && inode->i_dent_count &&
index 840468a769f8982168b386cf07cdde935ada83a6..198179b98c3d17066a48c25a8c7212f200af6ef4 100644 (file)
@@ -384,10 +384,12 @@ static /*inline*/ int reserved_lookup(struct inode * dir, struct qstr * name,
                                error = 0;
                        }
                        else if(dir->i_dentry) {
-                               *result = dir->i_dentry->d_parent->u.d_inode;
-                               if(!*result)
-                                       panic("dcache parent directory is lost");
                                error = 0;
+                               *result = dir->i_dentry->d_parent->u.d_inode;
+                               if(!*result) {
+                                       printk("dcache parent directory is lost");
+                                       error = -ESTALE;        /* random error */
+                               }
                        }
                }
                if(!error)
@@ -943,6 +945,7 @@ asmlinkage int sys_mkdir(const char * pathname, int mode)
        return error;
 }
 
+#if 0 /* We need a "deletefs", someone please write it.  -DaveM */
 /* Perhaps this could be moved out into a new file. */
 static void basket_name(struct inode * dir, struct dentry * entry)
 {
@@ -975,6 +978,7 @@ static void basket_name(struct inode * dir, struct dentry * entry)
         vfs_unlock();
        iput(inode);
 }
+#endif
 
 static inline int do_rmdir(const char * name)
 {
@@ -1034,20 +1038,27 @@ static inline int do_rmdir(const char * name)
                dir->i_sb->dq_op->initialize(dir, -1);
 
         down(&dir->i_sem);
+#if 0
        if(lastent && d_isbasket(lastent)) {
                d_del(lastent, D_REMOVE);
                error = 0;
                goto exit_lock;
        }
+#endif
        atomic_inc(&dir->i_count);
        error = dir->i_op->rmdir(dir, last.name, last.len);
 #ifdef CONFIG_OMIRR
        if(!error)
                omirr_print(lastent, NULL, NULL, " r %ld ", CURRENT_TIME);
 #endif
+#if 0
        if(!error && lastent)
                basket_name(dir, lastent);
 exit_lock:
+#else
+       if(!error && lastent)
+               d_del(lastent, D_REMOVE);
+#endif
         up(&dir->i_sem);
 exit_dir:
        iput(inode);
@@ -1132,20 +1143,27 @@ static inline int do_unlink(const char * name)
                       inode->i_ddir_count, inode->i_dent_count);
        }
 #endif
+#if 0
        if(lastent && d_isbasket(lastent)) {
                d_del(lastent, D_REMOVE);
                error = 0;
                goto exit_lock;
        }
+#endif
        atomic_inc(&dir->i_count);
        error = dir->i_op->unlink(dir, last.name, last.len);
 #ifdef CONFIG_OMIRR
        if(!error)
                omirr_print(lastent, NULL, NULL, " u %ld ", CURRENT_TIME);
 #endif
+#if 0
        if(!error && lastent)
                basket_name(dir, lastent);
 exit_lock:
+#else
+       if(!error && lastent)
+               d_del(lastent, D_REMOVE);
+#endif
         up(&dir->i_sem);
 exit_dir:
        iput(inode);
index 770ff2b6124fe1dc6a546ec8990de43bd68e6f10..f27d083e479efa72d5f3ea97627d86d529d5b01a 100644 (file)
@@ -133,7 +133,7 @@ nfs_unlock_page(struct page *page)
        if (test_and_clear_bit(PG_decr_after, &page->flags))
                atomic_dec(&page->count);
        if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
-               swap_after_unlock_page(page->swap_unlock_entry);
+               swap_after_unlock_page(page->pg_swap_entry);
 #endif
 }
 
index 53ad636021442da42fc03ee8cbe69c87782353cb..659eef522fc5d343ae9b44fb52ca750ca1478bf5 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef DALLOC_H
 #define DALLOC_H
 /*
- * $Id: dalloc.h,v 1.2 1997/06/12 08:02:42 davem Exp $
+ * $Id: dalloc.h,v 1.3 1997/06/13 04:39:34 davem Exp $
  *
  * include/linux/dalloc.h - alloc routines for dcache
  * alloc / free space for pathname strings
@@ -19,7 +19,6 @@
 
 /* public flags for d_flag */
 #define D_PRELOADED 8
-#define D_DDELIP    16 /* d_del() in progress, see __iput() for details... */
 
 /* public flags for d_del() */
 #define D_REMOVE         0
index 6ebf15a55d74e913e5d3ae8343696c5ad0de7f41..c8b9046a730ec8fcfe9c371ac02b5081b855eb50 100644 (file)
@@ -124,7 +124,7 @@ typedef struct page {
        struct wait_queue *wait;
        struct page **pprev_hash;
        struct buffer_head * buffers;
-       unsigned long swap_unlock_entry;
+       unsigned long pg_swap_entry;
        unsigned long map_nr;   /* page->map_nr == page - mem_map */
 } mem_map_t;
 
@@ -138,6 +138,7 @@ typedef struct page {
 #define PG_swap_unlock_after    6
 #define PG_DMA                  7
 #define PG_Slab                         8
+#define PG_swap_cache           9
 #define PG_reserved            31
 
 /* Make it prettier to test the above... */
@@ -151,10 +152,19 @@ typedef struct page {
 #define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
 #define PageDMA(page)          (test_bit(PG_DMA, &(page)->flags))
 #define PageSlab(page)         (test_bit(PG_Slab, &(page)->flags))
+#define PageSwapCache(page)    (test_bit(PG_swap_cache, &(page)->flags))
 #define PageReserved(page)     (test_bit(PG_reserved, &(page)->flags))
 
 #define PageSetSlab(page)      (set_bit(PG_Slab, &(page)->flags))
+#define PageSetSwapCache(page) (set_bit(PG_swap_cache, &(page)->flags))
+#define PageTestandSetSwapCache(page)  \
+                       (test_and_set_bit(PG_swap_cache, &(page)->flags))
+
 #define PageClearSlab(page)    (clear_bit(PG_Slab, &(page)->flags))
+#define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
+
+#define PageTestandClearSwapCache(page)        \
+                       (test_and_clear_bit(PG_swap_cache, &(page)->flags))
 
 /*
  * page->reserved denotes a page which must never be accessed (which
index b0bdc40b6b017f1dea8a2555a997101e7d8d1a62..56fef7a214331bea33afc1e718ec445eb8437761 100644 (file)
@@ -66,8 +66,7 @@ extern void swap_in(struct task_struct *, struct vm_area_struct *,
 
 /* linux/mm/swap_state.c */
 extern void show_swap_cache_info(void);
-extern int add_to_swap_cache(unsigned long, unsigned long);
-extern unsigned long init_swap_cache(unsigned long, unsigned long);
+extern int add_to_swap_cache(struct page *, unsigned long);
 extern void swap_duplicate(unsigned long);
 
 /* linux/mm/swapfile.c */
@@ -90,8 +89,6 @@ extern void swap_free(unsigned long);
 
 #define SWAP_CACHE_INFO
 
-extern unsigned long * swap_cache;
-
 #ifdef SWAP_CACHE_INFO
 extern unsigned long swap_cache_add_total;
 extern unsigned long swap_cache_add_success;
@@ -101,39 +98,37 @@ extern unsigned long swap_cache_find_total;
 extern unsigned long swap_cache_find_success;
 #endif
 
-extern inline unsigned long in_swap_cache(unsigned long index)
+extern inline unsigned long in_swap_cache(struct page *page)
 {
-       return swap_cache[index]; 
+       if (PageSwapCache(page))
+               return page->pg_swap_entry;
+       return 0;
 }
 
-extern inline long find_in_swap_cache(unsigned long index)
+extern inline long find_in_swap_cache(struct page *page)
 {
-       unsigned long entry;
-
 #ifdef SWAP_CACHE_INFO
        swap_cache_find_total++;
 #endif
-       entry = xchg(swap_cache + index, 0);
+       if (PageTestandClearSwapCache(page))  {
 #ifdef SWAP_CACHE_INFO
-       if (entry)
                swap_cache_find_success++;
 #endif 
-       return entry;
+               return page->pg_swap_entry;
+       }
+       return 0;
 }
 
-extern inline int delete_from_swap_cache(unsigned long index)
+extern inline int delete_from_swap_cache(struct page *page)
 {
-       unsigned long entry;
-       
 #ifdef SWAP_CACHE_INFO
        swap_cache_del_total++;
 #endif 
-       entry = xchg(swap_cache + index, 0);
-       if (entry)  {
+       if (PageTestandClearSwapCache(page))  {
 #ifdef SWAP_CACHE_INFO
                swap_cache_del_success++;
 #endif
-               swap_free(entry);
+               swap_free(page->pg_swap_entry);
                return 1;
        }
        return 0;
index 4d85b6cee47dab99561a35c663c5d955eed85e7f..157b39556e90fb154480afa8913145d846a28d7c 100644 (file)
@@ -195,7 +195,7 @@ static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)
        }
        if (cow)
                pte = pte_wrprotect(pte);
-       if (delete_from_swap_cache(page_nr))
+       if (delete_from_swap_cache(&mem_map[page_nr]))
                pte = pte_mkdirty(pte);
        set_pte(new_pte, pte_mkold(pte));
        set_pte(old_pte, pte);
index 3fe22737099ed02bce9cf37165c3da87678b8c61..69a72de9d8bf337b1e6d859ba01e04a863ce9169 100644 (file)
@@ -133,9 +133,8 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
 void __free_page(struct page *page)
 {
        if (!PageReserved(page) && atomic_dec_and_test(&page->count)) {
-               unsigned long map_nr = page->map_nr;
-               delete_from_swap_cache(map_nr);
-               free_pages_ok(map_nr, 0);
+               delete_from_swap_cache(page);
+               free_pages_ok(page->map_nr, 0);
        }
 }
 
@@ -148,7 +147,7 @@ void free_pages(unsigned long addr, unsigned long order)
                if (PageReserved(map))
                        return;
                if (atomic_dec_and_test(&map->count)) {
-                       delete_from_swap_cache(map_nr);
+                       delete_from_swap_cache(map);
                        free_pages_ok(map_nr, order);
                        return;
                }
@@ -280,8 +279,7 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e
        min_free_pages = i;
        free_pages_low = i + (i>>1);
        free_pages_high = i + i;
-       start_mem = init_swap_cache(start_mem, end_mem);
-       mem_map = (mem_map_t *) start_mem;
+       mem_map = (mem_map_t *) LONG_ALIGN(start_mem);
        p = mem_map + MAP_NR(end_mem);
        start_mem = LONG_ALIGN((unsigned long) p);
        memset(mem_map, 0, start_mem - (unsigned long) mem_map);
@@ -336,7 +334,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
        }
        vma->vm_mm->rss++;
        tsk->maj_flt++;
-       if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
+       if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) {
                /* keep swap page allocated for the moment (swap cache) */
                set_pte(page_table, mk_pte(page, vma->vm_page_prot));
                return;
index 6a16ccee8bb5dd1e0505ed75f1a4e230217daa95..30d0c882ea22a179b62608276037eecd010507ac 100644 (file)
@@ -83,7 +83,9 @@ void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
                        set_bit(PG_free_after, &page->flags);
                        set_bit(PG_decr_after, &page->flags);
                        set_bit(PG_swap_unlock_after, &page->flags);
-                       page->swap_unlock_entry = entry;
+                       /* swap-cache  shouldn't be set, but play safe */
+                       PageClearSwapCache(page);
+                       page->pg_swap_entry = entry;
                        atomic_inc(&nr_async_pages);
                }
                ll_rw_page(rw,p->swap_device,offset,buf);
index f3ffa46d54b591afd281d072862bfa9170f580f1..e0cfe1fefe762f9a862035c494edf8c308e95053 100644 (file)
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
-/*
- * To save us from swapping out pages which have just been swapped in and
- * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
- * the swap entry which was last used to fill the page, or zero if the
- * page does not currently correspond to a page in swap. PAGE_DIRTY makes
- * this info useless.
- */
-unsigned long *swap_cache;
-
 #ifdef SWAP_CACHE_INFO
 unsigned long swap_cache_add_total = 0;
 unsigned long swap_cache_add_success = 0;
@@ -50,7 +41,7 @@ void show_swap_cache_info(void)
 }
 #endif
 
-int add_to_swap_cache(unsigned long index, unsigned long entry)
+int add_to_swap_cache(struct page *page, unsigned long entry)
 {
        struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
 
@@ -58,10 +49,9 @@ int add_to_swap_cache(unsigned long index, unsigned long entry)
        swap_cache_add_total++;
 #endif
        if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-               entry = xchg(swap_cache + index, entry);
-               if (entry)  {
-                       printk("swap_cache: replacing non-NULL entry\n");
-               }
+               page->pg_swap_entry = entry;
+               if (PageTestandSetSwapCache(page))
+                       printk("swap_cache: replacing non-empty entry\n");
 #ifdef SWAP_CACHE_INFO
                swap_cache_add_success++;
 #endif
@@ -70,18 +60,6 @@ int add_to_swap_cache(unsigned long index, unsigned long entry)
        return 0;
 }
 
-__initfunc(unsigned long init_swap_cache(unsigned long mem_start,
-                                        unsigned long mem_end))
-{
-       unsigned long swap_cache_size;
-
-       mem_start = (mem_start + 15) & ~15;
-       swap_cache = (unsigned long *) mem_start;
-       swap_cache_size = MAP_NR(mem_end);
-       memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
-       return (unsigned long) (swap_cache + swap_cache_size);
-}
-
 void swap_duplicate(unsigned long entry)
 {
        struct swap_info_struct * p;
index 5bf6511b835798cffe4f2a7e2840bf22b7775e6b..4a6addce1b9155114f7626de347c2b608cc881f7 100644 (file)
@@ -176,14 +176,16 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
        if (pte_none(pte))
                return 0;
        if (pte_present(pte)) {
+               struct page *pg;
                unsigned long page_nr = MAP_NR(pte_page(pte));
                if (page_nr >= max_mapnr)
                        return 0;
-               if (!in_swap_cache(page_nr))
+               pg = mem_map + page_nr;
+               if (!in_swap_cache(pg))
                        return 0;
-               if (SWP_TYPE(in_swap_cache(page_nr)) != type)
+               if (SWP_TYPE(in_swap_cache(pg)) != type)
                        return 0;
-               delete_from_swap_cache(page_nr);
+               delete_from_swap_cache(pg);
                set_pte(dir, pte_mkdirty(pte));
                return 0;
        }
index 875f668eed00794c9c08e7821d798740ea964dc5..21c178159d2f75092a8945a1dc0ca34ef344df91 100644 (file)
@@ -87,7 +87,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
        /* Deal with page aging.  Pages age from being unused; they
         * rejuvenate on being accessed.  Only swap old pages (age==0
         * is oldest). */
-       if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page))) 
+       if ((pte_dirty(pte) && delete_from_swap_cache(page_map)) 
            || pte_young(pte))  {
                set_pte(page_table, pte_mkold(pte));
                touch_page(page_map);
@@ -117,7 +117,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
                free_page(page);
                return 1;       /* we slept: the process may not exist any more */
        }
-        if ((entry = find_in_swap_cache(MAP_NR(page))))  {
+        if ((entry = find_in_swap_cache(page_map)))  {
                if (atomic_read(&page_map->count) != 1) {
                        set_pte(page_table, pte_mkdirty(pte));
                        printk("Aiee.. duplicated cached swap-cache entry\n");