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

Next file: linux/drivers/scsi/aic7xxx_proc.c
Previous file: linux/drivers/scsi/aha1542.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.36/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -100,7 +100,7 @@
  *
  * Further driver modifications made by Doug Ledford <dledford@redhat.com>
  *
- * Copyright (c) 1997-1998 Doug Ledford
+ * Copyright (c) 1997-1999 Doug Ledford
  *
  * These changes are released under the same licensing terms as the FreeBSD
  * driver written by Justin Gibbs.  Please see his Copyright notice above
@@ -336,6 +336,7 @@
 #include "aic7xxx/sequencer.h"
 #include "aic7xxx/scsi_message.h"
 #include "aic7xxx_reg.h"
+#include <scsi/scsicam.h>
 
 #include <linux/stat.h>
 #include <linux/malloc.h>        /* for kmalloc() */
@@ -354,7 +355,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.4"
+#define AIC7XXX_C_VERSION  "5.1.13"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -447,8 +448,10 @@
  * You can try raising me if tagged queueing is enabled, or lowering
  * me if you only have 4 SCBs.
  */
-#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
-#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#else
+#define AIC7XXX_CMDS_PER_DEVICE 8
 #endif
 
 /* Set this to the delay in seconds after SCSI bus reset. */
@@ -493,7 +496,7 @@
  *
  * *** Determining commands per LUN ***
  * 
- * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
  * own algorithm to determine the commands/LUN.  If SCB paging is
  * enabled, which is always now, the default is 8 commands per lun
  * that indicates it supports tagged queueing.  All non-tagged devices
@@ -511,8 +514,13 @@
  * Make a define that will tell the driver not to use tagged queueing
  * by default.
  */
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+                              0, 0, 0, 0, 0, 0, 0, 0}
+#else
 #define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
                               255, 255, 255, 255, 255, 255, 255, 255}
+#endif
 
 /*
  * Modify this as you see fit for your system.  By setting tag_commands
@@ -551,6 +559,27 @@
 };
 */
 
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+
 /*
  * Define an array of board names that can be indexed by aha_type.
  * Don't forget to change this when changing the types!
@@ -577,9 +606,14 @@
   "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
   "Adaptec AIC-7895 Ultra SCSI host adapter",           /* AIC_7895 */
   "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
+  "Adaptec AHA-293X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
   "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
-  "Adaptec AHA-394X Ultra2 SCSI host adapter"           /* AIC_7897 */
+  "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
+  "Adaptec AIC-7892 Ultra 160/m SCSI host adapter",     /* AIC_7892 */
+  "Adaptec AIC-7899 Ultra 160/m SCSI host adapter",     /* AIC_7899 */
 };
 
 /*
@@ -882,6 +916,7 @@
   *  and what flags weren't.  This way, I could clean up the flag usage on
   *  a use by use basis.  Doug Ledford
   */
+        AHC_RESET_DELAY           = 0x00080000,
         AHC_A_SCANNED             = 0x00100000,
         AHC_B_SCANNED             = 0x00200000,
         AHC_MULTI_CHANNEL         = 0x00400000,
@@ -908,6 +943,8 @@
   AHC_AIC7890          = 0x0006,
   AHC_AIC7895          = 0x0007,
   AHC_AIC7896          = 0x0008,
+  AHC_AIC7892          = 0x0009,
+  AHC_AIC7899          = 0x000a,
   AHC_VL               = 0x0100,
   AHC_EISA             = 0x0200,
   AHC_PCI              = 0x0400,
@@ -924,6 +961,7 @@
   AHC_QUEUE_REGS       = 0x0040,
   AHC_SG_PRELOAD       = 0x0080,
   AHC_SPIOCAP          = 0x0100,
+  AHC_ULTRA160         = 0x0200,
   AHC_AIC7770_FE       = AHC_FENONE,
   AHC_AIC7850_FE       = AHC_SPIOCAP,
   AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
@@ -933,6 +971,8 @@
                          AHC_QUEUE_REGS|AHC_SG_PRELOAD,
   AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
   AHC_AIC7896_FE       = AHC_AIC7890_FE,
+  AHC_AIC7892_FE       = AHC_AIC7890_FE|AHC_ULTRA160,
+  AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA160,
 } ahc_feature;
 
 struct aic7xxx_scb {
@@ -941,7 +981,6 @@
         struct aic7xxx_scb    *q_next;        /* next scb in queue */
         volatile scb_flag_type flags;         /* current state of scb */
         struct hw_scatterlist *sg_list;       /* SG list in adapter format */
-        void                  *kmalloc_ptr;
         unsigned char          tag_action;
         unsigned char          sg_count;
         unsigned char          sense_cmd[6];  /*
@@ -952,6 +991,7 @@
                                            * don't have to calculate anything
                                            * during underflow/overflow/stat code
                                            */
+        void                  *kmalloc_ptr;
 };
 
 /*
@@ -1029,88 +1069,73 @@
    *  This is the first 64 bytes in the host struct
    */
 
-  struct Scsi_Host        *host;             /* pointer to scsi host */
-  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
-  int                      host_no;          /* SCSI host number */
-  unsigned long            base;             /* card base address */
-  volatile unsigned char  *maddr;            /* memory mapped address */
-  unsigned long            mbase;            /* I/O memory address */
+  /*
+   * We are grouping things here....first, items that get either read or
+   * written with nearly every interrupt
+   */
   volatile ahc_flag_type   flags;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
-  spinlock_t               spin_lock;
-#endif
-  volatile unsigned char   cpu_lock_count[NR_CPUS];
-  ahc_chip                 chip;             /* chip type */
   ahc_feature              features;         /* chip features */
-  unsigned long            last_reset;
+  unsigned long            base;             /* card base address */
+  volatile unsigned char  *maddr;            /* memory mapped address */
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
-  struct target_cmd       *targetcmds;
-  unsigned int             num_targetcmds;
+  scb_data_type           *scb_data;
+  volatile unsigned short  needsdtr;
+  volatile unsigned short  sdtr_pending;
+  volatile unsigned short  needwdtr;
+  volatile unsigned short  wdtr_pending;
+  struct aic7xxx_cmd_queue {
+    Scsi_Cmnd *head;
+    Scsi_Cmnd *tail;
+  } completeq;
+
+  /*
+   * Things read/written on nearly every entry into aic7xxx_queue()
+   */
+  volatile scb_queue_type  waiting_scbs;
   unsigned short           discenable;       /* Targets allowed to disconnect */
   unsigned short           tagenable;        /* Targets using tagged I/O */
   unsigned short           orderedtag;       /* Ordered Q tags allowed */
-  volatile unsigned char   activescbs;       /* active scbs */
-  volatile unsigned char   max_activescbs;
   unsigned char            unpause;          /* unpause value for HCNTRL */
   unsigned char            pause;            /* pause value for HCNTRL */
   volatile unsigned char   qoutfifonext;
