patch-2.0.13 linux/drivers/scsi/aic7xxx.c

Next file: linux/drivers/scsi/aic7xxx.h
Previous file: linux/drivers/scsi/advansys.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.12/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -30,7 +30,7 @@
  * ----------------------------------------------------------------
  *  Modified to include support for wide and twin bus adapters,
  *  DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
- *  and other rework of the code.
+ *  SCB paging, and other rework of the code.
  *
  *  Parts of this driver are based on the FreeBSD driver by Justin
  *  T. Gibbs.
@@ -39,9 +39,9 @@
  *
  *    Form:  aic7xxx=extended,no_reset
  *
- *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
+ *    -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
  *
- *  $Id: aic7xxx.c,v 3.2 1996/05/12 17:28:23 deang Exp $
+ *  $Id: aic7xxx.c,v 3.4 1996/08/09 15:56:31 deang Exp $
  *-M*************************************************************************/
 
 #ifdef MODULE
@@ -74,7 +74,7 @@
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 3.2 $"
+#define AIC7XXX_C_VERSION  "$Revision: 3.4 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        ((a < b) ? a : b)
@@ -109,15 +109,9 @@
  *     set to 2. If you want to implement tagged queueing, ensure
  *     this define is not commented out.
  *
- *   o Sharing IRQs - allowed for sharing of IRQs. This will allow
- *     for multiple aic7xxx host adapters sharing the same IRQ, but
- *     not for sharing IRQs with other devices. The higher level
- *     PCI code and interrupt handling needs to be modified to
- *     support this.
- *
  *   o Commands 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
+ *     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
@@ -125,10 +119,16 @@
  *     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
+ *     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.
  *
  *   o 3985 support - The 3985 adapter is much like the 3940, but
  *     has three 7870 controllers as opposed to two for the 3940.
@@ -140,7 +140,18 @@
  *     In the near future, we'll modify the driver to reserve 1/3
  *     of the SCBs for each controller.
  *
- *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/11/96
+ *   o SCB paging support - SCB paging is enabled by defining
+ *     AIC7XXX_PAGE_ENABLE.  Support for this was taken from the
+ *     FreeBSD driver (by Justin Gibbs) and allows for up to 255
+ *     active SCBs.  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.
+ *
+ *  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, 06/30/96
  */
 
 /* Uncomment this for testing twin bus support. */
@@ -149,14 +160,11 @@
 /* Uncomment this for tagged queueing. */
 /* #define AIC7XXX_TAGGED_QUEUEING */
 
-/* Uncomment this for allowing sharing of IRQs. */
-#define AIC7XXX_SHARE_IRQS
-
 /*
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#define AIC7XXX_CMDS_PER_LUN 2
+/* #define AIC7XXX_CMDS_PER_LUN 8 */
 
 /* Set this to the delay in seconds after SCSI bus reset. */
 #define AIC7XXX_RESET_DELAY 15
@@ -170,9 +178,14 @@
 /* #define AIC7XXX_PROC_STATS */
 
 /*
+ * Uncomment the following to enable SCB paging.
+ */
+/* #define AIC7XXX_PAGE_ENABLE */
+
+/*
  * For debugging the abort/reset code.
  */
-/* #define AIC7XXX_DEBUG_ABORT */
+#define AIC7XXX_DEBUG_ABORT
 
 /*
  * For general debug messages
@@ -189,6 +202,7 @@
   AIC_284x,	/* VLB  aic7770 on 284x, BIOS disabled */
   AIC_7850,	/* PCI  aic7850 */
   AIC_7855,	/* PCI  aic7855 */
+  AIC_7860,	/* PCI  aic7860 (7850 Ultra) */
   AIC_7870,	/* PCI  aic7870 on motherboard */
   AIC_7871,	/* PCI  aic7871 on 294x */
   AIC_7872,	/* PCI  aic7872 on 3940 */
@@ -235,13 +249,14 @@
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
  */
-static const char * board_names[] = {
+static const char *board_names[] = {
   "<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 */
   "AIC-7870",			/* AIC_7870 */
   "AHA-2940",			/* AIC_7871 */
   "AHA-3940",			/* AIC_7872 */
@@ -265,8 +280,15 @@
  *  the command to us. There is no specific driver status for this
  *  condition, but the higher level scsi driver will requeue the
  *  command on a DID_BUS_BUSY error.
+ *
+ *  Upon further inspection and testing, it seems that DID_BUS_BUSY
+ *  will *always* retry the command.  We can get into an infinite loop
+ *  if this happens when we really want some sort of counter that
+ *  will automatically abort/reset the command after so many retries.
+ *  Using DID_ERROR will do just that.  (Made by a suggestion by
+ *  Doug Ledford 8/1/96)
  */
-#define DID_RETRY_COMMAND DID_BUS_BUSY
+#define DID_RETRY_COMMAND DID_ERROR
 
 /*
  * EISA/VL-bus stuff
@@ -395,6 +417,9 @@
   unsigned short checksum;		/* word 31 */
 };
 
+
+#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
@@ -514,17 +539,18 @@
 /*16*/  unsigned long data_count;
 /*20*/  unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
 /*24*/  unsigned char SCSI_cmd_length;
-#define SCB_PIO_TRANSFER_SIZE   25      /*
-                                         * amount we need to upload/download
-                                         * via rep in/outsb to perform
-                                         * a request sense.  The second
-                                         * RESERVED byte is initialized to
-                                         * 0 in getscb().
+/*25*/	u_char tag;			/* Index into our kernel SCB array.
+					 * Also used as the tag for tagged I/O
+					 */
+#define SCB_PIO_TRANSFER_SIZE	26 	/* amount we need to upload/download
+					 * via PIO to initialize a transaction.
+					 */
+/*26*/  u_char next;                    /* Used to thread SCBs awaiting selection
+                                         * or disconnected down in the sequencer.
                                          */
-/*25*/  u_char next_waiting;            /* Used to thread SCBs awaiting selection. */
 	/*-----------------end of hardware supported fields----------------*/
-	struct aic7xxx_scb *next;	/* next ptr when in free list */
 	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
@@ -532,6 +558,12 @@
 #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 scatterlist  sg;
@@ -539,6 +571,14 @@
 	unsigned char       sense_cmd[6];   /* Allocate 6 characters for sense command */
 };
 