+  volatile unsigned char   activescbs;       /* active scbs */
+  volatile unsigned char   max_activescbs;
   volatile unsigned char   qinfifonext;
 
-  /*
-   * MAX_TARGETS is currently == 16, so that makes these entries the next
-   * 64 bytes
-   */
-
 #define  DEVICE_PRESENT                 0x01
 #define  BUS_DEVICE_RESET_PENDING       0x02
-#define  DEVICE_TIMEOUT                 0x04
+#define  DEVICE_RESET_DELAY             0x04
 #define  DEVICE_PRINT_SDTR              0x08
 #define  DEVICE_PRINT_WDTR              0x10
-#define  DEVICE_SUCCESS                 0x20
-#define  DEVICE_TAGGED_SUCCESS          0x40
+#define  DEVICE_WAS_BUSY                0x20
 #define  DEVICE_SCANNED                 0x80
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
   unsigned char            dev_commands_sent[MAX_TARGETS];
 
-  /*
-   * The next 128 (or 256 on 64 bit machines)....
-   */
-  Scsi_Cmnd               *dev_wdtr_cmnd[MAX_TARGETS];
-  Scsi_Cmnd               *dev_sdtr_cmnd[MAX_TARGETS];
+  unsigned int             dev_timer_active; /* Which devs have a timer set */
+  struct timer_list        dev_timer;
+  unsigned long            dev_expires[MAX_TARGETS];
 
-  /*
-   * The next 64.... 
-   */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+#endif
 
-  long                     dev_last_reset[MAX_TARGETS];
 
-  /*
-   * The next 64....
-   */
+#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+  Scsi_Cmnd               *dev_wdtr_cmnd[MAX_TARGETS];
+  Scsi_Cmnd               *dev_sdtr_cmnd[MAX_TARGETS];
+#endif
 
-  unsigned char            dev_mid_level_queue_depth[MAX_TARGETS];
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
   unsigned char            dev_max_queue_depth[MAX_TARGETS];
 
-  /*
-   * The next 128....
-   */
-
   volatile scb_queue_type  delayed_scbs[MAX_TARGETS];
 
-  /*
-   *
-   */
-
-  struct timer_list        dev_timer[MAX_TARGETS];
-
-  /*
-   * The next 64....
-   */
 
   unsigned char            msg_buf[9];       /* The message for the target */
   unsigned char            msg_type;
@@ -1120,16 +1145,6 @@
   unsigned char            msg_len;          /* Length of message */
   unsigned char            msg_index;        /* Index into msg_buf array */
   transinfo_type           transinfo[MAX_TARGETS];
-  volatile scb_queue_type  waiting_scbs;     /*
-                                              * SCBs waiting for space in
-                                              * the QINFIFO.
-                                              */
-  scb_data_type           *scb_data;
-
-  struct aic7xxx_cmd_queue {
-    Scsi_Cmnd *head;
-    Scsi_Cmnd *tail;
-  } completeq;
 
 
   /*
@@ -1147,16 +1162,11 @@
   volatile unsigned char   qoutfifo[256];
   volatile unsigned char   qinfifo[256];
   unsigned int             irq;              /* IRQ for this adapter */
-  volatile unsigned short  needsdtr;
-  volatile unsigned short  sdtr_pending;
-  volatile unsigned short  needwdtr;
-  volatile unsigned short  wdtr_pending;
   int                      instance;         /* aic7xxx instance number */
   int                      scsi_id;          /* host adapter SCSI ID */
   int                      scsi_id_b;        /* channel B for twin adapters */
   unsigned int             bios_address;
   int                      board_name_index;
-  unsigned long            reset_start;
   unsigned short           needsdtr_copy;    /* default config */
   unsigned short           needwdtr_copy;    /* default config */
   unsigned short           ultraenb;         /* Ultra mode target list */
@@ -1170,6 +1180,11 @@
   struct seeprom_config    sc;
   unsigned short           sc_type;
   unsigned short           sc_size;
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
+  struct Scsi_Host        *host;             /* pointer to scsi host */
+  int                      host_no;          /* SCSI host number */
+  unsigned long            mbase;            /* I/O memory address */
+  ahc_chip                 chip;             /* chip type */
 
   /*
    * Statistics Kept:
@@ -1184,21 +1199,27 @@
    *
    * NOTE: Enabling this feature is likely to cause a noticeable performance
    * decrease as the accesses into the stats structures blows apart multiple
-   * cache lines and is CPU time consuming.  We keep the xfer count always
-   * for use by the aic7xxx_proc.c code, but only do the bins if the
-   * proc stats code is enabled.
+   * cache lines and is CPU time consuming.
+   *
+   * NOTE: Since it doesn't really buy us much, but consumes *tons* of RAM
+   * and blows apart all sorts of cache lines, I modified this so that we
+   * no longer look at the LUN.  All LUNs now go into the same bin on each
+   * device for stats purposes.
    */
   struct aic7xxx_xferstats {
-    long xfers;                              /* total xfer count */
-    long w_total;                            /* total writes */
-    long w_total512;                         /* 512 byte blocks written */
-    long r_total;                            /* total reads */
-    long r_total512;                         /* 512 byte blocks read */
+    long w_total;                          /* total writes */
+    long r_total;                          /* total reads */
 #ifdef AIC7XXX_PROC_STATS
-    long w_bins[10];                         /* binned write */
-    long r_bins[10];                         /* binned reads */
+    long w_bins[8];                       /* binned write */
+    long r_bins[8];                       /* binned reads */
 #endif /* AIC7XXX_PROC_STATS */
-  } stats[MAX_TARGETS][MAX_LUNS];            /* [(channel << 3)|target][lun] */
+  } stats[MAX_TARGETS];                    /* [(channel << 3)|target] */
+
+#if 0
+  struct target_cmd       *targetcmds;
+  unsigned int             num_targetcmds;
+#endif
+
 };
 
 /*
@@ -1282,11 +1303,9 @@
  */
 static int aic7xxx_reverse_scan = 0;
 /*
- * This setting enables a hack to fix the IRQ settings on buggy 7895
- * MB controller setups:
- *    -1 == Disable this hack
- *     0 == Use the Channel A IRQ for both channels
- *     1 == Use the Channel B IRQ for both channels
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
  */
 static unsigned int aic7xxx_extended = 0;
 /*
@@ -1426,35 +1445,6 @@
 
 #endif
 
-/*
- * See the comments earlier in the file for what this item is all about
- * If you have more than 4 controllers, you will need to increase the
- * the number of items in the array below.  Additionally, if you don't
- * want to have lilo pass a humongous config line to the aic7xxx driver,
- * then you can get in and manually adjust these instead of leaving them
- * at the default.  Pay attention to the comments earlier in this file
- * concerning this array if you are going to hand modify these values.
- */
-static adapter_tag_info_t aic7xxx_tag_info[] =
-{
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS},
-  {DEFAULT_TAG_COMMANDS}
-};
-
 #define VERBOSE_NORMAL         0x0000
 #define VERBOSE_NEGOTIATION    0x0001
 #define VERBOSE_SEQINT         0x0002