+/*
+ * Define a linked list of SCBs.
+ */
+typedef struct {
+  struct aic7xxx_scb *head;
+  struct aic7xxx_scb *tail;
+} scb_queue_type;
+
 static struct {
   unsigned char errno;
   const char *errmesg;
@@ -564,34 +604,73 @@
  */
 struct aic7xxx_host {
   struct Scsi_Host        *host;             /* pointer to scsi host */
+  int                      host_no;          /* SCSI host number */
   int                      base;             /* card base address */
-  int                      maxscb;           /* hardware SCBs */
-  int                      numscb;           /* current number of scbs */
-  int                      extended;         /* extended xlate? */
+  int                      maxhscbs;         /* hardware SCBs */
+  int                      maxscbs;          /* max SCBs (including pageable) */
+  int                      numscbs;          /* current number of scbs */
+  int                      activescbs;       /* active scbs */
+#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 */
+  unsigned short           needsdtr;
+  unsigned short           sdtr_pending;
+  unsigned short           needwdtr_copy;    /* default config */
+  unsigned short           needwdtr;
+  unsigned short           wdtr_pending;
+  unsigned short           orderedtag;
+  unsigned short           discenable;	     /* Targets allowed to disconnect */
   aha_type                 type;             /* card type */
   aha_chip_type            chip_type;        /* chip base type */
-  int                      ultra_enabled;    /* Ultra SCSI speed enabled */
-  int                      chan_num;         /* for 3940/3985, channel number */
   aha_bus_type             bus_type;         /* normal/twin/wide bus */
-  unsigned char            a_scanned;        /* 0 not scanned, 1 scanned */
-  unsigned char            b_scanned;        /* 0 not scanned, 1 scanned */
-  unsigned int             isr_count;        /* Interrupt count */
-  volatile unsigned char   unpause;          /* unpause value for HCNTRL */
-  volatile unsigned char   pause;            /* pause value for HCNTRL */
-  volatile unsigned short  needsdtr_copy;    /* default config */
-  volatile unsigned short  needsdtr;
-  volatile unsigned short  sdtr_pending;
-  volatile unsigned short  needwdtr_copy;    /* default config */
-  volatile unsigned short  needwdtr;
-  volatile unsigned short  wdtr_pending;
-  volatile unsigned short  discenable;       /* Targets allowed to disconnect */
-  struct seeprom_config    seeprom;
-  int                      have_seeprom;
+  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;
+  struct seeprom_config    seeprom;
   struct Scsi_Host        *next;             /* allow for multiple IRQs */
   struct aic7xxx_scb       scb_array[AIC7XXX_MAXSCB];  /* active commands */
-  struct aic7xxx_scb      *free_scb;         /* list of free SCBs */
-  struct aic7xxx_scb      *aborted_scb;       /* list of aborted SCBs */
+  struct aic7xxx_scb      *pagedout_ntscbs[16];  /*
+                                                  * paged-out, non-tagged scbs
+                                                  * indexed by target.
+                                                  */
+  scb_queue_type           free_scbs;        /*
+                                              * SCBs assigned to free slot on
+                                              * card (no paging required)
+                                              */
+  scb_queue_type           page_scbs;        /*
+                                              * SCBs that will require paging
+                                              * before use (no assigned slot)
+                                              */
+  scb_queue_type           waiting_scbs;     /*
+                                              * SCBs waiting to be paged and
+                                              * started.
+                                              */
+  scb_queue_type           assigned_scbs;    /*
+                                              * SCBs that were waiting but have
+                                              * have now been assigned a slot
+                                              * by aic7xxx_free_scb
+                                              */
+  struct aic7xxx_cmd_queue {
+    Scsi_Cmnd *head;
+    Scsi_Cmnd *tail;
+  } completeq;
+  struct aic7xxx_device_status {
+    long last_reset;
+#define  DEVICE_SUCCESS                 0x01
+#define  BUS_DEVICE_RESET_PENDING       0x02
+    int  flags;
+    int  commands_sent;
+  } device_status[16];
 #ifdef AIC7XXX_PROC_STATS
   /*
    * Statistics Kept:
@@ -618,16 +697,16 @@
 
 struct aic7xxx_host_config {
   int              irq;        /* IRQ number */
-  int              base;       /* I/O base */
-  int              maxscb;     /* hardware SCBs */
+  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 */
-  int              extended;   /* extended xlate? */
-  int              ultra_enabled;    /* Ultra SCSI speed enabled */
+  unsigned int     flags;      /* used the same as struct aic7xxx_host flags */
   int              chan_num;   /* for 3940/3985, channel number */
-  int              use_defaults;   /* Use default wide/sync settings. */
   unsigned char    busrtime;   /* bus release time */
   unsigned char    bus_speed;  /* bus speed */
   unsigned char    qcntmask;
@@ -652,39 +731,28 @@
   short rate;
   const char *english;
 } aic7xxx_syncrates[] = {
-  {  50,  0x100,  "20.0" },
-  {  62,  0x110,  "16.0" },
-  {  75,  0x120,  "13.4" },
-  { 100,  0x140,  "10.0" },
-  { 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"  }
+  {  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 =
     sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
 
 #ifdef CONFIG_PCI
-static int number_of_39xxs = 0;
+static int number_of_3940s = 0;
+static int number_of_3985s = 0;
 #endif CONFIG_PCI
 
 #ifdef AIC7XXX_DEBUG
-static void
-debug(const char *fmt, ...)
-{
-  va_list ap;
-  char buf[256];
-
-  va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
-  printk(buf);
-  va_end(ap);
-}
 
 static void
 debug_config(struct aic7xxx_host_config *p)
@@ -700,7 +768,7 @@
   scsi_conf = inb(SCSICONF + p->base);
 
   /*
-   * Scale the Data FIFO Threshold and the Bus Release Time; they are
+   * 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;
@@ -733,6 +801,7 @@
 
     case AIC_7850:
     case AIC_7855:
+    case AIC_7860:
     case AIC_7870:
     case AIC_7871:
     case AIC_7872:
@@ -743,7 +812,8 @@
     case AIC_7882:
     case AIC_7883:
     case AIC_7884:
-      printk("%s%s (PCI-bus):\n", board_names[p->type], BUSW[p->bus_type]);
+      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:
@@ -819,11 +889,16 @@
 #endif
 
 #else
-#  define debug(fmt, args...)
 #  define debug_config(x)
 #  define debug_scb(x)
 #endif AIC7XXX_DEBUG
 
+#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(x)  ((x)->target | ((x)->channel << 3))
+
 /*
  * XXX - these options apply unilaterally to _all_ 274x/284x/294x
  *       cards in the system. This should be fixed, but then,
@@ -831,7 +906,11 @@
  */
 static unsigned int aic7xxx_extended = 0;    /* extended translation on? */
 static unsigned int aic7xxx_no_reset = 0;    /* no resetting of SCSI bus */
-
+static int aic7xxx_irq_trigger = -1;         /*
+                                              * -1 use board setting
+                                              *  0 use edge triggered
+                                              *  1 use level triggered
+                                              */
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_setup
@@ -853,6 +932,7 @@
   } options[] = {
     { "extended",    &aic7xxx_extended },
     { "no_reset",    &aic7xxx_no_reset },
+    { "irq_trigger", &aic7xxx_irq_trigger },
     { NULL,          NULL }
   };
 
@@ -1072,6 +1152,8 @@
     short period, unsigned char offset, int target, char channel)
 {
   int i;
+  unsigned long ultra_enb_addr;
+  unsigned char ultra_enb, sxfrctl0;
 
   for (i = 0; i < num_aic7xxx_syncrates; i++)
   {
@@ -1081,36 +1163,44 @@
        * Watch out for Ultra speeds when ultra is not enabled and
        * vice-versa.
        */
-      if (p->ultra_enabled)
-      {
-        if (!(aic7xxx_syncrates[i].rate & ULTRA_SXFR))
-        {
-          printk ("aic7xxx: Target %d, channel %c, requests %sMHz transfers, "
-                  "but adapter in Ultra mode can only sync at 7.2MHz or "
-                  "above.\n", target, channel, aic7xxx_syncrates[i].english);
-          break;  /* Use asynchronous transfers. */
-        }
-      }
-      else
+      if (!(p->flags & ULTRA_ENABLED) &&
+          (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
       {
         /*
-         * Check for an Ultra device trying to negotiate an Ultra rate
-         * on an adapter with Ultra mode disabled.
+         * This should only happen if the drive is the first to negotiate
+         * and chooses a high rate.   We'll just move down the table until
+         * we hit a non ultra speed.
          */
-        if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
-        {
-          /*
-           * This should only happen if the driver is the first to negotiate
-           * and chooses a high rate.  We'll just move down the table until
-           * we hit a non Ultra speed.
-           */
-           continue;
-        }
+        continue;
       }
       *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
-      printk("aic7xxx: Target %d, channel %c, now synchronous at %sMHz, "
-             "offset(0x%x).\n",
-	     target, channel, aic7xxx_syncrates[i].english, offset);
+
+      /*
+       * Ensure Ultra mode is set properly for this target.
+       */
+      ultra_enb_addr = ULTRA_ENB;
+      if ((channel == 'B') || (target > 7))
+      {
+        ultra_enb_addr++;
+      }
+      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;
     }
   }
@@ -1119,8 +1209,8 @@
    * Default to asynchronous transfer
    */
   *scsirate = 0;
-  printk("aic7xxx: Target %d, channel %c, using asynchronous transfers.\n",
-         target, channel);
+  printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
+         p->host_no, target, channel);
 }
 
 /*+F*************************************************************************
@@ -1133,11 +1223,8 @@
 static inline void
 aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  unsigned char curscb;
   int base = p->base;
 
-  curscb = inb(SCBPTR + base);
-  outb(scb->position, SCBPTR + base);
   outb(SCBAUTO, SCBCNT + base);
 
   /*
@@ -1158,7 +1245,6 @@
   }
 
   outb(0, SCBCNT + base);
-  outb(curscb, SCBPTR + base);
 }
 
 /*+F*************************************************************************
@@ -1183,6 +1269,75 @@
 
 /*+F*************************************************************************
  * Function:
+ *   scbq_init
+ *
+ * Description:
+ *   SCB queue initialization.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_init(scb_queue_type *queue)
+{
+  queue->head = NULL;
+  queue->tail = NULL;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_insert_head
+ *
+ * Description:
+ *   Add an SCB to the head of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  scb->q_next = queue->head;
+  queue->head = scb;
+  if (queue->tail == NULL)       /* If list was empty, update tail. */
+    queue->tail = queue->head;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_remove_head
+ *
+ * Description:
+ *   Remove an SCB from the head of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove_head(scb_queue_type *queue)
+{
+  if (queue->head != NULL)
+    queue->head = queue->head->q_next;
+  if (queue->head == NULL)       /* If list is now empty, update tail. */
+    queue->tail = NULL;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_insert_tail
+ *
+ * Description:
+ *   Add an SCB at the tail of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  scb->q_next = NULL;
+  if (queue->tail != NULL)       /* Add the scb at the end of the list. */
+    queue->tail->q_next = scb;
+
+  queue->tail = scb;             /* Update the tail. */
+  if (queue->head == NULL)       /* If list was empty, update head. */
+    queue->head = queue->tail;
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_match_scb
  *
  * Description:
@@ -1198,8 +1353,8 @@
   char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
-          target, channel, targ, chan);
+  printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
+         target, channel, targ, chan);
 #endif
   if (target == ALL_TARGETS)
   {
@@ -1250,10 +1405,6 @@
   unsigned char active;
   unsigned long active_port = ACTIVE_A + base;
 
-#ifdef 0
-  printk ("aic7xxx: (unbusy_target) target/channel %d/%c\n",
-          target, channel);
-#endif
   if ((target > 0x07) || (channel == 'B'))
   {
     /*
@@ -1269,6 +1420,164 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_allocate_scb
+ *
+ * Description:
+ *   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 aic7xxx_scb *
+aic7xxx_allocate_scb(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb *scbp = NULL;
+  int maxscbs;
+
+  scbp = p->free_scbs.head;
+  if (scbp != NULL)
+  {
+    scbq_remove_head(&p->free_scbs);
+  }
+  else
+  {
+    /*
+     * This should always be NULL if paging is not enabled.
+     */
+    scbp = p->page_scbs.head;
+    if (scbp != NULL)
+    {
+      scbq_remove_head(&p->page_scbs);
+    }
+    else
+    {
+      /*
+       * Set limit the SCB allocation to the maximum number of
+       * hardware SCBs if paging is not enabled; otherwise use
+       * the maximum (255).
+       */
+      if (p->flags & PAGE_ENABLED)
+        maxscbs = p->maxscbs;
+      else
+        maxscbs = p->maxhscbs;
+      if (p->numscbs < maxscbs)
+      {
+        scbp = &(p->scb_array[p->numscbs]);
+        memset(scbp, 0, sizeof(*scbp));
+        scbp->tag = p->numscbs;
+        if (p->numscbs < p->maxhscbs)
+	  scbp->position = p->numscbs;
+        else
+	  scbp->position = SCB_LIST_NULL;
+        p->numscbs++;
+      }
+    }
+  }
+  if (scbp != NULL)
+  {
+#ifdef AIC7XXX_DEBUG
+    p->activescbs++;
+#endif
+  }
+  return (scbp);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_queue_cmd_complete
+ *
+ * Description:
+ *   Due to race conditions present in the SCSI subsystem, it is easier
+ *   to queue completed commands, then call scsi_done() on them when
+ *   we're finished.  This function queues the completed commands.
+ *-F*************************************************************************/
+static inline void
+aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+{
+  if (p->completeq.tail == NULL)
+    p->completeq.head = cmd;
+  else
+    p->completeq.tail->host_scribble = (char *) cmd;
+  p->completeq.tail = cmd;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_done_cmds_complete
+ *
+ * Description:
+ *   Process the completed command queue.
+ *-F*************************************************************************/
+static inline void
+aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
+{
+  Scsi_Cmnd *cmd;
+
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    cmd->scsi_done(cmd);
+  }
+  p->completeq.tail = NULL;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free_scb
+ *
+ * Description:
+ *   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_scb *wscb;
+
+  scb->state = SCB_FREE;
+  scb->cmd = NULL;
+  scb->control = 0;
+  scb->state = 0;
+
+  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->free_scbs, scb);
+    }
+#ifdef AIC7XXX_DEBUG
+    p->activescbs--;  /* For debugging purposes. */
+#endif
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_done
  *
  * Description:
@@ -1277,31 +1586,11 @@
 static void
 aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
-  long flags;
   Scsi_Cmnd *cmd = scb->cmd;
 
-#ifdef 0
-  printk ("aic7xxx: (done) target/channel %d/%d\n",
-          cmd->target, cmd->channel);
-#endif
-  /*
-   * This is a critical section, since we don't want the
-   * queue routine mucking with the host data.
-   */
-  save_flags(flags);
-  cli();
-
-  /*
-   * Process the command after marking the scb as free
-   * and adding it to the free list.
-   */
-  scb->state = SCB_FREE;
-  scb->next = p->free_scb;
-  p->free_scb = scb;
-  scb->cmd = NULL;
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
 
-  restore_flags(flags);
-  cmd->scsi_done(cmd);
 }
 
 /*+F*************************************************************************
@@ -1313,49 +1602,31 @@
  *   aborted list, and adds each scb to the free list.
  *-F*************************************************************************/
 static void
-aic7xxx_done_aborted_scbs (struct aic7xxx_host *p)
+aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
   struct aic7xxx_scb *scb;
   int i;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  int scb_aborted = 0;
-  printk("aic7xxx: (done_aborted_scbs) calling scsi_done() for aborted scbs\n");
-#endif
-
-  for (i = 0; i < p->numscb; i++)
+  for (i = 0; i < p->numscbs; i++)
   {
     scb = &(p->scb_array[i]);
     if (scb->state & SCB_QUEUED_FOR_DONE)
     {
 #ifdef AIC7XXX_DEBUG_ABORT
-      if (scb_aborted == 0)
-      {
-        printk("aic7xxx: (done_aborted_scbs) Aborting scb %d", scb->position);
-        scb_aborted++;
-      }
-      else
-      {
-        printk(", %d", scb->position);
-      }
+      printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
+      scb->position, TCL_OF_SCB(scb));
 #endif
       /*
        * Process the command after marking the scb as free
        * and adding it to the free list.
        */
-      scb->state = SCB_FREE;
-      scb->next = p->free_scb;
-      p->free_scb = scb;
       cmd = scb->cmd;
-      scb->cmd = NULL;
+      p->device_status[TARGET_INDEX(cmd)].flags = 0;
+      aic7xxx_free_scb(p, scb);
       cmd->scsi_done(cmd);  /* call the done function */
     }
   }
-#ifdef AIC7XXX_DEBUG_ABORT
-  if (scb_aborted != 0)
-    printk("\n");
-#endif
 }
 
 /*+F*************************************************************************
@@ -1375,7 +1646,7 @@
   next = inb(WAITING_SCBH + base);
 
   outb(scb->position, SCBPTR + base);
-  outb(next, SCB_NEXT_WAITING + base);
+  outb(next, SCB_NEXT + base);
   outb(scb->position, WAITING_SCBH + base);
 
   outb(curscb, SCBPTR + base);
@@ -1391,7 +1662,7 @@
  *-F*************************************************************************/
 static unsigned char
 aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