@@ -1511,6 +1501,21 @@
   for(i=0; i<milliseconds; i++)
     udelay(1000);
 }
+
+static inline int
+time_after_eq(unsigned long a, unsigned long b)
+{
+  return((long)((a) - (b)) >= 0L);
+}
+
+static inline int
+timer_pending(struct timer_list *timer)
+{
+  return( timer->prev != NULL );
+}
+
+#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
+
 #endif
 
 static inline unsigned char
@@ -1950,7 +1955,10 @@
   {
     printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
   }
+#if 0
   download_consts[TMODE_NUMCMDS] = p->num_targetcmds;
+#endif
+  download_consts[TMODE_NUMCMDS] = 0;
   cur_patch = &sequencer_patches[0];
   downloaded = 0;
   skip_addr = 0;
@@ -2794,6 +2802,7 @@
   Scsi_Cmnd *cmd;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned int cpu_flags = 0;
+#endif
   
   DRIVER_LOCK
   while (p->completeq.head != NULL)
@@ -2801,20 +2810,9 @@
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    sti();
     cmd->scsi_done(cmd);
-    cli();
   }
   DRIVER_UNLOCK
-#else
-  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);
-  }
-#endif
 }
 
 /*+F*************************************************************************
@@ -2873,6 +2871,7 @@
     {
       char *buffer;
       
+      p->dev_flags[tindex] |= DEVICE_PRESENT;
       if(cmd->use_sg)
       {
         struct scatterlist *sg;
@@ -2914,23 +2913,34 @@
         p->needsdtr_copy |= (1<<tindex);
 
         if (p->flags & AHC_SEEPROM_FOUND)
+        {
           p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-        else if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_period =
-            aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
-        else if (p->features & AHC_ULTRA)
-          p->transinfo[tindex].goal_period =
-            aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
-        else
-          p->transinfo[tindex].goal_period =
-            aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
-
-        if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+          p->transinfo[tindex].goal_offset = p->transinfo[tindex].user_offset;
+        }
         else
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+        {
+          if (p->features & AHC_ULTRA2)
+          {
+            p->transinfo[tindex].goal_period =
+              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            p->transinfo[tindex].goal_period =
+              aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
+          }
+          else
+          {
+            p->transinfo[tindex].goal_period =
+              aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
+          }
+          if (p->features & AHC_ULTRA2)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+          else
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+        }
       }
       else
       {
@@ -3076,12 +3086,7 @@
       int x;
 #endif /* AIC7XXX_PROC_STATS */
 
-      sp = &p->stats[TARGET_INDEX(cmd)][cmd->lun & 0x7];
-      sp->xfers++;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if ( (sp->xfers > 16) && (aic7xxx_verbose > 0xffff) )
-        aic7xxx_verbose &= 0xffff;
-#endif
+      sp = &p->stats[TARGET_INDEX(cmd)];
 
       /*
        * For block devices, cmd->request.cmd is always == either READ or
@@ -3093,7 +3098,10 @@
            (cmd->data_cmnd[0] == WRITE_FILEMARKS) )
       {
         sp->w_total++;
-        sp->w_total512 += (actual >> 9);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if ( (sp->w_total > 16) && (aic7xxx_verbose > 0xffff) )
+          aic7xxx_verbose &= 0xffff;
+#endif
 #ifdef AIC7XXX_PROC_STATS
         ptr = sp->w_bins;
 #endif /* AIC7XXX_PROC_STATS */
@@ -3101,23 +3109,32 @@
       else
       {
         sp->r_total++;
-        sp->r_total512 += (actual >> 9);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if ( (sp->r_total > 16) && (aic7xxx_verbose > 0xffff) )
+          aic7xxx_verbose &= 0xffff;
+#endif
 #ifdef AIC7XXX_PROC_STATS
         ptr = sp->r_bins;
 #endif /* AIC7XXX_PROC_STATS */
       }
 #ifdef AIC7XXX_PROC_STATS
-      for (x = 9; x <= 17; x++)
+      x = -10;
+      while(actual)
       {
-        if (actual < (1 << x))
-        {
-          ptr[x - 9]++;
-          break;
-        }
+        actual >>= 1;
+        x++;
       }
-      if (x > 17)
+      if (x < 0)
       {
-        ptr[x - 9]++;
+        ptr[0]++;
+      }
+      else if (x > 7)
+      {
+        ptr[7]++;
+      }
+      else
+      {
+        ptr[x]++;
       }
 #endif /* AIC7XXX_PROC_STATS */
     }
@@ -3401,42 +3418,24 @@
 
     for (i = min_target; i <= max_target; i++)
     {
+      if ( i == p->scsi_id )
+      {
+        continue;
+      }
       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      if ( !(p->dev_flags[i] & DEVICE_TAGGED_SUCCESS) &&
-            (p->dev_active_cmds[i]) &&
-            (p->tagenable & (0x01 << i)) )
-      {
-        printk(INFO_LEAD "Device appears to be choking on tagged commands.\n",
-          p->host_no, channel, i, lun);
-        printk(INFO_LEAD "Will use untagged I/O instead.\n", p->host_no,
-          channel, i, lun);
-        p->dev_max_queue_depth[i] = 1;
-        p->dev_temp_queue_depth[i] = 1;
-        p->tagenable &= ~(0x01 << i);
-        p->orderedtag &= ~(0x01 << i);
-      }
       p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
       if ( tag == SCB_LIST_NULL )
       {
-        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
-        p->dev_last_reset[i] = jiffies;
+        p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR |
+                           DEVICE_RESET_DELAY;
+        p->dev_expires[i] = jiffies + (4 * HZ);
+        p->dev_timer_active |= (0x01 << i);
         p->dev_last_queue_full_count[i] = 0;
         p->dev_last_queue_full[i] = 0;
         p->dev_temp_queue_depth[i] =
           p->dev_max_queue_depth[i];
-  /*
-   * In case this isn't a full bus reset, we want to add a 4 second timer in
-   * here so that we can delay all re-sent commands for this device for the
-   * 4 seconds and then have our timer routine pick them back up.
-   */
-        if(p->dev_timer[i].expires)
-        {
-          del_timer(&p->dev_timer[i]);
-        }
-        p->dev_timer[i].expires = jiffies + (4 * HZ);
-        add_timer(&p->dev_timer[i]);
       }
       for(j=0; j<MAX_LUNS; j++)
       {
@@ -3483,11 +3482,13 @@
             "delayed_scbs queue!\n", p->host_no, channel, i, lun);
         scbq_init(&p->delayed_scbs[i]);
       }