-    unsigned char prev, unsigned char timedout_scb)
+    unsigned char prev)
 {
   unsigned char curscb, next;
   int target = (scb->target_channel_lun >> 4) & 0x0F;
@@ -1403,13 +1674,13 @@
    */
   curscb = inb(SCBPTR + base);
   outb(scb->position, SCBPTR + base);
-  next = inb(SCB_NEXT_WAITING + base);
+  next = inb(SCB_NEXT + base);
 
   /*
    * Clear the necessary fields
    */
   outb(0, SCB_CONTROL + base);
-  outb(SCB_LIST_NULL, SCB_NEXT_WAITING + base);
+  outb(SCB_LIST_NULL, SCB_NEXT + base);
   aic7xxx_unbusy_target(target, channel, base);
 
   /*
@@ -1428,7 +1699,7 @@
      * Select the scb that pointed to us and update its next pointer.
      */
     outb(prev, SCBPTR + base);
-    outb(next, SCB_NEXT_WAITING + base);
+    outb(next, SCB_NEXT + base);
   }
   /*
    * Point us back at the original scb position and inform the SCSI
@@ -1438,10 +1709,6 @@
   scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
   scb->cmd->result = (DID_RESET << 16);
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (abort_waiting_scb) target/channel %d/%c, prev %d, "
-          "to_scb %d, next %d\n", target, channel, prev, timedout_scb, next);
-#endif
   return (next);
 }
 
@@ -1454,8 +1721,7 @@
  *   all active and queued scbs for that target/channel.
  *-F*************************************************************************/
 static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
-    unsigned char timedout_scb)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
 {
   int base = p->base;
   struct aic7xxx_scb *scb;
@@ -1469,36 +1735,33 @@
   active_scb = inb(SCBPTR + base);
 
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (reset_device) target/channel %d/%c, to_scb %d, "
-          "active_scb %d\n", target, channel, timedout_scb, active_scb);
+  printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
+         target, channel, active_scb);
 #endif
   /*
    * Search the QINFIFO.
    */
   {
     int saved_queue[AIC7XXX_MAXSCB];
-    int queued = inb(QINCNT + base);
+    int queued = inb(QINCNT + base) & p->qcntmask;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-    if (queued)
-      printk ("aic7xxx: (reset_device) found %d SCBs in queue\n", queued);
-#endif
     for (i = 0; i < (queued - found); i++)
     {
       saved_queue[i] = inb(QINFIFO + base);
-      scb = &(p->scb_array[saved_queue[i]]);
+      outb(saved_queue[i], SCBPTR + base);
+      scb = &(p->scb_array[inb(SCB_TAG + base)]);
       if (aic7xxx_match_scb(scb, target, channel))
       {
         /*
          * We found an scb that needs to be aborted.
          */
 #ifdef AIC7XXX_DEBUG_ABORT
-        printk ("aic7xxx: (reset_device) aborting SCB %d\n", saved_queue[i]);
+        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(scb->position, SCBPTR + base);
-        outb(0, SCBARRAY + base);
+        outb(0, SCB_CONTROL + base);
         i--;
         found++;
       }
@@ -1521,25 +1784,22 @@
     next = inb(WAITING_SCBH + base);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (reset_device) Searching waiting SCBs, head %d\n", next);
-#endif
     while (next != SCB_LIST_NULL)
     {
-      scb = &(p->scb_array[next]);
+      outb(next, SCBPTR + base);
+      scb = &(p->scb_array[inb(SCB_TAG + base)]);
       /*
        * Select the SCB.
        */
       if (aic7xxx_match_scb(scb, target, channel))
       {
-        next = aic7xxx_abort_waiting_scb(p, scb, prev, timedout_scb);
+        next = aic7xxx_abort_waiting_scb(p, scb, prev);
         found++;
       }
       else
       {
-        outb(scb->position, SCBPTR + base);
         prev = next;
-        next = inb(SCB_NEXT_WAITING + base);
+        next = inb(SCB_NEXT + base);
       }
     }
   }
@@ -1549,7 +1809,7 @@
    * 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->numscb; i++)
+  for (i = 0; i < p->numscbs; i++)
   {
     scb = &(p->scb_array[i]);
     if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
@@ -1557,12 +1817,12 @@
       /*
        * Ensure the target is "free"
        */
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (reset_device) freeing disconnected SCB %d\n", i);
-#endif
       aic7xxx_unbusy_target(target, channel, base);
-      outb(scb->position, SCBPTR + base);
-      outb(0, SCBARRAY + base);
+      if (! (scb->state & SCB_PAGED_OUT))
+      {
+        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++;
@@ -1583,9 +1843,6 @@
 static void
 aic7xxx_reset_current_bus(int base)
 {
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk ("aic7xxx: (reset_current_bus)\n");
-#endif
   outb(SCSIRSTO, SCSISEQ + base);
   udelay(1000);
   outb(0, SCSISEQ + base);
@@ -1599,8 +1856,7 @@
  *   Reset the channel.
  *-F*************************************************************************/
 static int
-aic7xxx_reset_channel(struct aic7xxx_host *p, char channel,
-    unsigned char timedout_scb, int initiate_reset)
+aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
 {
   int base = p->base;
   unsigned char sblkctl;
@@ -1608,15 +1864,11 @@
   unsigned long offset, offset_max;
   int found;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (reset_channel) channel %c, to_scb %d\n",
-          channel, timedout_scb);
-#endif
   /*
    * Clean up all the state information for the
    * pending transactions on this bus.
    */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, timedout_scb);
+  found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
 
   if (channel == 'B')
   {
@@ -1673,8 +1925,8 @@
   if (cur_channel != channel)
   {
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk ("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
-            channel);
+    printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
+           channel);
 #endif
     /*
      * Stealthily reset the other bus without upsetting the current bus
@@ -1684,10 +1936,6 @@
     {
       aic7xxx_reset_current_bus(base);
     }
-
-    /*
-     * Ensure we don't get a RSTI interrupt from this.
-     */
     outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
     outb(CLRSCSIINT, CLRINT + base);
     outb(sblkctl, SBLKCTL + base);
@@ -1700,29 +1948,25 @@
   else
   {
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk ("aic7xxx: (reset_channel) Resetting current channel %c\n",
-            channel);
+    printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
+           channel);
 #endif
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(base);
     }
-    /*
-     * Ensure we don't get a RSTI interrupt from this.
-     */
     outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
     outb(CLRSCSIINT, CLRINT + base);
-
     RESTART_SEQUENCER(p);
 #ifdef AIC7XXX_DEBUG_ABORT
-    printk ("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
+    printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
 #endif
   }
 
   /*
-   * Set the time of last reset.
+   * Delay by the bus settle time.
    */
-  p->host->last_reset = jiffies;
+  aic7xxx_delay(AIC7XXX_RESET_DELAY);
 
   /*
    * Now loop through all the SCBs that have been marked for abortion,
@@ -1734,74 +1978,217 @@
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_isr
+ *   aic7xxx_page_scb
  *
  * Description:
- *   SCSI controller interrupt handler.
+ *   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.
  *
- *   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)
+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*************************************************************************
+ * Function:
+ *   aic7xxx_run_waiting_queues
+ *
+ * Description:
+ *   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)
 {
-  int base, intstat;
-  struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
-  unsigned char ha_flags;
-  short         transfer;
-  unsigned char scsi_id, bus_width;
-  unsigned char offset, rate, scratch, scratch_offset;
-  unsigned char max_offset, rej_byte;
-  unsigned short target_mask;
-  char channel;
-  void *addr;
-  int actual;
-  int scb_index;
-  Scsi_Cmnd *cmd;
+  u_char cur_scb;
+  u_long base = p->base;
+  long flags;
 
-  p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+  if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
+    return;
+
+  save_flags(flags);
+  cli();
+
+  PAUSE_SEQUENCER(p);
+  cur_scb = inb(SCBPTR + base);
 
   /*
-   * Search for the host with a pending interrupt.  If we can't find
-   * one, then we've encountered a spurious interrupt.
+   * First handle SCBs that are waiting but have been assigned a slot.
    */
-  while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
+  scb = p->assigned_scbs.head;
+  while (scb != NULL)
   {
-    if (p->next == NULL)
+    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 = NULL;
+      /* Attempt to page this SCB in */
+      if (disc_scb == SCB_LIST_NULL)
+        break;
+
+      /*
+       * 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;
+
+        scbq_remove_head(&(p->waiting_scbs));
+
+        /*
+         * 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;
     }
-    else
+
+    if (count)
     {
-      p = (struct aic7xxx_host *) p->next->hostdata;
+      /* 
+       * Update the head of the disconnected list.
+       */
+      outb(disc_scb, DISCONNECTED_SCBH + base);
+      if (disc_scb != SCB_LIST_NULL)
+      {
+        outb(disc_scb, SCBPTR + base);
+        outb(SCB_LIST_NULL, SCB_PREV + base);
+      }
     }
   }
+  /* Restore old position */
+  outb(cur_scb, SCBPTR + base);
+  UNPAUSE_SEQUENCER(p);
 
-  if (p == NULL)
+  restore_flags(flags);
+}
+
+/*+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)
+{
+  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;
+  void *addr;
+  Scsi_Cmnd *cmd;
+
+  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(INTSTAT + p->base) & INT_PEND))
   {
-    if (aic7xxx_spurious_count == 1)
+    if (p->next == NULL)
     {
-      aic7xxx_spurious_count = 2;
-      printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
-      return;
+      p = NULL;
     }
     else
     {
-      /*
-       * The best we can do is to set p back to head of list and process
-       * the erroneous interrupt - most likely a BRKADRINT.
-       */
-      p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+      p = (struct aic7xxx_host *) p->next->hostdata;
     }
   }
 
+  if (p == NULL)
+    return;
+
   /*
    * Keep track of interrupts for /proc/scsi
    */
   p->isr_count++;
 
-  if (!p->a_scanned && (p->isr_count == 1))
+  if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
   {
     /*
      * We must only have one card at this IRQ and it must have been
@@ -1820,21 +2207,26 @@
    */
   intstat = inb(INTSTAT + base);
 
+  /*
+   * Indicate that we're in the interrupt handler.
+   */
+  p->flags |= IN_ISR;
+
   if (intstat & BRKADRINT)
   {
     int i;
     unsigned char errno = inb(ERROR + base);
 
-    printk("aic7xxx: (aic7xxx_isr) BRKADRINT error(0x%x):\n", errno);
+    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("  %s\n", hard_error[i].errmesg);
+        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
       }
     }
-    panic("aic7xxx: (aic7xxx_isr) BRKADRINT, error(0x%x) seqaddr(0x%x).\n",
-	  inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
+    panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
+          inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
   }
 
   if (intstat & SEQINT)