-      if ( (p->delayed_scbs[i].head == NULL) &&
-           (p->dev_timer[i].expires) )
+      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+            time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
       {
-        del_timer(&p->dev_timer[i]);
-        p->dev_timer[i].expires = 0;
+        del_timer(&p->dev_timer);
+        p->dev_timer.expires = p->dev_expires[i];
+        add_timer(&p->dev_timer);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
       }
     }
   }
@@ -3620,7 +3621,7 @@
   if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
     printk(INFO_LEAD "Cleaning disconnected scbs "
       "list.\n", p->host_no, channel, target, lun);
-  if (p->features & AHC_PAGESCBS)
+  if (p->flags & AHC_PAGESCBS)
   {
     unsigned char next, prev, scb_index;
 
@@ -3672,7 +3673,7 @@
    * Walk the free list making sure no entries on the free list have
    * a valid SCB_TAG value or SCB_CONTROL byte.
    */
-  if (p->features & AHC_PAGESCBS)
+  if (p->flags & AHC_PAGESCBS)
   {
     unsigned char next;
 
@@ -3953,12 +3954,6 @@
    */
   aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
 
-  /*
-   * Convince Mid Level SCSI code to leave us be for a little bit...
-   */
-  p->last_reset = jiffies;
-  p->host->last_reset = (jiffies + (HZ * AIC7XXX_RESET_DELAY));
-
   if ( !(p->features & AHC_TWIN) )
   {
     restart_sequencer(p);
@@ -4000,38 +3995,18 @@
     tindex = TARGET_INDEX(scb->cmd);
     if ( !scb->tag_action && (p->tagenable & (1<<tindex)) )
     {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Reducing Queue depth for untagged command.\n",
-               p->host_no, CTL_OF_SCB(scb));
-#endif
       p->dev_temp_queue_depth[tindex] = 1;
     }
     if ( (p->dev_active_cmds[tindex] >=
           p->dev_temp_queue_depth[tindex]) ||
-         (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) )
+         (p->dev_flags[tindex] & (DEVICE_RESET_DELAY|DEVICE_WAS_BUSY)) ||
+         (p->flags & AHC_RESET_DELAY) )
     {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-      if (aic7xxx_verbose > 0xffff)
-        printk(INFO_LEAD "Moving SCB to Delayed Queue.\n",
-               p->host_no, CTL_OF_SCB(scb));
-#endif
       scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-      if ( !(p->dev_timer[tindex].expires) &&
-           !(p->dev_active_cmds[tindex]) )
-      {
-        p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ);
-        add_timer(&p->dev_timer[tindex]);
-      }
     }
     else
     {
         scb->flags &= ~SCB_WAITINGQ;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if (aic7xxx_verbose > 0xffff)
-          printk(INFO_LEAD "Sending command %d/0x%x to QINFIFO\n", p->host_no,
-                 CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-#endif
         p->dev_active_cmds[tindex]++;
         p->activescbs++;
         if ( !(scb->tag_action) )
@@ -4044,16 +4019,6 @@
   }
   if (sent)
   {
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-    if (aic7xxx_verbose > 0xffff)
-    {
-      printk(INFO_LEAD "Sending commands to QINFIFO\n", p->host_no,
-             -1, -1, -1);
-      if ( (p->isr_count < 16) && (aic7xxx_panic_on_abort) &&
-           (p->flags & AHC_PAGESCBS) )
-        aic7xxx_check_scbs(p, "While sending commands to QINFIFO");
-    }
-#endif
     if (p->features & AHC_QUEUE_REGS)
       aic_outb(p, p->qinfifonext, HNSCB_QOFF);
     else
@@ -4154,17 +4119,21 @@
 #else
   spin_lock_irqsave(&io_request_lock, cpu_flags);
 #endif
+  p->dev_timer_active &= ~(0x01 << MAX_TARGETS);
+  if ( (p->dev_timer_active & (0x01 << p->scsi_id)) &&
+       time_after_eq(jiffies, p->dev_expires[p->scsi_id]) )
+  {
+    p->flags &= ~AHC_RESET_DELAY;
+    p->dev_timer_active &= ~(0x01 << p->scsi_id);
+  }
   for(i=0; i<MAX_TARGETS; i++)
   {
-    if ( (p->dev_timer[i].expires) && 
-          (p->dev_timer[i].expires <= jiffies) )
+    if ( (i != p->scsi_id) &&
+         (p->dev_timer_active & (0x01 << i)) &&
+         time_after_eq(jiffies, p->dev_expires[i]) )
     {
-      p->dev_timer[i].expires = 0;
-      if ( (p->dev_timer[i].prev != NULL) ||
-           (p->dev_timer[i].next != NULL) )
-      {
-        del_timer(&p->dev_timer[i]);
-      }
+      p->dev_timer_active &= ~(0x01 << i);
+      p->dev_flags[i] &= ~(DEVICE_RESET_DELAY|DEVICE_WAS_BUSY);
       p->dev_temp_queue_depth[i] =  p->dev_max_queue_depth[i];
       j = 0;
       while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) &&
@@ -4184,7 +4153,27 @@
          */
       }
     }
+    else if ( p->dev_timer_active & (0x01 << i) )
+    {
+      if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
+      {
+        if ( time_after_eq(p->dev_timer.expires, p->dev_expires[i]) )
+        {
+          p->dev_timer.expires = p->dev_expires[i];
+        }
+      }
+      else
+      {
+        p->dev_timer.expires = p->dev_expires[i];
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+      }
+    }
+  }
+  if ( p->dev_timer_active & (0x01 << MAX_TARGETS) )
+  {
+    add_timer(&p->dev_timer);
   }
+
   aic7xxx_run_waiting_queues(p);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)   
   DRIVER_UNLOCK