@@ -1858,43 +2250,234 @@
 
     switch (intstat & SEQINT_MASK)
     {
+      case NO_MATCH:
+    	if (p->flags & PAGE_ENABLED)
+        {
+    	  /* SCB Page-in request */
+    	  struct aic7xxx_scb *outscb;
+    	  u_char arg_1 = inb(ARG_1 + base);
+          int use_disconnected = FALSE;
+
+          /*
+           * 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)
+          {
+    	    /* 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;
+          }
+
+    	  /*
+    	   * 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->free_scbs.head != NULL)
+          {
+    	    outscb = p->free_scbs.head;
+    	    scbq_remove_head(&p->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)
+          {
+            int scb_index;
+
+            outb(CLRCMDINT, CLRINT + base);
+            scb_index = inb(QOUTFIFO + base);
+            if (!(inb(QOUTCNT + base) & p->qcntmask))
+            {
+              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;
+            }
+            else
+            {
+              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))
+              {
+                /*
+                 * Got sense information.
+                 */
+	        outscb->cmd->flags &= ASKED_FOR_SENSE;
+              }
+              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)
+              {
+                /*
+                 * 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
+            {
+  	      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);
+            }
+          }
+    	}
+    	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 BAD_PHASE:
-	panic("aic7xxx: (aic7xxx_isr) Unknown scsi bus phase.\n");
+	panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
 	break;
 
       case SEND_REJECT:
         rej_byte = inb(REJBYTE + base);
         if ((rej_byte & 0xF0) == 0x20)
         {
-          scb_index = inb(SCBPTR + base);
+          scb_index = inb(SCB_TAG + base);
           scb = &(p->scb_array[scb_index]);
-          printk("aic7xxx: Warning - Tagged message received without identify."
+          printk(KERN_WARNING "scsi%d: Tagged message received without identify."
                  "Disabling tagged commands for target %d channel %c.\n",
-                  scsi_id, channel);
+                  p->host_no, scsi_id, channel);
           scb->cmd->device->tagged_supported = 0;
           scb->cmd->device->tagged_queue = 0;
         }
         else
         {
-          debug("aic7xxx: Warning - Rejecting unknown message (0x%x) received "
-                "from target %d channel %c.\n", rej_byte, scsi_id, channel);
+          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;
 
       case NO_IDENT:
-	panic("aic7xxx: Target %d, channel %c, did not send an IDENTIFY "
-	      "message. SAVED_TCL(0x%x).\n",
-              scsi_id, channel, inb(SAVED_TCL + base));
-	break;
-
-      case NO_MATCH:
-	printk("aic7xxx: No active SCB for reconnecting target %d, "
-	      "channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
-              scsi_id, channel, inb(SAVED_TCL + base));
-        aic7xxx_unbusy_target(scsi_id, channel, base);
-        outb(0, SCBARRAY + base);
-	outb(CLRSELTIMEO, CLRSINT1 + base);
-	RESTART_SEQUENCER(p);
+	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 SDTR_MSG:
@@ -1967,8 +2550,8 @@
       case WDTR_MSG:
       {
 	bus_width = inb(ARG_1 + base);
-	printk("aic7xxx: Received MSG_WDTR, Target %d, channel %c "
-	       "needwdtr(0x%x).\n", scsi_id, channel, p->needwdtr);
+	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);
 
 	if (p->wdtr_pending & target_mask)
@@ -1984,15 +2567,15 @@
 	      break;
 
 	    case BUS_16_BIT:
-	      printk("aic7xxx: Target %d, channel %c, using 16 bit "
-                     "transfers.\n", scsi_id, channel);
+	      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("aic7xxx: Target %d, channel %c, requesting 32 bit "
-                     "transfers, rejecting...\n", scsi_id, channel);
+	      printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
+                     "transfers, rejecting...\n", p->host_no, scsi_id, channel);
 	      break;
 	  }
 	}
@@ -2001,7 +2584,7 @@
 	  /*
 	   * Send our own WDTR in reply.
 	   */
-	  printk("aic7xxx: Will send WDTR!!\n");
+	  printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
 	  switch (bus_width)
 	  {
 	    case BUS_8_BIT:
@@ -2016,8 +2599,8 @@
 	      /* Yes, we mean to fall thru here. */
 
 	    case BUS_16_BIT:
-	      printk("aic7xxx: Target %d, channel %c, using 16 bit "
-                     "transfers.\n", scsi_id, channel);
+	      printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
+                     "transfers.\n", p->host_no, scsi_id, channel);
 	      scratch |= 0x80;
 	      break;
 	  }
@@ -2049,8 +2632,9 @@
 	  scratch &= 0x7F;
 	  p->needwdtr &= ~target_mask;
 	  p->wdtr_pending &= ~target_mask;
-	  printk("aic7xxx: Target %d, channel %c, refusing WIDE negotiation. "
-                 "Using 8 bit transfers.\n", scsi_id, channel);
+	  printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+                 "negotiation; using 8 bit transfers.\n",
+                 p->host_no, scsi_id, channel);
 	}
 	else
 	{
@@ -2062,9 +2646,9 @@
 	    scratch &= 0xF0;
 	    p->needsdtr &= ~target_mask;
 	    p->sdtr_pending &= ~target_mask;
-	    printk("aic7xxx: Target %d, channel %c, refusing synchronous "
-                   "negotiation. Using asynchronous transfers.\n",
-                   scsi_id, channel);
+	    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.
@@ -2076,19 +2660,25 @@
       }
 
       case BAD_STATUS:
-	scb_index = inb(SCBPTR + base);
+        /* 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.
+         */
+
+	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("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
-		 "scb(%d) state(0x%x) cmd(0x%x).\n",
+	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no,
 		 intstat, scb_index, scb->state, (unsigned int) scb->cmd);
 	}
 	else
 	{
 	  cmd = scb->cmd;
-	  aic7xxx_getscb(p, scb);
+          scb->target_status = inb(SCB_TARGET_STATUS + base);
 	  aic7xxx_status(cmd) = scb->target_status;
 
 	  cmd->result |= scb->target_status;
@@ -2096,14 +2686,13 @@
 	  switch (status_byte(scb->target_status))
 	  {
 	    case GOOD:
-              printk("aic7xxx: Interrupted for status of GOOD???\n");
+              printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
 	      break;
 
 	    case CHECK_CONDITION:
 	      if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
 	      {
                 unsigned char tcl;
-                unsigned char control;
 		void         *req_buf;
 
                 tcl = scb->target_channel_lun;
@@ -2122,10 +2711,8 @@
 		scb->sense_sg.length = sizeof(cmd->sense_buffer);
 		req_buf = &scb->sense_sg;
 		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-                control = scb->control;
 
-		memset(scb, 0, SCB_PIO_TRANSFER_SIZE);
-                scb->control = control & DISCENB;
+                scb->control = scb->control & DISCENB;
 		scb->target_channel_lun = tcl;
 		addr = scb->sense_cmd;
 		scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
@@ -2138,7 +2725,6 @@
 		memcpy(scb->data_pointer, &(scb->sense_sg.address), 4);
 
                 aic7xxx_putscb(p, scb);
-		outb(SCB_LIST_NULL, SCB_NEXT_WAITING + base);
                 /*
                  * Ensure that the target is "BUSY" so we don't get overlapping
                  * commands if we happen to be doing tagged I/O.
@@ -2159,7 +2745,8 @@
 	      break;
 
 	    case BUSY:
-	      printk("aic7xxx: Target busy.\n");
+	      printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
+                     p->host_no, scb->target_channel_lun);
 	      if (!aic7xxx_error(cmd))
 	      {
 		aic7xxx_error(cmd) = DID_BUS_BUSY;
@@ -2167,16 +2754,14 @@
 	      break;
 
 	    case QUEUE_FULL:
-	      printk("aic7xxx: Queue full.\n");
-	      if (!aic7xxx_error(cmd))
-	      {
-		aic7xxx_error(cmd) = DID_RETRY_COMMAND;
-	      }
+	      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("aic7xxx: Unexpected target status(0x%x).\n",
-		     scb->target_status);
+	      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;
@@ -2187,12 +2772,12 @@
 	break;
 
       case RESIDUAL:
-	scb_index = inb(SCBPTR + base);
+	scb_index = inb(SCB_TAG + base);
 	scb = &(p->scb_array[scb_index]);
 	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
-	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
-		 "scb(%d) state(0x%x) cmd(0x%x).\n",
+	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no,
 		 intstat, scb_index, scb->state, (unsigned int) scb->cmd);
 	}
 	else
@@ -2218,9 +2803,9 @@
 
 	    if (actual < cmd->underflow)
 	    {
-	      printk("aic7xxx: Target %d underflow - "
-		     "Wanted (at least) (%u) got(%u) count(%d).\n",
-		     cmd->target, cmd->underflow, actual,
+	      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;
@@ -2230,12 +2815,12 @@
 	break;
 
       case ABORT_TAG:
-	scb_index = inb(SCBPTR + base);
+	scb_index = inb(SCB_TAG + base);
 	scb = &(p->scb_array[scb_index]);
 	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
-	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
-		 "scb(%d) state(0x%x) cmd(0x%x)\n",
+	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x\n", p->host_no,
 		 intstat, scb_index, scb->state, (unsigned int) scb->cmd);
 	}
 	else
@@ -2245,8 +2830,8 @@
 	   * We didn't receive a valid tag back from the target
 	   * on a reconnect.
 	   */
-	  printk("aic7xxx: Invalid tag received on target %d, channel %c, "
-                 "lun %d - Sending ABORT_TAG.\n",
+	  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);
@@ -2255,12 +2840,12 @@
 	break;
 
       case AWAITING_MSG:
-	scb_index = inb(SCBPTR + base);
+	scb_index = inb(SCB_TAG + base);
 	scb = &(p->scb_array[scb_index]);
 	if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
 	{
-	  printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) "
-		 "scb(%d) state(0x%x) cmd(0x%x).\n",
+	  printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+		 "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no,
 		 intstat, scb_index, scb->state, (unsigned int) scb->cmd);
 	}
 	else
@@ -2281,18 +2866,18 @@
 	   }
 	   else
 	   {
-	     panic("aic7xxx: AWAITING_SCB for an SCB that does "
-		   "not have a waiting message.\n");
+	     panic("scsi%d: AWAITING_SCB for an SCB that does "
+		   "not have a waiting message.\n", p->host_no);
 	   }
 	}
 	break;
 
       case IMMEDDONE:
-        scb_index = inb(SCBPTR + base);
+        scb_index = inb(SCB_TAG + base);
 	scb = &(p->scb_array[scb_index]);
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (isr) received IMMEDDONE for target %d, scb %d, state %d\n",
-          scsi_id, scb_index, scb->state);
+  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)
         {
@@ -2309,15 +2894,33 @@
           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, SCB_LIST_NULL);
-          aic7xxx_done_aborted_scbs (p);
+          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
         {
-          panic("aic7xxx: Immediate complete for unknown operation.\n");
+          panic("scsi%d: Immediate complete for unknown operation.\n",
+                p->host_no);
         }
         break;
 
+      case DATA_OVERRUN:
+      {
+        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 AIC7XXX_NOT_YET
       /* XXX Fill these in later */
       case MESG_BUFFER_BUSY:
@@ -2327,8 +2930,8 @@
 #endif
 
       default:               /* unknown */
-	debug("aic7xxx: SEQINT, INTSTAT(0x%x) SCSISIGI(0x%x).\n",
-	      intstat, inb(SCSISIGI + base));
+	printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+	       p->host_no, intstat, inb(SCSISIGI + base));
 	break;
     }
 
@@ -2349,11 +2952,23 @@
       channel = 'B';
     }
 
-    scb_index = inb(SCBPTR + base);
+    scb_index = inb(SCB_TAG + base);
     scb = &(p->scb_array[scb_index]);
-    if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+    if (status & SCSIRSTI)
+    {
+      PAUSE_SEQUENCER(p);
+      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, FALSE);
+      run_aborted_queue = TRUE;
+    }
+    else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
     {
-      printk("aic7xxx: No command for SCB (SCSIINT).\n");
+      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.
@@ -2363,16 +2978,6 @@
       outb(CLRSCSIINT, CLRINT + base);
       scb = NULL;
     }
-    else if (status & SCSIRSTI)
-    {
-      PAUSE_SEQUENCER(p);
-      printk ("aic7xxx: Someone reset channel %c (SCSIINT).\n", channel);
-      /*
-       * Go through and abort all commands for the channel, but do not
-       * reset the channel again.
-       */
-      aic7xxx_reset_channel (p, channel, SCB_LIST_NULL, FALSE);
-    }
     else if (status & SCSIPERR)
     {
       char  *phase;
@@ -2412,8 +3017,8 @@
        * A parity error has occurred during a data
        * transfer phase. Flag it and continue.
        */
-      printk("aic7xxx: Parity error during phase %s on target %d, "
-             "channel %d, lun %d.\n", phase,
+      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);
 
       /*
@@ -2424,16 +3029,16 @@
        */
       if (mesg_out != MSG_NOP)
       {
-         outb(mesg_out, MSG0 + base);
-         outb(1, MSG_LEN + base);
-         cmd->result = DID_PARITY << 16;
+        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;
+        /*
+         * Should we allow the target to make this decision for us?
+         */
+        cmd->result = DID_RETRY_COMMAND << 16;
       }
       aic7xxx_done(p, scb);
     }