@@ -4459,8 +4448,7 @@
              (scb->tag_action) &&
             !(scb->flags & SCB_MSGOUT_BITS) )
         {
-          if ((scb->tag_action == MSG_ORDERED_Q_TAG) &&
-              (p->dev_flags[tindex] & DEVICE_TAGGED_SUCCESS))
+          if (scb->tag_action == MSG_ORDERED_Q_TAG)
           {
             /*
              * OK...the device seems able to accept tagged commands, but
@@ -4481,8 +4469,7 @@
             aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
             aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
           }
-          else if ( (scb->tag_action == MSG_SIMPLE_Q_TAG) &&
-                   !(p->dev_flags[tindex] & DEVICE_TAGGED_SUCCESS) )
+          else if (scb->tag_action == MSG_SIMPLE_Q_TAG)
           {
             unsigned char i, reset = 0;
             struct aic7xxx_scb *scbp;
@@ -4897,17 +4884,29 @@
               p->activescbs--;
               scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
                   
-              if (p->dev_timer[tindex].expires == 0) 
+              if ( !(p->dev_timer_active & (0x01 << tindex)) ) 
               {
+                p->dev_timer_active |= (0x01 << tindex);
                 if ( p->dev_active_cmds[tindex] )
                 {
-                  p->dev_timer[tindex].expires = jiffies + (HZ * 2);
-                  add_timer(&p->dev_timer[tindex]);
+                  p->dev_expires[tindex] = jiffies + HZ;
                 }
                 else
                 {
-                  p->dev_timer[tindex].expires = jiffies + (HZ / 2);
-                  add_timer(&p->dev_timer[tindex]);
+                  p->dev_expires[tindex] = jiffies + (HZ / 10);
+                }
+                if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) )
+                {
+                  p->dev_timer.expires = p->dev_expires[tindex];
+                  p->dev_timer_active |= (0x01 << MAX_TARGETS);
+                  add_timer(&p->dev_timer);
+                }
+                else if ( time_after_eq(p->dev_timer.expires,
+                                        p->dev_expires[tindex]) )
+                {
+                  del_timer(&p->dev_timer);
+                  p->dev_timer.expires = p->dev_expires[tindex];
+                  add_timer(&p->dev_timer);
                 }
               }
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
@@ -4949,6 +4948,10 @@
                   p->dev_last_queue_full[tindex] = 0;
                   p->dev_last_queue_full_count[tindex] = 0;
                 }
+                else
+                {
+                  p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+                }
               }
               break;
             }
@@ -5267,50 +5270,61 @@
         {
           maxsync = AHC_SYNCRATE_FAST;
         }
-  
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-        if (aic7xxx_verbose > 0xffff)
-        {
-          printk(INFO_LEAD "Finished receipt of SDTR, parsing %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
-          printk(INFO_LEAD "After find_syncrate() %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-          aic7xxx_validate_offset(p, syncrate, &offset,
-                                  target_scsirate & WIDEXFER);
-          printk(INFO_LEAD "After validate_offset() %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          printk(INFO_LEAD "Final values of Period/Offset as set: %d/%d\n",
-                 p->host_no, CTL_OF_SCB(scb), period, offset);
-        }
-        else
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
-          aic7xxx_validate_offset(p, syncrate, &offset,
-                                  target_scsirate & WIDEXFER);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+          {
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_offset =
+              p->transinfo[tindex].user_offset;
+            p->needsdtr_copy |= target_mask;
+          }
+          if ( !p->transinfo[tindex].goal_offset )
+            period = 255;
+          if ( p->transinfo[tindex].goal_period > period )
+            period = p->transinfo[tindex].goal_period;
         }
-#else
+  
         syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
         aic7xxx_validate_offset(p, syncrate, &offset,
                                 target_scsirate & WIDEXFER);
         aic7xxx_set_syncrate(p, syncrate, target, channel, period,
                              offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-#endif
 
-        if (offset == 0)
+        /*
+         * Did we drop to async?  If so, are we sending a reply?  If we are,
+         * then we have to make sure that the reply value reflects the proper
+         * settings so we need to set the goal values according to what
+         * we need to send.
+         */
+        if ( (offset == 0) || (offset != saved_offset) ||
+             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
         {
-          /*
-           * Uhh ohh, things fell through to async....update the goal
-           * items and the needsdtr_copy to reflect this...
-           */
           aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                 offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-          p->needsdtr_copy &= ~target_mask;
+                               offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          if ( offset == 0 )
+          {
+            p->needsdtr_copy &= ~target_mask;
+          }
         }
+        
         /*
          * Did we start this, if not, or if we went to low and had to
          * go async, then send an SDTR back to the target
@@ -5325,32 +5339,6 @@
         }
         else
         {
-          /*
-           * Send a reply SDTR back.  Even if we sent the first one, it
-           * is valid to send another one out immediately to re-negotiate
-           * things, and a few devices don't like getting rejects after
-           * we already sent them one SDTR.  Just send an SDTR for async
-           * this time if need be (or for the correct params if we didn't
-           * start all of this).  If this is a Reject Reply type message,
-           * then we've put the async settings into the goal area for
-           * future reference (when we get the AWAITING_MSG interrupt).
-           * If this is a case where we are responding to the target's
-           * initiated SDTR, then leave our own goal and user values in
-           * place (unless the device hasn't been scanned yet, in which
-           * case, put the user values into the goal values so we don't
-           * send out an Async message).
-           */
-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
-          {
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
-            p->needwdtr_copy |= target_mask;
-            p->needsdtr_copy |= target_mask;
-          }
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
@@ -5419,12 +5407,12 @@
              * it contacted us first, mark it as such and copy the user stuff
              * over to the goal stuff.
              */
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
             p->transinfo[tindex].goal_period =
               p->transinfo[tindex].user_period;
             p->transinfo[tindex].goal_offset =
               p->transinfo[tindex].user_offset;
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
             p->needwdtr_copy |= target_mask;
             p->needsdtr_copy |= target_mask;
           }
@@ -5444,6 +5432,8 @@
             {
               p->needwdtr_copy &= ~target_mask;
               bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic7xxx_set_width(p, target, channel, lun, bus_width,
+                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
               break;
             }
           }
@@ -5820,23 +5810,19 @@
        * Put this SCB back on the free list.
        */
       aic7xxx_add_curscb_to_free_list(p);
-      /*
-       * XXX - If we queued an abort tag, go clean up the disconnected list.
-       * We know that this particular SCB had to be the queued abort since
-       * the disconnected SCB would have gotten a reconnect instead.
-       * However, if this is an abort command, then DID_TIMEOUT isn't
-       * appropriate, neither is returning the command for that matter.
-       * What we need to do then is to let the command timeout again so
-       * we get a reset since this abort just failed.
-       */
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
       if (aic7xxx_verbose > 0xffff)
         printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
 #endif
-      if (p->flags & SCB_QUEUED_ABORT)
+      if (scb->flags & SCB_QUEUED_ABORT)
       {
+        /*
+         * We know that this particular SCB had to be the queued abort since
+         * the disconnected SCB would have gotten a reconnect instead.
+         * What we need to do then is to let the command timeout again so
+         * we get a reset since this abort just failed.
+         */
         cmd->result = 0;
-        scb->flags &= ~SCB_QUEUED_ABORT;
         scb = NULL;
       }
     }
@@ -6253,12 +6239,6 @@
             aic7xxx_calculate_residual(p, scb);
           }
           cmd->result |= (aic7xxx_error(cmd) << 16);
-          if (scb->tag_action)
-            p->dev_flags[TARGET_INDEX(cmd)] |= 
-               DEVICE_TAGGED_SUCCESS | DEVICE_SUCCESS | DEVICE_PRESENT;
-          else
-            p->dev_flags[TARGET_INDEX(cmd)] |= 
-               DEVICE_SUCCESS | DEVICE_PRESENT;
           aic7xxx_done(p, scb);
           break;
       }      
@@ -6384,7 +6364,7 @@
  *   Determines the queue depth for a given device.  There are two ways
  *   a queue depth can be obtained for a tagged queueing device.  One
  *   way is the default queue depth which is determined by whether