@@ -2443,11 +3048,6 @@
 
       cmd = scb->cmd;
 
-     /*
-       * Hardware selection timer has expired. Turn
-       * off SCSI selection sequence.
-       */
-      outb(ENRSELI, SCSISEQ + base);
       cmd->result = (DID_TIME_OUT << 16);
       /*
        * Clear an pending messages for the timed out
@@ -2456,26 +3056,12 @@
       ha_flags = inb(FLAGS + base);
       outb(0, MSG_LEN + base);
       aic7xxx_unbusy_target(scsi_id, channel, base);
-
-      outb(0, SCBARRAY + base);
-
       /*
-       * Shut off the offending interrupt sources, reset
-       * the sequencer address to zero and unpause it,
-       * then call the high-level SCSI completion routine.
-       *
-       * WARNING!  This is a magic sequence!  After many
-       * hours of guesswork, turning off the SCSI interrupts
-       * in CLRSINT? does NOT clear the SCSIINT bit in
-       * INTSTAT. By writing to the (undocumented, unused
-       * according to the AIC-7770 manual) third bit of
-       * CLRINT, you can clear INTSTAT. But, if you do it
-       * while the sequencer is paused, you get a BRKADRINT
-       * with an Illegal Host Address status, so the
-       * sequencer has to be restarted first.
+       * Stop the selection.
        */
+      outb(0, SCSISEQ + base);
+      outb(0, SCB_CONTROL + base);
       outb(CLRSELTIMEO, CLRSINT1 + base);
-
       outb(CLRSCSIINT, CLRINT + base);
 
       /*
@@ -2483,15 +3069,11 @@
        */
       waiting = inb(WAITING_SCBH + base);
       outb(waiting, SCBPTR + base);
-      waiting = inb(SCB_NEXT_WAITING + base);
+      waiting = inb(SCB_NEXT + base);
       outb(waiting, WAITING_SCBH + base);
 
       RESTART_SEQUENCER(p);
       aic7xxx_done(p, scb);
-#if 0
-printk("aic7xxx: SELTO SCB(%d) state(0x%x) cmd(0x%x).\n",
-       scb->position, scb->state, (unsigned int) scb->cmd);
-#endif
     }
     else if (!(status & BUSFREE))
     {
@@ -2499,13 +3081,16 @@
        * We don't know what's going on. Turn off the
        * interrupt source and try to continue.
        */
-      printk("aic7xxx: SSTAT1(0x%x).\n", status);
+      printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
       outb(status, CLRSINT1 + base);
       UNPAUSE_SEQUENCER(p);
       outb(CLRSCSIINT, CLRINT + base);
     }
   }
 
+  if (run_aborted_queue)
+    aic7xxx_done_aborted_scbs(p);
+
   if (intstat & CMDCMPLT)
   {
     int complete;
@@ -2521,11 +3106,11 @@
       scb = &(p->scb_array[complete]);
       if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
       {
-	printk("aic7xxx: Warning - No command for SCB %d (CMDCMPLT).\n"
-	       "         QOUTCNT(%d) QINCNT(%d) SCB state(0x%x) cmd(0x%x) "
-               "pos(%d).\n",
-	       complete, inb(QOUTCNT + base), inb(QINCNT + base),
-	       scb->state, (unsigned int) scb->cmd, scb->position);
+	printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
+	       "       QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%x, "
+               "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
+               inb(QINCNT + base), scb->state, (unsigned int) scb->cmd,
+               scb->position);
 	outb(CLRCMDINT, CLRINT + base);
 	continue;
       }
@@ -2538,30 +3123,17 @@
          */
 	cmd->flags &= ASKED_FOR_SENSE;
       }
-#if 0
-      printk("aic7xxx: (complete) State(%d) cmd(0x%x) free(0x%x).\n",
-	     scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb);
-#endif
+      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
-       * complete between the queue poll and the
-       * interrupt clearing, so notification of the
-       * command being complete never made it back
-       * up to the kernel.
+       * Clear interrupt status before checking the output queue again.
+       * This eliminates a race condition whereby a command could
+       * complete between the queue poll and the interrupt clearing,
+       * so notification of the command being complete never made it
+       * back up to the kernel.
        */
       outb(CLRCMDINT, CLRINT + base);
       aic7xxx_done(p, scb);
-#if 0
-  if (scb != &p->scb_array[scb->position])
-  {
-    printk("aic7xxx: (complete) Address mismatch, pos(%d).\n", scb->position);
-  }
-  printk("aic7xxx: (complete) State(%d) cmd(0x%x) free(0x%x).\n",
-	 scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb);
-#endif
 
 #ifdef AIC7XXX_PROC_STATS
       /*
@@ -2607,6 +3179,67 @@
 
     } while (inb(QOUTCNT + base) & p->qcntmask);
   }
+  aic7xxx_done_cmds_complete(p);
+  p->flags &= ~IN_ISR;
+  aic7xxx_run_waiting_queues(p);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_select_queue_depth
+ *
+ * Description:
+ *   Sets the queue depth for each SCSI device hanging off the input
+ *   host adapter.  We use a queue depth of 2 for devices that do not
+ *   support tagged queueing.  If AIC7XXX_CMDS_PER_LUN is defined, we
+ *   use that for tagged queueing devices; otherwise we use our own
+ *   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,
+    Scsi_Device *scsi_devs)
+{
+  Scsi_Device *device = scsi_devs;
+  int tq_depth = 2;
+
+#ifdef AIC7XXX_CMDS_PER_LUN
+  tq_depth = AIC7XXX_CMDS_PER_LUN;
+#else
+  {
+    struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+
+    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)
+    {
+      device->queue_depth = 2;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+      if (device->tagged_supported)
+      {
+        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
+    }
+  }
 }
 
 /*+F*************************************************************************
@@ -3043,6 +3676,9 @@
   unsigned char sblkctl_reg;
   int base, i;
 
+#ifdef AIC7XXX_PAGE_ENABLE
+  config->flags |= PAGE_ENABLED;
+#endif
   base = config->base;
   switch (config->type)
   {
@@ -3052,8 +3688,9 @@
       /*
        * 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.
-       * Until we know how to access more than 4 SCBs for the Rev E chips,
-       * we limit them, along with the Rev C chips, 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.
@@ -3063,15 +3700,18 @@
       if (inb(SBLKCTL + base) == sblkctl_reg)
       {
         /*
-         * We detected a Rev E board.
+         * We detected a Rev E board, we allow paging on this board.
          */
-        printk("aic7xxx: %s Rev E and subsequent.\n",
+        printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
                board_names[config->type]);
 	outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
       }
       else
       {
-        printk("aic7xxx: %s Rev C and previous.\n", board_names[config->type]);
+        /* Do not allow paging. */
+        config->flags &= ~PAGE_ENABLED;
+        printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
+               board_names[config->type]);
       }
       break;
 
@@ -3083,8 +3723,8 @@
    * Walk the SCBs to determine how many there are.
    */
   i = 1;
-  outb (0, SCBPTR + base);
-  outb (0, SCBARRAY + base);
+  outb(0, SCBPTR + base);
+  outb(0, SCBARRAY + base);
 
   while (i < AIC7XXX_MAXSCB)
   {
@@ -3107,11 +3747,23 @@
   outb(0, SCBPTR + base); 
   outb(0, SCBARRAY + base);
 
-  config->maxscb = i;
+  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("aic7xxx: Using %d SCB's after checking for SCB memory.\n",
-         config->maxscb);
+  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");
 
 }
 