- *   AIC7XXX_CMDS_PER_LUN is defined.  If it is defined, then it is used
+ *   AIC7XXX_CMDS_PER_DEVICE is defined.  If it is defined, then it is used
  *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
  *   default queue depth (dependent on the number of hardware SCBs).
  *   The other way we determine queue depth is through the use of the
@@ -6404,7 +6384,6 @@
   target_mask = (1 << tindex);
 
   device->queue_depth = default_depth;
-  p->dev_mid_level_queue_depth[tindex] = 3;
   p->dev_temp_queue_depth[tindex] = 1;
   p->dev_max_queue_depth[tindex] = 1;
   p->tagenable &= ~target_mask;
@@ -6413,11 +6392,7 @@
   {
     int tag_enabled = TRUE;
 
-#ifdef AIC7XXX_CMDS_PER_LUN
-    default_depth = AIC7XXX_CMDS_PER_LUN;
-#else
-    default_depth = 8;  /* Not many SCBs to work with. */
-#endif
+    default_depth = AIC7XXX_CMDS_PER_DEVICE;
  
     if (!(p->discenable & target_mask))
     {
@@ -6469,7 +6444,6 @@
         }
         p->dev_max_queue_depth[tindex] = device->queue_depth;
         p->dev_temp_queue_depth[tindex] = device->queue_depth;
-        p->dev_mid_level_queue_depth[tindex] = device->queue_depth;
         p->tagenable |= target_mask;
         p->orderedtag |= target_mask;
         device->tagged_queue = 1;
@@ -6980,7 +6954,7 @@
   }
   printk("\n");
 #endif
-  if (checksum != scarray[len - 1])
+  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
   {
     return (0);
   }
@@ -7464,7 +7438,6 @@
   }
 
   p->host = host;
-  p->last_reset = 0;
   p->host_no = host->host_no;
   host->unique_id = p->instance;
   p->isr_count = 0;
@@ -7473,6 +7446,10 @@
   p->completeq.tail = NULL;
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
+  init_timer(&p->dev_timer);
+  p->dev_timer.data = (unsigned long)p;
+  p->dev_timer.function = (void *)aic7xxx_timer;
+  p->dev_timer_active = 0;
 
   for (i = 0; i < NUMBER(p->untagged_scbs); i++)
   {
@@ -7491,17 +7468,12 @@
     p->dev_commands_sent[i] = 0;
     p->dev_flags[i] = 0;
     p->dev_active_cmds[i] = 0;
-    p->dev_last_reset[i] = 0;
     p->dev_last_queue_full[i] = 0;
     p->dev_last_queue_full_count[i] = 0;
     p->dev_max_queue_depth[i] = 1;
     p->dev_temp_queue_depth[i] = 1;
-    p->dev_mid_level_queue_depth[i] = 3;
+    p->dev_expires[i] = 0;
     scbq_init(&p->delayed_scbs[i]);
-    init_timer(&p->dev_timer[i]);
-    p->dev_timer[i].expires = 0;
-    p->dev_timer[i].data = (unsigned long)p;
-    p->dev_timer[i].function = (void *)aic7xxx_timer;
   }
 
   printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
@@ -7551,10 +7523,9 @@
   }
   aic_outb(p, 0, SEQ_FLAGS);
 
-  /*
-   * Detect SCB parameters and initialize the SCB array.
-   */
   detect_maxscb(p);
+
+
   printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
   if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
@@ -7673,7 +7644,7 @@
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-    aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+    aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
          ENSTIMER | ACTNEGEN, SXFRCTL1);
     aic_outb(p, 0, SIMODE0);
     aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -7690,7 +7661,7 @@
     aic_outb(p, p->scsi_id, SCSIID);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
-  aic_outb(p, (scsi_conf & ENSPCHK) | term | 
+  aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
        ENSTIMER | ACTNEGEN, SXFRCTL1);
   aic_outb(p, 0, SIMODE0);
   aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
@@ -7865,6 +7836,11 @@
    */
   aic7xxx_loadseq(p);
 
+  /*
+   * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+   */
+  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
   if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
   {
     aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
@@ -8151,6 +8127,8 @@
         p->flags |= AHC_TERM_ENB_A;
       if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) )
         p->flags |= AHC_TERM_ENB_B;
+      aic_outb(p, 0, DISC_DSB);
+      aic_outb(p, 0, DISC_DSB + 1);
       break;
 
     case (AHC_AIC7770|AHC_VL):
@@ -8169,6 +8147,21 @@
           have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
                                       scarray, p->sc_size, C46);
       }
+      if (!have_seeprom)
+      {
+        p->sc_size = 128;
+        have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                    scarray, p->sc_size, p->sc_type);
+        if (!have_seeprom)
+        {
+          if(p->sc_type == C46)
+            have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C56_66);
+          else
+            have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C46);
+        }
+      }
       break;
   }
 
@@ -8194,13 +8187,16 @@
     {
       printk("aic7xxx: Using leftover BIOS values.\n");
     }
-    if ( *sxfrctl1 & STPWEN )
+    if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
     {
       p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
       sc->adapter_control &= ~CFAUTOTERM;
       sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
     }
-    p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
+    if (aic7xxx_extended)
+      p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+    else
+      p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
   }
   else
   {
@@ -8288,7 +8284,7 @@
     mask = (0x01 << i);
     if (!have_seeprom)
     {
-      if(aic_inb(p, SCSISEQ) != 0)
+      if (aic_inb(p, SCSISEQ) != 0)
       {
         /*
          * OK...the BIOS set things up and left behind the settings we need.
@@ -8348,19 +8344,30 @@
     }
     if (p->flags & AHC_NEWEEPROM_FMT)
     {
-      if (sc->device_flags[i] & CFSYNCHISULTRA)
-      {
-        p->ultraenb |= mask;
-      }
-      else if (sc->device_flags[i] & CFNEWULTRAFORMAT)
+      if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+          !(p->features & AHC_ULTRA2) )
       {
-        if ( (sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03 )
+        /*
+         * I know of two different Ultra BIOSes that do this differently.
+         * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+         * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+         * while on the IBM Netfinity 5000 they want the same thing
+         * to be something else, while flags[i] & CFXFER == 0x03 and
+         * SYNCISULTRA false should be 40MByte/s.  So, we set both to
+         * 40MByte/s and the lower speeds be damned.  People will have
+         * to select around the conversely mapped lower speeds in order
+         * to select lower speeds on these boards.
+         */
+        if ((sc->device_flags[i] & (CFXFER)) == 0x03)
         {
           sc->device_flags[i] &= ~CFXFER;
           sc->device_flags[i] |= CFSYNCHISULTRA;
-          p->ultraenb |= mask;
         }
       }
+      if (sc->device_flags[i] & CFSYNCHISULTRA)
+      {
+        p->ultraenb |= mask;
+      }
     }
     else if (sc->adapter_control & CFULTRAEN)
     {
@@ -8635,12 +8642,6 @@
         current_p = current_p->next;
       current_p->next = temp_p;
     }
-    if (aic7xxx_extended)
-    {
-      temp_p->flags |= AHC_EXTEND_TRANS_A;
-      if (temp_p->flags & AHC_MULTI_CHANNEL)
-        temp_p->flags |= AHC_EXTEND_TRANS_B;
-    }
 
     switch (type)
     {
@@ -8797,6 +8798,14 @@
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
        AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
@@ -8839,6 +8848,18 @@
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
        AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
        AHC_AIC7895_FE,                                      19,
@@ -8847,25 +8868,70 @@
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      20,
        32, C46 },
-      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      20,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7890_FE,                                      21,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      22,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      22,
+       AHC_AIC7896_FE,                                      23,
        32, C56_66 },
       {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
-       AHC_AIC7896_FE,                                      23,
+       AHC_AIC7896_FE,                                      24,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      25,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                      26,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7899_FE,                                      28,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7899_FE,                                      28,
        32, C56_66 },
     };
 
     unsigned short command;
     unsigned int  devconfig, i, oldverbose;