@@ -3127,11 +3779,13 @@
     struct aic7xxx_host_config *config)
 {
   int i;
-  unsigned char sblkctl;
+  unsigned char sblkctl, flags = 0;
   int max_targets;
-  int found = 1, base;
+  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;
@@ -3142,31 +3796,40 @@
   /*
    * Lock out other contenders for our i/o space.
    */
-  request_region(MINREG + base, MAXREG - MINREG, "aic7xxx");
+  request_region(base, MAXREG - MINREG, "aic7xxx");
 
   switch (config->type)
   {
     case AIC_7770:
     case AIC_7771:
       /*
-       * 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.
-       *
-       * Use the BIOS settings to determine the interrupt
-       * trigger type (level or edge) and use this value
-       * for pausing and unpausing the sequencer.
+       * 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.
        */
-      config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN;
+      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;
-      config->extended = aic7xxx_extended;
 
+      /*
+       * 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.
+       */
       outb(config->pause | CHIPRST, HCNTRL + base);
       aic7xxx_delay(1);
       if (inb(HCNTRL + base) & CHIPRST)
       {
-	printk("aic7xxx: Chip reset not cleared; clearing manually.\n");
+	printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
       }
       outb(config->pause, HCNTRL + base);
 
@@ -3179,7 +3842,7 @@
           (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
       {
         config->bios = AIC_DISABLED;
-        config->use_defaults = TRUE;
+        config->flags |= USE_DEFAULTS;
       }
       else
       {
@@ -3197,8 +3860,8 @@
       /*
        * A reminder until this can be detected automatically.
        */
-      printk("aic7xxx: Extended translation %sabled.\n",
-	     config->extended ? "en" : "dis");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+	     (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
       break;
 
     case AIC_284x:
@@ -3209,11 +3872,10 @@
       outb(config->pause, HCNTRL + base);
 
       config->parity = AIC_ENABLED;
-      config->extended = aic7xxx_extended;
       config->irq = inb(INTDEF + base) & 0x0F;
       host_conf = inb(HOSTCONF + base);
 
-      printk("aic7xxx: Reading SEEPROM...");
+      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
       have_seeprom = read_2840_seeprom(base, &sc);
       if (!have_seeprom)
       {
@@ -3222,7 +3884,9 @@
       else
       {
 	printk("done.\n");
-	config->extended = ((sc.bios_control & CF284XEXTEND) >> 5);
+        config->flags |= HAVE_SEEPROM;
+        if (sc.bios_control & CF284XEXTEND)
+          config->flags |= EXTENDED_TRANSLATION;
         if (!(sc.bios_control & CFBIOSEN))
         {
           /*
@@ -3256,10 +3920,23 @@
       outb(config->bus_speed & DFTHRSH, BUSSPD + base);
       outb(config->busrtime, BUSTIME + base);
 
-      printk("aic7xxx: Extended translation %sabled.\n",
-	     config->extended ? "en" : "dis");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+	     (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
       break;
 
+    case AIC_7860:
+    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)
+        config->flags |= ULTRA_ENABLED;
+
     case AIC_7850:
     case AIC_7855:
     case AIC_7870:
@@ -3267,31 +3944,56 @@
     case AIC_7872:
     case AIC_7873:
     case AIC_7874:
-    case AIC_7880:
-    case AIC_7881:
-    case AIC_7882:
-    case AIC_7883:
-    case AIC_7884:
+      /*
+       * 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->extended = aic7xxx_extended;
-      config->scsi_id = 7;
       config->parity = AIC_ENABLED;
 
-      printk("aic7xxx: Reading SEEPROM...");
+      printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
       have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2), &sc);
       if (!have_seeprom)
       {
-	printk("\naic7xxx: Unable to read SEEPROM; "
-               "using leftover BIOS values.\n");
+        for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
+        {
+          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("\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;
+        }
+        scsi_conf = ENSPCHK | RESET_SCSI;
       }
       else
       {
 	printk("done.\n");
+        config->flags |= HAVE_SEEPROM;
         if (!(sc.bios_control & CFBIOSEN))
         {
           /*
@@ -3300,10 +4002,17 @@
            * AIC-7770 case.
            */
           config->bios = AIC_DISABLED;
+          scsi_conf = ENSPCHK | RESET_SCSI;
         }
         else
         {
-	  config->extended = ((sc.bios_control & CFEXTEND) >> 7);
+          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;
@@ -3312,32 +4021,19 @@
 	  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_7882) ||
-               (config->type == AIC_7883) || (config->type == AIC_7884)) &&
-              (sc.adapter_control & CFULTRAEN))
+          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 ("aic7xxx: Enabling support for Ultra SCSI speed.\n");
-            config->ultra_enabled = TRUE;
+            printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
+                   "speed.\n");
+            config->flags |= ULTRA_ENABLED;
           }
         }
       }
 
-      /*
-       * XXX - force data fifo threshold to 100%. Why does this
-       *       need to be done?
-       *
-       * We don't know where this is set in the SEEPROM or by the BIOS,
-       * so we default it to 100%.
-       */
+      outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
       config->bus_speed = DFTHRSH_100;
-      scsi_conf = config->scsi_id | config->bus_speed;
-#if 0
-      if (config->parity == AIC_ENABLED)
-      {
-        scsi_conf |= ENSPCHK;
-      }
-#endif
-      outb(scsi_conf, SCSICONF + base);
       outb(config->bus_speed, DSPCISTATUS + base);
 
       /*
@@ -3345,12 +4041,12 @@
        */
       outb(config->scsi_id, SCSICONF + base + 1);
 
-      printk("aic7xxx: Extended translation %sabled.\n",
-	     config->extended ? "en" : "dis");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+	     (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
       break;
 
     default:
-      panic("aic7xxx: (aic7xxx_register) Internal error.\n");
+      panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
   }
 
   detect_maxscb(config);
@@ -3359,11 +4055,11 @@
   {
     if (config->pause & IRQMS)
     {
-      printk("aic7xxx: Using level sensitive interrupts.\n");
+      printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
     }
     else
     {
-      printk("aic7xxx: Using edge triggered interrupts.\n");
+      printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
     }
   }
 
@@ -3372,12 +4068,15 @@
    * register in the sequencer for twin and wide bus cards.
    */
   sblkctl = inb(SBLKCTL + base);
+  if (config->flags & PAGE_ENABLED)
+    flags = PAGESCBS;
+
   switch (sblkctl & SELBUS_MASK)
   {
     case SELNARROW:     /* narrow/normal bus */
       config->scsi_id = inb(SCSICONF + base) & 0x07;
       config->bus_type = AIC_SINGLE;
-      outb(SINGLE_BUS, FLAGS + base);
+      outb(flags | SINGLE_BUS, FLAGS + base);
       break;
 
     case SELWIDE:     /* Wide bus */
@@ -3385,7 +4084,7 @@
       config->bus_type = AIC_WIDE;
       printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
 	     board_names[config->type]);
-      outb(WIDE_BUS, FLAGS + base);
+      outb(flags | WIDE_BUS, FLAGS + base);
       break;
 
     case SELBUSB:     /* Twin bus */
@@ -3393,19 +4092,19 @@
 #ifdef AIC7XXX_TWIN_SUPPORT
       config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
       config->bus_type = AIC_TWIN;
-      printk("aic7xxx: Enabled channel B of %s-Twin.\n",
+      printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
 	     board_names[config->type]);
-      outb(TWIN_BUS, FLAGS + base);
+      outb(flags | TWIN_BUS, FLAGS + base);
 #else
       config->bus_type = AIC_SINGLE;
-      printk("aic7xxx: Channel B of %s-Twin will be ignored.\n",
+      printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
 	     board_names[config->type]);
-      outb(0, FLAGS + base);
+      outb(flags, FLAGS + base);
 #endif
       break;
 
     default:
-      printk("aic7xxx: Unsupported type 0x%x, please "
+      printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
 	     "mail deang@teleport.com\n", inb(SBLKCTL + base));
       outb(0, FLAGS + base);
       return (0);
@@ -3430,26 +4129,12 @@
    */
   if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
   {
-    printk("aic7xxx: Host adapter uses unsupported IRQ level, ignoring.\n");
+    printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
+          "ignoring.\n");
     return (0);
   }
 
   /*
-   * Check the IRQ to see if it is shared by another aic7xxx
-   * controller. If it is and sharing of IRQs is not defined,
-   * then return 0 hosts found. If sharing of IRQs is allowed
-   * or the IRQ is not shared by another host adapter, then
-   * proceed.
-   */
-#ifndef AIC7XXX_SHARE_IRQS
-   if (aic7xxx_boards[config->irq] != NULL)
-   {
-     printk("aic7xxx: Sharing of IRQ's is not configured.\n");
-     return (0);
-   }
-#endif
-
-  /*
    * Print out debugging information before re-enabling
    * the card - a lot of registers on it can't be read
    * when the sequencer is active.
@@ -3469,8 +4154,8 @@
 
     if (SG_STRUCT_CHECK(sg))
     {
-      printk("aic7xxx: Warning - Kernel scatter-gather structures changed, "
-             "disabling it.\n");
+      printk(KERN_WARNING "aic7xxx: Warning - Kernel scatter-gather structures "
+             "changed, disabling it.\n");
       template->sg_tablesize = SG_NONE;
     }
   }
@@ -3484,9 +4169,13 @@
    * information when an IRQ is triggered.
    */
   host = scsi_register(template, sizeof(struct aic7xxx_host));
-  host->can_queue = config->maxscb;
-  host->cmd_per_lun = AIC7XXX_CMDS_PER_LUN;
+  host->can_queue = config->maxscbs;
+  host->cmd_per_lun = 2;
+  host->select_queue_depths = aic7xxx_select_queue_depth;
   host->this_id = config->scsi_id;
+  host->io_port = config->base;
+  host->n_io_port = 0xFF;
+  host->base = (char *)config->mbase;
   host->irq = config->irq;
   if (config->bus_type == AIC_WIDE)
   {
@@ -3500,28 +4189,37 @@
   p = (struct aic7xxx_host *) host->hostdata;
 
   p->host = host;
+  p->host_no = (int)host->host_no;
   p->isr_count = 0;
-  p->a_scanned = FALSE;
-  p->b_scanned = FALSE;
   p->base = base;
-  p->maxscb = config->maxscb;
+  p->maxscbs = config->maxscbs;
+  p->maxhscbs = config->maxhscbs;
   p->qcntmask = config->qcntmask;
-  p->numscb = 0;
-  p->extended = config->extended;
+  p->numscbs = 0;
+  p->mbase = (char *)config->mbase;
   p->type = config->type;
   p->chip_type = config->chip_type;
-  p->ultra_enabled = config->ultra_enabled;
+  p->flags = config->flags;
   p->chan_num = config->chan_num;
   p->bus_type = config->bus_type;
-  p->have_seeprom = have_seeprom;
   p->seeprom = sc;
-  p->free_scb = NULL;
-  p->aborted_scb = NULL;
   p->next = NULL;
+  p->completeq.head = NULL;
+  p->completeq.tail = NULL;
+  scbq_init(&p->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 <= 15; i++)
+  {
+    p->device_status[i].commands_sent = 0;
+    p->device_status[i].flags = 0;
+    p->device_status[i].last_reset = 0;
+  }
   if (aic7xxx_boards[config->irq] == NULL)
   {
     /*
@@ -3536,9 +4234,11 @@
     /*
      * Register IRQ with the kernel.
      */
-    if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx", NULL))
+    if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+       "aic7xxx", NULL))
     {
-      printk("aic7xxx: Couldn't register IRQ %d, ignoring.\n", config->irq);
+      printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
+             config->irq);
       aic7xxx_boards[config->irq] = NULL;
       return (0);
     }
@@ -3561,7 +4261,7 @@
    * but then your mailing address is dynamically assigned
    * so no one can find you anyway :-)
    */
-  printk("aic7xxx: Downloading sequencer code...");
+  printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
   aic7xxx_loadseq(base);
 
   /*
@@ -3589,8 +4289,12 @@
     outb(config->scsi_id_b, SCSIID + base);
     scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
     outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
+#if 1
+    outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
+#else
     outb(ENSELTIMO, SIMODE1 + base);
-    if (p->ultra_enabled)
+#endif
+    if (p->flags & ULTRA_ENABLED)
     {
       outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
     }
@@ -3607,8 +4311,12 @@
   outb(config->scsi_id, SCSIID + base);
   scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
   outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
+#if 1
+  outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
+#else
   outb(ENSELTIMO, SIMODE1 + base);
-  if (p->ultra_enabled)
+#endif
+  if (p->flags & ULTRA_ENABLED)
   {
     outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
   }
@@ -3649,7 +4357,7 @@
   {
     if (config->bios == AIC_DISABLED)
     {
-      printk("aic7xxx : Host adapter BIOS disabled. Using default SCSI "
+      printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
              "device parameters.\n");
       p->discenable = 0xFFFF;
     }
@@ -3662,29 +4370,29 @@
 
   for (i = 0; i < max_targets; i++)
   {
-    if (have_seeprom)
+    if (config->flags & USE_DEFAULTS)
     {
-      target_settings = ((sc.device_flags[i] & CFXFER) << 4);
-      if (sc.device_flags[i] & CFSYNCH)
+      target_settings = 0;  /* 10 MHz */
+      p->needsdtr_copy |= (0x01 << i);
+      p->needwdtr_copy |= (0x01 << i);
+    }
+    else
+    {
+      if (have_seeprom)
       {
-	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);
-      }
-    }
-    else
-    {
-      if (config->use_defaults)
-      {
-        target_settings = 0;  /* 10 MHz */
-        p->needsdtr_copy |= (0x01 << i);
-        p->needwdtr_copy |= (0x01 << i);
+  	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);
+        }
       }
       else
       {
@@ -3703,6 +4411,22 @@
           target_settings &= 0x7F;
         }
       }
+      if (p->flags & ULTRA_ENABLED)
+      {
+        switch (target_settings & 0x70)
+        {
+          case 0x00:
+          case 0x10:
+          case 0x20:
+            ultraenable |= (0x01 << i);
+            break;
+          case 0x40:
+            target_settings &= ~(0x70);
+            break;
+          default:
+            break;
+        }
+      }
     }
     outb(target_settings, (TARG_SCRATCH + base + i));
   }
@@ -3718,26 +4442,28 @@
   }
   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);
 
   /*
-   * For reconnecting targets, the sequencer code needs to
-   * know how many SCBs it has to search through.
+   * Set the number of available SCBs.
    */
-  outb(config->maxscb, SCBCOUNT + base);
+  outb(config->maxhscbs, SCBCOUNT + base);
 
   /*
-   * 2s compliment of SCBCOUNT
+   * 2s compliment of maximum tag value.
    */
-  i = p->maxscb;
+  i = p->maxscbs;
   outb(-i & 0xFF, COMP_SCBCOUNT + base);
 
   /*
    * Set the QCNT (queue count) mask to deal with broken aic7850s that
-   * sporadically get garbage in the upper bits of their QCNT registers.
+   * sporatically get garbage in the upper bits of their QCNT registers.
    */
   outb(config->qcntmask, QCNTMASK + base);
 
@@ -3748,9 +4474,10 @@
   outb(0, ACTIVE_B + base);
 
   /*
-   * We don't have any waiting selections
+   * We don't have any waiting selections or disconnected SCBs.
    */
   outb(SCB_LIST_NULL, WAITING_SCBH + base);
+  outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
 
   /*
    * Message out buffer starts empty
@@ -3769,7 +4496,6 @@
    * Some devices need a long time to "settle" after a SCSI
    * bus reset.
    */