-#ifdef MMAPIO
-    unsigned long page_offset, base;
-#endif
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
     struct pci_dev *pdev = NULL;
 #else
@@ -9016,21 +9082,68 @@
           temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
           temp_p->unpause = INTEN;
           temp_p->pause = temp_p->unpause | PAUSE;
+          if ( ((temp_p->base == 0) &&
+                (temp_p->mbase == 0)) ||
+               (temp_p->irq == 0) )
+          {
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
+            printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+            kfree(temp_p);
+            temp_p = NULL;
+            continue;
+          }
 
 #ifdef MMAPIO
-          base = temp_p->mbase & PAGE_MASK;
-          page_offset = temp_p->mbase - base;
+          {
+            unsigned long page_offset, base;
+
+            base = temp_p->mbase & PAGE_MASK;
+            page_offset = temp_p->mbase - base;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-          temp_p->maddr = ioremap_nocache(base, page_offset + 256);
+            temp_p->maddr = ioremap_nocache(base, page_offset + 256);
 #else
-          temp_p->maddr = vremap(base, page_offset + 256);
+            temp_p->maddr = vremap(base, page_offset + 256);
 #endif
-          if(temp_p->maddr)
-          {
-            temp_p->maddr += page_offset;
+            if(temp_p->maddr)
+            {
+              temp_p->maddr += page_offset;
+              /*
+               * We need to check the I/O with the MMAPed address.  Some machines
+               * simply fail to work with MMAPed I/O and certain controllers.
+               */
+              if(aic_inb(temp_p, HCNTRL) == 0xff)
+              {
+                /*
+                 * OK.....we failed our test....go back to programmed I/O
+                 */
+                printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d\n", 
+                  board_names[aic_pdevs[i].board_name_index],
+                  PCI_SLOT(temp_p->pci_device_fn),
+                  PCI_FUNC(temp_p->pci_device_fn));
+                printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
+                                 "Programmed I/O.\n");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+                iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+#else
+                vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
+#endif
+                temp_p->maddr = 0;
+              }
+            }
           }
 #endif
 
+          /*
+           * We HAVE to make sure the first pause_sequencer() and all other
+           * subsequent I/O that isn't PCI config space I/O takes place
+           * after the MMAPed I/O region is configured and tested.  The
+           * problem is the PowerPC architecture that doesn't support
+           * programmed I/O at all, so we have to have the MMAP I/O set up
+           * for this pause to even work on those machines.
+           */
           pause_sequencer(temp_p);
 
           /*
@@ -9065,44 +9178,36 @@
           }
 
           /*
-           * Doing a switch based upon i is really gross, but since Justin
-           * changed around the chip ID stuff, we can't use that any more.
-           * Since we don't scan the devices the same way as FreeBSD, we end
-           * up doing this gross hack in order to avoid totally splitting
-           * away from Justin's init code in ahc_pci.c
+           * We need to set the CHNL? assignments before loading the SEEPROM
+           * The 3940 and 3985 cards (original stuff, not any of the later
+           * stuff) are 7870 and 7880 class chips.  The Ultra2 stuff falls
+           * under 7896 and 7897.  The 7895 is in a class by itself :)
            */
-          switch (i)
+          switch (temp_p->chip & AHC_CHIPID_MASK)
           {
-            case 7:   /* 3940 */
-            case 12:  /* 3940-Ultra */
-              switch(PCI_SLOT(temp_p->pci_device_fn))
+            case AHC_AIC7870: /* 3840 / 3985 */
+            case AHC_AIC7880: /* 3840 UW / 3985 UW */
+              if(temp_p->flags & AHC_MULTI_CHANNEL)
               {
-                case 5:
-                  temp_p->flags |= AHC_CHNLB;
-                  break;
-                default:
-                  break;
-              }
-              break;
-
-            case 8:   /* 3985 */
-            case 13:  /* 3985-Ultra */
-              switch(PCI_SLOT(temp_p->pci_device_fn))
-              {
-                case 8:
-                  temp_p->flags |= AHC_CHNLB;
-                  break;
-                case 12:
-                  temp_p->flags |= AHC_CHNLC;
-                  break;
-                default:
-                  break;
+                switch(PCI_SLOT(temp_p->pci_device_fn))
+                {
+                  case 5:
+                    temp_p->flags |= AHC_CHNLB;
+                    break;
+                  case 8:
+                    temp_p->flags |= AHC_CHNLB;
+                    break;
+                  case 12:
+                    temp_p->flags |= AHC_CHNLC;
+                    break;
+                  default:
+                    break;
+                }
               }
               break;
 
-            case 15:
-            case 18:
-            case 19:
+            case AHC_AIC7895: /* 7895 */
+            case AHC_AIC7896: /* 7896/7 */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               if (PCI_FUNC(temp_p->pdev->devfn) != 0)
               {
@@ -9178,16 +9283,6 @@
               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                 CACHETHEN | MPARCKEN | USCBSIZE32 |
                                 CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
-              /* FALLTHROUGH */
-            default:
-              /*
-               * We attempt to read a SEEPROM on *everything*.  If we fail,
-               * then we fail, but this covers things like 2910c cards that
-               * now have SEEPROMs with their 7856 chipset that we would
-               * otherwise ignore.  They still don't have a BIOS, but they
-               * have a SEEPROM that the SCSISelect utility on the Adaptec
-               * diskettes can configure.
-               */
               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
               break;
             case AHC_AIC7850:
@@ -9199,14 +9294,13 @@
               aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
                                 CACHETHEN | MPARCKEN) & ~DPARCKEN,
                        DSCOMMAND0);
+              /* FALLTHROUGH */
+            default:
               aic7xxx_load_seeprom(temp_p, &sxfrctl1);
               break;
             case AHC_AIC7880:
               /*
-               * Only set the DSCOMMAND0 register if this is a Rev B.
-               * chipset.  For those, we also enable Ultra mode by
-               * force due to brain-damage on the part of some BIOSes
-               * We overload the devconfig variable here since we can.
+               * Check the rev of the chipset before we change DSCOMMAND0
                */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
               pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
@@ -9270,13 +9364,10 @@
           }
 
           /*
-           * We do another switch based on i so that we can exclude all
-           * 3895 devices from the next option since the 3895 cards use
-           * shared external SCB RAM while all other cards have dedicated
-           * external SCB RAM per channel.  Also exclude the 7850 and
-           * 7860 based stuff since they can have garbage in the bit
-           * that indicates external RAM and get some of this stuff
-           * wrong as a result.
+           * We only support external SCB RAM on the 7895/6/7 chipsets.
+           * We could support it on the 7890/1 easy enough, but I don't
+           * know of any 7890/1 based cards that have it.  I do know
+           * of 7895/6/7 cards that have it and they work properly.
            */
           switch(temp_p->chip & AHC_CHIPID_MASK)
           {
@@ -9340,9 +9431,6 @@
             aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
           }
 
-          if (aic7xxx_extended)
-            temp_p->flags |= AHC_EXTEND_TRANS_A;
-
           if ( list_p == NULL )
           {
             list_p = current_p = temp_p;
@@ -10109,8 +10197,6 @@
                 "message buffer\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
-                ~DEVICE_SUCCESS;
         p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
                 BUS_DEVICE_RESET_PENDING;
         /* Send the abort message to the active SCB. */
@@ -10131,8 +10217,6 @@
                 "in use\n", p->host_no, CTL_OF_SCB(scb));
         scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
         aic7xxx_error(scb->cmd) = DID_RESET;
-        p->dev_flags[TARGET_INDEX(scb->cmd)] &= 
-                ~DEVICE_SUCCESS;
         p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
                 BUS_DEVICE_RESET_PENDING;
         return(SCSI_RESET_ERROR);
@@ -10160,7 +10244,6 @@
          */
     scb->hscb->control |= MK_MESSAGE;
     scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-    p->dev_flags[TARGET_INDEX(scb->cmd)] &= ~DEVICE_SUCCESS;
     p->dev_flags[TARGET_INDEX(scb->cmd)] |= 
         BUS_DEVICE_RESET_PENDING;
     if (hscb_index != SCB_LIST_NULL)
@@ -10240,7 +10323,7 @@
     {
       mask = (0x01 << i);
       printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
-             " q_depth=%d:%d:%d\n",
+             " q_depth=%d:%d\n",
         p->host_no, 0, i, 0, p->dev_flags[i],
         (p->wdtr_pending & mask) ? 'Y' : 'N',
         (p->needwdtr & mask) ? 'Y' : 'N',
@@ -10249,7 +10332,7 @@
         (p->needsdtr & mask) ? 'Y' : 'N',
         (p->needsdtr_copy & mask) ? 'Y' : 'N',
         p->dev_active_cmds[i],
-        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+        p->dev_max_queue_depth[i] );
       printk(INFO_LEAD "targ_scsirate=0x%x", p->host_no, 0, i, 0,
              aic_inb(p, TARG_SCSIRATE + i));
       if (p->features & AHC_ULTRA2)
@@ -10890,7 +10973,7 @@
   {
     action = HOST_RESET;
   }
-  if ( ((jiffies - p->dev_last_reset[tindex]) < (HZ * 3)) &&
+  if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
        !(action & (HOST_RESET | BUS_RESET)))
   {
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
@@ -10902,23 +10985,14 @@
     }
     action = BUS_RESET;
   }
-  if ( ((jiffies - p->last_reset) < (HZ * 3)) &&
-        (action & (HOST_RESET | BUS_RESET)) )
+  if ( (p->flags & AHC_RESET_DELAY) &&
+       (action & (HOST_RESET | BUS_RESET)) )
   {
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
       printk(INFO_LEAD "Reset called too soon after "
         "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
     action = RESET_DELAY;
   }
-  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & AHC_IN_RESET)
-        && ((jiffies - p->reset_start) > (2 * HZ * 3)) )
-  {
-    printk(KERN_ERR "(scsi%d:%d:%d:%d) Yikes!!  Card must have left to go "
-        "back to Adaptec!!\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, FALSE);
-    DRIVER_UNLOCK
-    return(SCSI_RESET_SNOOZE);
-  }
 /*
  *  By this point, we want to already know what we are going to do and
  *  only have the following code implement our course of action.
@@ -10950,15 +11024,23 @@
     case BUS_RESET:
     case HOST_RESET:
     default:
-      p->reset_start = jiffies;
-      p->flags |= AHC_IN_RESET;
+      p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
+      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+      p->dev_timer_active |= (0x01 << p->scsi_id);
+      if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
+            time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
+      {
+        del_timer(&p->dev_timer);
+        p->dev_timer.expires = p->dev_expires[p->scsi_id];
+        add_timer(&p->dev_timer);
+        p->dev_timer_active |= (0x01 << MAX_TARGETS);
+      }
       aic7xxx_reset_channel(p, cmd->channel, TRUE);
       if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
       {
         aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
         restart_sequencer(p);
       }
-      p->last_reset = jiffies;
       if (action != HOST_RESET)
         result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
       else
@@ -10973,9 +11055,27 @@
         p->msg_len = 0;
       }
       aic7xxx_run_done_queue(p, TRUE);
+      /*
+       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
+       * in need of being re-started, so send it on through to aic7xxx_queue
+       * and let it set until the delay is over.  This keeps it from dying
+       * entirely and avoids getting a bogus dead command back through the
+       * mid-level code due to too many retries.
+       */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+      if ( flags & SCSI_RESET_SYNCHRONOUS )
+      {
+        cmd->result = DID_BUS_BUSY << 16;
+        cmd->done(cmd);
+      }
+#endif
       p->flags &= ~AHC_IN_RESET;
-      /*  We can't rely on run_waiting_queues to unpause the sequencer for
-       *  PCI based controllers since we use AAP */
+      /*
+       * We can't rely on run_waiting_queues to unpause the sequencer for
+       * PCI based controllers since we use AAP.  NOTE: this also sets
+       * the timer for the one command we might have queued in the case
+       * of a synch reset.
+       */
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
@@ -10994,16 +11094,21 @@
 int
 aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
 {
-  int heads, sectors, cylinders;
+  int heads, sectors, cylinders, ret;
   struct aic7xxx_host *p;
+  struct buffer_head *bh;
 
   p = (struct aic7xxx_host *) disk->device->host->hostdata;
+  bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
 
-  /*
-   * XXX - if I could portably find the card's configuration
-   *       information, then this could be autodetected instead
-   *       of left to a boot-time switch.
-   */
+  if ( bh )
+  {
+    ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+    brelse(bh);
+    if ( ret != -1 )
+      return(ret);
+  }
+  
   heads = 64;
   sectors = 32;
   cylinders = disk->capacity / (heads * sectors);

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