-
   if (!aic7xxx_no_reset)
   {
     printk("aic7xxx: Resetting the SCSI bus...");
@@ -3784,13 +4510,11 @@
       udelay(1000);
       outb(0, SCSISEQ + base);
 
-      /*
-       * Ensure we don't get a RSTI interrupt from this.
-       */
+      /* Ensure we don't get a RSTI interrupt from this. */
       outb(CLRSCSIRSTI, CLRSINT1 + base);
       outb(CLRSCSIINT, CLRINT + base);
 
-      /*
+     /*
        * Select Channel A.
        */
       outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
@@ -3800,9 +4524,7 @@
     udelay(1000);
     outb(0, SCSISEQ + base);
 
-    /*
-     * Ensure we don't get a RSTI interrupt from this.
-     */
+    /* Ensure we don't get a RSTI interrupt from this. */
     outb(CLRSCSIRSTI, CLRSINT1 + base);
     outb(CLRSCSIINT, CLRINT + base);
 
@@ -3862,7 +4584,7 @@
   {
     base = SLOTBASE(slot) + MINREG;
 
-    if (check_region(MINREG + base, MAXREG - MINREG))
+    if (check_region(base, MAXREG - MINREG))
     {
       /*
        * Some other driver has staked a
@@ -3886,14 +4608,16 @@
        */
       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.ultra_enabled = FALSE;
-      config.extended = aic7xxx_extended;
+      config.flags = 0;
+      if (aic7xxx_extended)
+        config.flags |= EXTENDED_TRANSLATION;
       config.bus_speed = DFTHRSH_100;
-      config.busrtime = BOFF_60BCLKS;
+      config.busrtime = BOFF;
       found += aic7xxx_register(template, &config);
 
       /*
@@ -3918,6 +4642,7 @@
     } 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_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},
@@ -3932,7 +4657,7 @@
 
     int error;
     int done = 0;
-    unsigned int io_port;
+    unsigned int iobase, mbase;
     unsigned short index = 0;
     unsigned char pci_bus, pci_device_fn;
     unsigned int  csize_lattime;
@@ -3949,6 +4674,7 @@
                                 aic7xxx_pci_devices[i].device_id,
                                 index, &pci_bus, &pci_device_fn))
         {
+          index = 0;
           done = TRUE;
         }
         else  /* Found an Adaptec PCI device. */
@@ -3957,34 +4683,31 @@
           config.chip_type = aic7xxx_pci_devices[i].chip_type;
           config.chan_num = 0;
           config.bios = AIC_ENABLED;  /* Assume bios is enabled. */
-          config.use_defaults = FALSE;
+          config.flags = 0;
           config.busrtime = 40;
           switch (config.type)
           {
             case AIC_7850:
             case AIC_7855:
+            case AIC_7860:
               config.bios = AIC_DISABLED;
-              config.use_defaults = TRUE;
+              config.flags |= USE_DEFAULTS;
               config.bus_speed = DFTHRSH_100;
               break;
 
             case AIC_7872:  /* 3940 */
             case AIC_7882:  /* 3940-Ultra */
-              config.chan_num = number_of_39xxs & 0x01;  /* Has 2 controllers */
-              number_of_39xxs++;
-              if (number_of_39xxs == 2)
-              {
-                number_of_39xxs = 0;  /* To be consistent with 3985. */
-              }
+              config.chan_num = number_of_3940s & 0x1;  /* Has 2 controllers */
+              number_of_3940s++;
               break;
 
             case AIC_7873:  /* 3985 */
             case AIC_7883:  /* 3985-Ultra */
-              config.chan_num = number_of_39xxs & 0x03;  /* Has 3 controllers */
-              number_of_39xxs++;
-              if (number_of_39xxs == 3)
+              config.chan_num = number_of_3985s & 0x3;  /* Has 3 controllers */
+              number_of_3985s++;
+              if (number_of_3985s == 3)
               {
-                number_of_39xxs = 0;
+                number_of_3985s = 0;
               }
               break;
 
@@ -3996,43 +4719,32 @@
            * Read sundry information from PCI BIOS.
            */
           error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-                                            PCI_BASE_ADDRESS_0, &io_port);
+                                            PCI_BASE_ADDRESS_0, &iobase);
           error += pcibios_read_config_byte(pci_bus, pci_device_fn,
                                             PCI_INTERRUPT_LINE, &irq);
+          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                            PCI_BASE_ADDRESS_1, &mbase);
 
           /*
-           * Ensure that we are using good values for the PCI burst size
-           * and latency timer.
+           * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+           * we mask it off.
+           */
+          iobase &= PCI_BASE_ADDRESS_IO_MASK;
+
+          /*
+           * Read the PCI burst size and latency timer.
            */
           error += pcibios_read_config_dword(pci_bus, pci_device_fn,
                                              CSIZE_LATTIME, &csize_lattime);
-          if ((csize_lattime & CACHESIZE) == 0)
-          {
-            /*
-             * Default to 8DWDs - what's the PCI define for this?
-             */
-            csize_lattime |= 8;
-          }
-
-          if ((csize_lattime & LATTIME) == 0)
-          {
-            /*
-             * Default to 64 PCLKS (is this a good value?)
-             * This may also be available in the SEEPROM??
-             */
-            csize_lattime |= (64 << 8);
-          }
-          pcibios_write_config_dword(pci_bus, pci_device_fn,
-                                     CSIZE_LATTIME, csize_lattime);
-          printk("aic7xxx: BurstLen = %d DWDs, Latency Timer = %d PCLKS\n",
-                  (int) (csize_lattime & CACHESIZE),
-                  (csize_lattime >> 8) & 0x000000ff);
+          printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
+                 "PCLKS\n", (int) (csize_lattime & CACHESIZE),
+                 (csize_lattime >> 8) & 0x000000ff);
 
           error += pcibios_read_config_dword(pci_bus, pci_device_fn,
                                              CLASS_PROGIF_REVID, &class_revid);
           if ((class_revid & DEVREVID) < 3)
           {
-            printk("aic7xxx: %s Rev %c.\n", board_names[config.type],
+            printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
                    rev_id[class_revid & DEVREVID]);
           }
 
@@ -4044,13 +4756,7 @@
                   error);
           }
 
-          printk("aic7xxx: devconfig = 0x%x.\n", devconfig);
-
-          /*
-           * The first bit of PCI_BASE_ADDRESS_0 is always set, so
-           * we mask it off.
-           */
-          base = io_port & 0xFFFFFFFE;
+          printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
 
           /*
            * I don't think we need to bother with allowing
@@ -4059,13 +4765,14 @@
            */
           aic7xxx_spurious_count = 1;
 
-          config.base = base;
+          config.base = iobase;
+          config.mbase = mbase;
           config.irq = irq;
           config.parity = AIC_ENABLED;
           config.low_term = AIC_UNKNOWN;
           config.high_term = AIC_UNKNOWN;
-          config.extended = aic7xxx_extended;
-          config.ultra_enabled = FALSE;
+          if (aic7xxx_extended)
+            config.flags |= EXTENDED_TRANSLATION;
           if (devconfig & RAMPSM)
           {
             /*
@@ -4084,7 +4791,8 @@
              * sixteen bits of the register are R/O anyway, so it shouldn't
              * affect RAMPSM either way.
              */
-            printk ("aic7xxx: External RAM detected. Enabling RAM access.\n");
+            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);
@@ -4123,26 +4831,32 @@
   unsigned short mask;
   struct scatterlist *sg;
 
+  mask = (0x01 << TARGET_INDEX(cmd));
   /*
    * Setup the control byte if we need negotiation and have not
    * already requested it.
    */
 #ifdef AIC7XXX_TAGGED_QUEUEING
-  if (cmd->device->tagged_supported)
+  if (cmd->device->tagged_queue)
   {
-    if (cmd->device->tagged_queue == 0)
+    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)
     {
-      printk("aic7xxx: Enabling tagged queuing for target %d, "
-	     "channel %d.\n", cmd->target, cmd->channel);
-      cmd->device->tagged_queue = 1;
-      cmd->device->current_tag = 1;  /* enable tagging */
+      scb->control |= 0x02;
+      p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
     }
-    cmd->tag = cmd->device->current_tag;
-    cmd->device->current_tag++;
-    scb->control |= TAG_ENB;
+#if 0
+    if (p->orderedtag & mask)
+    {
+      scb->control |= 0x02;
+      p->orderedtag = p->orderedtag & ~mask;
+    }
+#endif
   }
 #endif
-  mask = (0x01 << (cmd->target | (cmd->channel << 3)));
   if (p->discenable & mask)
   {
     scb->control |= DISCENB;
@@ -4247,23 +4961,24 @@
   long flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+  u_char curscb;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
 
   /*
    * Check to see if channel was scanned.
    */
-  if (!p->a_scanned && (cmd->channel == 0))
+  if (!(p->flags & A_SCANNED) && (cmd->channel == 0))
   {
-    printk("aic7xxx: Scanning channel A for devices.\n");
-    p->a_scanned = TRUE;
+    printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no);
+    p->flags |= A_SCANNED;
   }
   else
   {
-    if (!p->b_scanned && (cmd->channel == 1))
+    if (!(p->flags & B_SCANNED) && (cmd->channel == 1))
     {
-      printk("aic7xxx: Scanning channel B for devices.\n");
-      p->b_scanned = TRUE;
+      printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no);
+      p->flags |= B_SCANNED;
     }
   }
 
@@ -4283,109 +4998,98 @@
   save_flags(flags);
   cli();
 
-  /*
-   * Find a free slot in the SCB array to load this command
-   * into. Since can_queue is set to the maximum number of
-   * SCBs for the card, we should always find one.
-   *
-   * First try to find an scb in the free list. If there are
-   * none in the free list, then check the current number of
-   * of scbs and take an unused one from the scb array.
-   */
-  scb = p->free_scb;
-  if (scb != NULL)
-  { /* found one in the free list */
-    p->free_scb = scb->next;   /* remove and update head of list */
-    /*
-     * Warning! For some unknown reason, the scb at the head
-     * of the free list is not the same address that it should
-     * be. That's why we set the scb pointer taken by the
-     * position in the array. The scb at the head of the list
-     * should match this address, but it doesn't.
-     */
-    scb = &(p->scb_array[scb->position]);
-    scb->control = 0;
-    scb->state = SCB_ACTIVE;
+  scb = aic7xxx_allocate_scb(p);
+  if (scb == NULL)
+  {
+    panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
   }
   else
   {
-    if (p->numscb >= p->maxscb)
-    {
-      panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
-    }
-    else
-    {
-      /*
-       * Initialize the scb within the scb array. The
-       * position within the array is the position on
-       * the board that it will be loaded.
-       */
-      scb = &(p->scb_array[p->numscb]);
-      memset(scb, 0, sizeof(*scb));
-
-      scb->position = p->numscb;
-      p->numscb++;
-      scb->state = SCB_ACTIVE;
-    }
-  }
-
-  scb->cmd = cmd;
-  aic7xxx_position(cmd) = scb->position;
+    scb->cmd = cmd;
+    aic7xxx_position(cmd) = scb->tag;
 #if 0
-  debug_scb(scb);
+    debug_scb(scb);
 #endif;
 
-  /*
-   * Construct the SCB beforehand, so the sequencer is
-   * paused a minimal amount of time.
-   */
-  aic7xxx_buildscb(p, cmd, scb);
+    /*
+     * Construct the SCB beforehand, so the sequencer is
+     * paused a minimal amount of time.
+     */
+    aic7xxx_buildscb(p, cmd, scb);
 
 #if 0
-  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->position, (unsigned int) scb->cmd,
-	 scb->state, (unsigned int) p->free_scb);
+    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->position, (unsigned int) scb->cmd,
+	   scb->state, (unsigned int) p->free_scb);
 #endif
 
-  /*
-   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
-   * is set up properly, and the parity error flag is reset, then send
-   * the SCB to the sequencer and watch the fun begin.
-   */
-  cmd->scsi_done = fn;
-  aic7xxx_error(cmd) = DID_OK;
-  aic7xxx_status(cmd) = 0;
-  cmd->result = 0;
-  memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+    /*
+     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+     * is set up properly, and the parity error flag is reset, then send
+     * the SCB to the sequencer and watch the fun begin.
+     */
+    cmd->scsi_done = fn;
+    aic7xxx_error(cmd) = DID_OK;
+    aic7xxx_status(cmd) = 0;
+    cmd->result = 0;
+    cmd->host_scribble = NULL;
+    memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
 
-  /*
-   * 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);
+    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);
 
-  /*
-   * 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.
-   */
-  aic7xxx_putscb(p, scb);
-  outb(scb->position, QINFIFO + 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;
+
+        UNPAUSE_SEQUENCER(p);
+      }
+    }
+    else
+    {
+      scb->state |= SCB_WAITINGQ;
+      scbq_insert_tail(&p->waiting_scbs, scb);
+      if (!(p->flags & IN_ISR))
+      {
+        aic7xxx_run_waiting_queues(p);
+      }
+    }
 
-  UNPAUSE_SEQUENCER(p);
 #if 0
-  printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
-         (long) cmd, (long) scb->cmd, scb->position);
+    printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
+           (long) cmd, (long) scb->cmd, scb->position);
 #endif;
-  restore_flags(flags);
+    restore_flags(flags);
+  }
   return (0);
 }
 
@@ -4400,201 +5104,208 @@
  *   aborted, then we will reset the channel and have all devices renegotiate.
  *   Returns an enumerated type that indicates the status of the operation.
  *-F*************************************************************************/
-static aha_abort_reset_type
-aic7xxx_abort_reset(Scsi_Cmnd *cmd, unsigned char errcode)
+static int
+aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
   struct aic7xxx_scb  *scb;
-  struct aic7xxx_host *p;
   long flags;
   unsigned char bus_state;
-  aha_abort_reset_type scb_status = ABORT_RESET_SUCCESS;
-  int base, found;
+  int base, result = -1;
   char channel;
 
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = &(p->scb_array[aic7xxx_position(cmd)]);
   base = p->base;
-  channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
-
-  save_flags(flags);
-  cli();
 
-  if (scb->state & SCB_ACTIVE)
+  channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
+  if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
   {
-    /*
-     * Ensure that the card doesn't do anything
-     * behind our back.
-     */
-    PAUSE_SEQUENCER(p);
 
-    printk ("aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
-    bus_state = inb(LASTPHASE + p->base);
-
-    switch (bus_state)
-    {
-      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);
-        /*
-         * We're not in a valid phase, so assume we're idle.
-         */
-        bus_state = 0;
-        break;
-    }
-    printk ("SCSISIGI = 0x%x\n", inb (p->base + SCSISIGI));
+    save_flags(flags);
+    cli();
 
-    /*
-     * 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,
-     * 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)
+    if (scb->state & SCB_IN_PROGRESS)
     {
       /*
-       * Been down this road before.  Do a full bus reset.
+       * Ensure that the card doesn't do anything
+       * behind our back.
        */
-      found = aic7xxx_reset_channel(p, channel, scb->position, TRUE);
-    }
-    else
-    {
-      unsigned char active_scb, control;
-      struct aic7xxx_scb *active_scbp;
+      PAUSE_SEQUENCER(p);
 
-      /*
-       * 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, it's 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 it's 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
-       * 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[active_scb]);
-      control = inb(SCB_CONTROL + base);
+      printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
+      bus_state = inb(LASTPHASE + p->base);
+
+      switch (bus_state)
+      {
+	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);
+          /*
+           * We're not in a valid phase, so assume we're idle.
+           */
+          bus_state = 0;
+          break;
+      }
+      printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
 
       /*
-       * Test to see if scbp is 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.
        */
-      outb(scb->position, SCBPTR + base);
-      if (inb(SCB_CONTROL + base) & DISCONNECTED)
+      if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
       {
-#ifdef AIC7XXX_DEBUG_ABORT
-        printk ("aic7xxx: (abort_scb) scb %d is disconnected; "
-                "bus device reset message queued.\n", scb->position);
+#if 0
+	if (scb->control & TAG_ENB)
+	{
+          /*
+           * We could be starving this command; try sending and ordered tag
+           * command to the target we come from.
+           */
+          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
-	scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
-	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);
-	aic7xxx_error(scb->cmd) = errcode;
-	scb_status = ABORT_RESET_PENDING;
-	outb(active_scb, SCBPTR + base);
-	UNPAUSE_SEQUENCER(p);
-      }
-      else
-      {
+	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);
+
 	/*
-	 * Is the active SCB really active?
+	 * Test to see if scbp is disconnected
 	 */
-	if ((active_scbp->state & SCB_ACTIVE) && bus_state)
+	outb(scb->position, SCBPTR + base);
+	if (inb(SCB_CONTROL + base) & DISCONNECTED)
 	{
-          /*
-           * 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");
+          printk("aic7xxx: (abort_scb) scb %d is disconnected; "
+                 "bus device reset message queued.\n", scb->position);
 #endif
-          if (active_scbp != scb)
+          if (p->flags & PAGE_ENABLED)
           {
-            /*
-             * 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.
-             */
-            ;
+            /* 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);
+            }
           }
-          aic7xxx_error(scb->cmd) = errcode;
-          scb_status = ABORT_RESET_PENDING;
-          /*
-           * Restore the active SCB and unpause the sequencer.
-           */
-          outb(active_scb, SCBPTR + base);
-
-          UNPAUSE_SEQUENCER(p);
+	  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) no active command.\n");
+            printk("aic7xxx: (abort_scb) asserted ATN - "
+                   "bus device reset in message buffer.\n");
 #endif
-          /*
-           * No active command to single out, so reset
-           * the bus for the timed out target.
-           */
-          aic7xxx_reset_channel(p, channel, scb->position, TRUE);
+            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);
+	  }
 	}
       }
     }
+    restore_flags(flags);
   }
-  else
-  {
-    /*
-     * The scb is not active and must have completed after the timeout
-     * check in scsi.c and before we check the scb state above.  For
-     * this case we return SCSI_ABORT_NOT_RUNNING (if abort was called)
-     * or SCSI_RESET_SUCCESS (if reset was called).
-     */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk ("aic7xxx: (abort_reset) called with no active scb, errcode 0x%x\n",
-            errcode);
-#endif
-    scb_status = ABORT_RESET_INACTIVE;
-    /*
-     * According to the comments in scsi.h and Michael Neuffer, if we do not
-     * have an active command for abort or reset, we should not call the
-     * command done function.  Unfortunately, this hangs the system for me
-     * unless we *do* call the done function.
-     *
-     * XXX - Revisit this sometime!
-     */
-    cmd->result = errcode << 16;
-    cmd->scsi_done(cmd);
-  }
-
-  restore_flags(flags);
-  return (scb_status);
+  return (result);
 }
 
 
@@ -4608,25 +5319,39 @@
 int
 aic7xxx_abort(Scsi_Cmnd *cmd)
 {
+  struct aic7xxx_scb  *scb = NULL;
+  struct aic7xxx_host *p;
+  int    base, result;
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = &(p->scb_array[aic7xxx_position(cmd)]);
+  base = p->base;
+
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (abort) target/channel %d/%d\n", cmd->target, cmd->channel);
+  printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
+         scb->position, TCL_OF_SCB(scb));
 #endif
 
-  switch (aic7xxx_abort_reset(cmd, DID_ABORT))
+  if (cmd->serial_number != cmd->serial_number_at_timeout)
   {
-    case ABORT_RESET_INACTIVE:
-      return (SCSI_ABORT_NOT_RUNNING);
-      break;
-    case ABORT_RESET_PENDING:
-      return (SCSI_ABORT_PENDING);
-      break;
-    case ABORT_RESET_SUCCESS:
-    default:
-      return (SCSI_ABORT_SUCCESS);
-      break;
+    result = SCSI_ABORT_NOT_RUNNING;
   }
+  else if (scb == NULL)
+  {
+    result = SCSI_ABORT_NOT_RUNNING;
+  }
+  else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
+  {
+    result = SCSI_ABORT_NOT_RUNNING;
+  }
+  else
+  {
+    result = SCSI_ABORT_SNOOZE;
+  }
+  return (result);
 }
 
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset
@@ -4638,25 +5363,150 @@
  *   the SCSI bus reset line.
  *-F*************************************************************************/
 int
-aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
+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, result = -1;
+  char   channel = 'A';
+
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = &(p->scb_array[aic7xxx_position(cmd)]);
+  base = p->base;
+  channel = cmd->channel ? 'B': 'A';
+  tindex = (cmd->channel << 4) | cmd->target;
+
 #ifdef AIC7XXX_DEBUG_ABORT
-  printk ("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
+  printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
 #endif
 
-  switch (aic7xxx_abort_reset(cmd, DID_RESET))
+  if (scb->cmd != cmd)
+    scb = NULL;
+
+  if (!(flags & SCSI_RESET_SUGGEST_HOST_RESET) && (scb != NULL))
   {
-    case ABORT_RESET_PENDING:
-      return (SCSI_RESET_PENDING);
-      break;
-    case ABORT_RESET_SUCCESS:
-      return (SCSI_RESET_BUS_RESET | SCSI_RESET_SUCCESS);
-      break;
-    case ABORT_RESET_INACTIVE:
-    default:
-      return (SCSI_RESET_SUCCESS);
-      break;
+    /*
+     * 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)
+      {
+        result = SCSI_RESET_NOT_RUNNING;
+      }
+      else
+      {
+        if (scb == NULL)
+        {
+          result = SCSI_RESET_NOT_RUNNING;
+        }
+        else if (flags & SCSI_RESET_ASYNCHRONOUS)
+        {
+          if (scb->state & SCB_ABORTED)
+          {
+            result = SCSI_RESET_PENDING;
+          }
+          else if (!(scb->state & SCB_IN_PROGRESS))
+          {
+            result = SCSI_RESET_NOT_RUNNING;
+          }
+        }
+
+        if (result == -1)
+        {
+          if ((flags & SCSI_RESET_SYNCHRONOUS) &&
+              (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
+          {
+            scb->state |= SCB_ABORTED;
+            result = SCSI_RESET_PENDING;
+          }
+          else
+          {
+            result = aic7xxx_bus_device_reset(p, cmd);
+            if (result == 0)
+              result = SCSI_RESET_PENDING;
+          }
+        }
+      }
+    }
+  }
+
+  if (result == -1)
+  {
+    /*
+     * The bus device reset failed; try resetting the channel.
+     */
+    if (flags & SCSI_RESET_ASYNCHRONOUS)
+    {
+      if (scb == NULL)
+      {
+	result = SCSI_RESET_NOT_RUNNING;
+      }
+      else if (!(scb->state & SCB_IN_PROGRESS))
+      {
+	result = SCSI_RESET_NOT_RUNNING;
+      }
+      else if ((scb->state & SCB_ABORTED) &&
+               (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
+      {
+	result = SCSI_RESET_PENDING;
+      }
+    }
+
+    if (result == -1)
+    {
+      found = aic7xxx_reset_channel(p, channel, TRUE);
+
+      /*
+       * If this is a synchronous reset and there is no SCB for this
+       * command, perform completion processing.
+       *
+       */
+      if ((flags & SCSI_RESET_SYNCHRONOUS) && (scb == NULL))
+      {
+	cmd->result = DID_RESET << 16;
+	cmd->scsi_done(cmd);
+      }
+
+      switch (p->bus_type)
+      {
+	case AIC_TWIN:
+	  if (channel == 'B')
+	  {
+            min_target = 8;
+            max_target = 15;
+	  }
+	  else
+	  {
+            min_target = 0;
+            max_target = 7;
+	  }
+	  break;
+
+	case AIC_WIDE:
+	  min_target = 0;
+	  max_target = 15;
+	  break;
+
+	case AIC_SINGLE:
+        default:
+	  min_target = 0;
+	  max_target = 7;
+	  break;
+      }
+
+      for (tindex = min_target; tindex <= max_target; tindex++)
+      {
+	p->device_status[tindex].last_reset = jiffies;
+      }
+
+      result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+    }
   }
+  return (result);
 }
 
 /*+F*************************************************************************
@@ -4683,7 +5533,7 @@
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);
 
-  if (p->extended && (cylinders > 1024))
+  if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024))
   {
     heads = 255;
     sectors = 63;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov