]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.33pre3 2.0.33pre3
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:37 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:37 +0000 (15:11 -0500)
17 files changed:
Documentation/Configure.help
drivers/scsi/aic7xxx.c
drivers/scsi/aic7xxx.h
drivers/scsi/aic7xxx/aic7xxx.seq
drivers/scsi/aic7xxx_reg.h
drivers/scsi/aic7xxx_seq.h
fs/buffer.c
fs/exec.c
include/asm-i386/locks.h
kernel/exit.c
kernel/fork.c
mm/filemap.c
mm/page_alloc.c
mm/vmalloc.c
mm/vmscan.c
net/ipv4/ip_forward.c
net/netsyms.c

index 22b86689b3b47f372800901130be661948dbaf1f..4f7cb5645f8d3ccb7e8b99572766e4e9f495d624 100644 (file)
@@ -1401,15 +1401,77 @@ CONFIG_SCSI_AHA1740
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-Adaptec AHA274X/284X/294X support
+Adaptec AIC7xxx chipset SCSI controller support
 CONFIG_SCSI_AIC7XXX
-  Information about this SCSI host adapter is contained in
-  drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
-  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it
-  doesn't work out of the box, you may have to change some settings in
-  drivers/scsi/aic7xxx.h.  If you want to compile this as a module ( =
-  code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt.
+  This is support for the various aic7xxx based Adaptec SCSI controllers.
+  These include the 274x EISA cards, 284x VLB cards, 294x PCI cards,
+  394x PCI cards, 3985 PCI card, and several versions of the Adaptec
+  built-in SCSI controllers on various PC motherboards.  Information on
+  the configuration options for this controller can be found by checking
+  the help file for each of the available configuration options.
+
+Enable tagged command queueing
+CONFIG_AIC7XXX_TAGGED_QUEUEING
+  Tagged command queueing is used to allow acceptable devices to have more
+  than one SCSI command active on the SCSI bus at the same time.  Regardless
+  of this option setting, only devices that report they are capable of
+  tagged queueing will use this support.  This option is highly recommended
+  if you use any SCSI hard drives on your aic7xxx SCSI controller for
+  performance reasons.  Default: Y
+
+Override driver defaults for commands per LUN
+CONFIG_OVERRIDE_CMDS
+  Use this option to allow you to override the default maximum number of
+  commands that a single device on the aic7xxx controller is allowed to have
+  active at one time.  This option only effects tagged queueing capable
+  devices.  The driver uses a "failsafe" value of 8 by default.  This is
+  much lower than many devices can handle, but left in place for safety sake.
+  Default: N
+
+Maximum number of commands per LUN
+CONFIG_AIC7XXX_CMDS_PER_LUN
+  Specify the maximum number of commands per lun you would like to allocate
+  per device.  Reasonable figures are in the range of 14 to 32 commands per
+  device, but depending on hardware could be increased or decreased from
+  that figure.  If the number is too high for any particular device, the
+  driver will automatically compensate usually after only 10 minutes of
+  uptime and will issue a message to alert you to the fact that the number
+  of commands for that device has been reduced.  It will not hinder
+  performance if a portion of your devices eventually have their commands
+  per lun reduced, but is a waste of memory if all of your devices end
+  up reducing this number down to a more reasonable figure.  Default: 24
+
+Enable SCB paging
+CONFIG_AIC7XXX_PAGE_ENABLE
+  This option allows the driver to issue more commands to the controller
+  than it has physical space to store.  Since some aic7xxx chipsets can only
+  store 3 commands, and the majority can only store 16, not enabling this
+  capability can effectively negate any performance increase you might get
+  from enabling Tagged Queueing.  Default: Y
+
+Collect statistics to report in /proc
+CONFIG_AIC7XXX_PROC_STATS
+  This option tells the driver to keep track of how many commands have been
+  sent to each particular device and report that information to the user
+  via the /proc/scsi/aic7xxx/x file, where x is the number of the aic7xxx
+  controller you want the information on.  This adds a small amount of
+  overhead to each and every SCSI command the aic7xxx driver handles, so if
+  you aren't really interested in this information, it is best to leave it
+  disabled.  Default: N
+
+Delay in seconds after SCSI bus reset
+CONFIG_AIC7XXX_RESET_DELAY
+  This sets how long the driver will wait after resetting the SCSI bus before
+  attempting to communicate with the devices on the SCSI bus again.  This
+  delay will be used during the reset phase at bootup time as well as after
+  any reset that might occur during normal operation.  Reasonable numbers
+  range anywhere from 5 to 15 seconds depending on your devices.  DAT tape
+  drives are notorious for needing more time after a bus reset to be
+  ready for the next command, but most hard drives and CD-ROM devices are
+  ready in only a few seconds.  This option has a maximum upper limit of
+  20 seconds to avoid bad interactions between the aic7xxx driver and the
+  rest of the linux kernel.  The default value is a "failsafe" value that
+  should work with just about any device.  Default: 15
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
index 03e10522bccea93b2225f0fe6d11aeef76d4875a..6d4b5584da910cf61d5556b8a933ffbd366fbfcd 100644 (file)
@@ -139,7 +139,7 @@ struct proc_dir_entry proc_scsi_aic7xxx = {
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "$Revision: 4.1 $"
+#define AIC7XXX_C_VERSION  "$Revision: 4.1.1 $"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -681,7 +681,7 @@ struct hw_scatterlist {
 /*
  * Maximum number of SG segments these cards can support.
  */
-#define        AIC7XXX_MAX_SG 27
+#define        AIC7XXX_MAX_SG 122
 
 /*
  * The maximum number of SCBs we could have for ANY type
@@ -737,7 +737,9 @@ typedef enum {
        SCB_MSGOUT_SDTR         = 0x0400,
        SCB_MSGOUT_WDTR         = 0x0800,
        SCB_ABORT               = 0x1000,
-       SCB_QUEUED_ABORT        = 0x2000
+       SCB_QUEUED_ABORT        = 0x2000,
+       SCB_RESET               = 0x4000,
+       SCB_WAS_BUSY            = 0x8000
 } scb_flag_type;
 
 struct aic7xxx_scb {
@@ -810,10 +812,14 @@ struct aic7xxx_host {
 #define USE_DEFAULTS            0x0080
 #define BIOS_ENABLED            0x0100
 #define IN_ISR                  0x0200
-#define IN_TIMEOUT              0x0400
+#define ABORT_PENDING           0x0400
 #define SHARED_SCBDATA          0x0800
 #define HAVE_SEEPROM            0x1000
+#define RESET_PENDING           0x2000
+#define IN_ABORT               0x4000
   unsigned int             flags;
+  unsigned long                   last_reset;
+  unsigned long                   reset_start;
   unsigned int             isr_count;        /* Interrupt count */
   unsigned short           needsdtr_copy;    /* default config */
   unsigned short           needsdtr;
@@ -846,12 +852,19 @@ struct aic7xxx_host {
     Scsi_Cmnd *tail;
   } completeq;
   struct aic7xxx_device_status {
+    unsigned char active_cmds;
+    unsigned char max_queue_depth;
+    unsigned char temp_queue_depth;
+    unsigned char last_queue_full;
+    unsigned char last_queue_full_count;
+    struct timer_list timer;
     long last_reset;
 #define  DEVICE_SUCCESS                 0x01
 #define  BUS_DEVICE_RESET_PENDING       0x02
+#define  DEVICE_TIMEOUT                 0x04
     int  flags;
     int  commands_sent;
-    int  active_cmds;
+    scb_queue_type delayed_scbs;
   } device_status[16];
 #ifdef AIC7XXX_PROC_STATS
   /*
@@ -939,14 +952,50 @@ debug_scb(struct aic7xxx_scb *scb)
 #  define debug_scb(x)
 #endif AIC7XXX_DEBUG
 
-#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                        (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
+                        (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
                         ((scb->hscb)->target_channel_lun & 0x07)
 
-#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf),  \
-                       (((scb->hscb)->target_channel_lun >> 3) & 0x01)
+#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01),  \
+                        ((cmd->target) & 0x0f), \
+                        ((cmd->lun) & 0x07)
+
+static inline int
+CHAN_TO_INT(char chan)
+{
+  switch(chan)
+  {
+    case ALL_CHANNELS:
+       return(-1);
+    case 'B':
+    case 'b':
+        return(1);
+    case 'A':
+    case 'a':
+        return(0);
+    default:
+        printk(KERN_WARNING "aic7xxx: Bad usage of char channel.\n");
+        return(0);
+  }
+}
+
+static inline char
+INT_TO_CHAN(int chan)
+{
+  switch(chan)
+  {
+    case -1:
+       return(ALL_CHANNELS);
+    case 1:
+        return('B');
+    case 0:
+        return('A');
+    default:
+        printk(KERN_WARNING "aic7xxx: Bad usage of int channel.\n");
+        return('A');
+  }
+}
 
-#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
 
 #define TARGET_INDEX(cmd)  ((cmd)->target | ((cmd)->channel << 3))
 
@@ -1060,7 +1109,7 @@ aic7xxx_setup(char *s, int *dummy)
         }
         else
         {
-          *(options[i].flag) = !0;
+          *(options[i].flag) += 1;
         }
       }
     }
@@ -1448,10 +1497,10 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
   unsigned char ultra_enb, sxfrctl0;
 
   /*
-   * If the period is 0, then the device is requesting asynchronous
+   * If the offset is 0, then the device is requesting asynchronous
    * transfers.
    */
-  if (*period != 0)
+  if ((*period != 0) && (*offset != 0))
   {
     for (i = 0; i < num_aic7xxx_syncrates; i++)
     {
@@ -1476,8 +1525,8 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
 
         if (aic7xxx_verbose)
         {
-          printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, target, channel,
+          printk("(scsi%d:%d:%d:%d) Synchronous at %sMHz, "
+                 "offset %d.\n", p->host_no, CHAN_TO_INT(channel), target, 0,
                  aic7xxx_syncrates[i].english, *offset);
         }
         break;
@@ -1495,8 +1544,8 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
     *offset = 0;
     if (aic7xxx_verbose)
     {
-      printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
-             p->host_no, target, channel);
+      printk("(scsi%d:%d:%d:%d) Using asynchronous transfers.\n",
+             p->host_no, CHAN_TO_INT(channel), target, 0);
     }
   }
 
@@ -1550,10 +1599,14 @@ scbq_init(scb_queue_type *queue)
 static inline void
 scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
+  unsigned long processor_flags;
+  save_flags(processor_flags);
+  cli();
   scb->q_next = queue->head;
   queue->head = scb;
   if (queue->tail == NULL)       /* If list was empty, update tail. */
     queue->tail = queue->head;
+  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1567,10 +1620,14 @@ scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb)
 static inline void
 scbq_remove_head(scb_queue_type *queue)
 {
+  unsigned long processor_flags;
+  save_flags(processor_flags);
+  cli();
   if (queue->head != NULL)
     queue->head = queue->head->q_next;
   if (queue->head == NULL)       /* If list is now empty, update tail. */
     queue->tail = NULL;
+  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1584,6 +1641,9 @@ scbq_remove_head(scb_queue_type *queue)
 static inline void
 scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
+  unsigned long processor_flags;
+  save_flags(processor_flags);
+  cli();
   if (queue->head == scb)
   {
     /* At beginning of queue, remove from head. */
@@ -1612,6 +1672,7 @@ scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
       }
     }
   }
+  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1625,6 +1686,9 @@ scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
 static inline void
 scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
 {
+  unsigned long processor_flags;
+  save_flags(processor_flags);
+  cli();
   scb->q_next = NULL;
   if (queue->tail != NULL)       /* Add the scb at the end of the list. */
     queue->tail->q_next = scb;
@@ -1632,6 +1696,7 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
   queue->tail = scb;             /* Update the tail. */
   if (queue->head == NULL)       /* If list was empty, update head. */
     queue->head = queue->tail;
+  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1653,10 +1718,6 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
   int slun = scb->hscb->target_channel_lun & 0x07;
   int match;
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
-         scb->cmd->device->host->host_no, target, channel, targ, chan);
-#endif
   match = ((chan == channel) || (channel == ALL_CHANNELS));
   if (match != 0)
     match = ((targ == target) || (target == ALL_TARGETS));
@@ -1665,6 +1726,24 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
   if (match != 0)
     match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
 
+  if (aic7xxx_verbose > 4)
+  {
+    if (match)
+    {
+      printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) matches search criteria"
+        " (scsi%d:%d:%d:%d:tag%d)\n", scb->cmd->device->host->host_no,
+        CTL_OF_SCB(scb), scb->hscb->tag, scb->cmd->device->host->host_no,
+        CHAN_TO_INT(channel), target, lun, tag);
+    }
+    else
+    {
+      printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) doesn't match search criteria"
+        " (scsi%d:%d:%d:%d:tag%d)\n", scb->cmd->device->host->host_no,
+        CTL_OF_SCB(scb), scb->hscb->tag, scb->cmd->device->host->host_no,
+        CHAN_TO_INT(channel), target, lun, tag);
+    }
+  }
+
   return (match);
 }
 
@@ -1707,6 +1786,7 @@ aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
   prev = inb(p->base + SCB_PREV);
 
   outb(0, p->base + SCB_CONTROL);
+  outb(SCB_LIST_NULL, p->base + SCB_TAG);
 
   aic7xxx_add_curscb_to_free_list(p);
 
@@ -1834,12 +1914,6 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb   *scbp = NULL;
   struct aic7xxx_hwscb *hscbp = NULL;
-#ifdef AGRESSIVE
-  long processor_flags;
-
-  save_flags(processor_flags);
-  cli();
-#endif
 
   scbp = p->scb_data->free_scbs.head;
   if (scbp != NULL)
@@ -1871,16 +1945,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
       }
     }
   }
-#ifdef AIC7XXX_DEBUG
-  if (scbp != NULL)
-  {
-    p->activescbs++;
-  }
-#endif
 
-#ifdef AGRESSIVE
-  restore_flags(processor_flags);
-#endif
   return (scbp);
 }
 
@@ -1896,11 +1961,12 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
 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;
+  unsigned int flags;
+  save_flags(flags);
+  cli();
+  cmd->host_scribble = (char *)p->completeq.head;
+  p->completeq.head = cmd;
+  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1914,16 +1980,20 @@ static inline void
 aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
 {
   Scsi_Cmnd *cmd;
-
+  unsigned int processor_flags;
+  
+  save_flags(processor_flags);
+  cli();
   while (p->completeq.head != NULL)
   {
     cmd = p->completeq.head;
     p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
     cmd->host_scribble = NULL;
-    p->device_status[TARGET_INDEX(cmd)].active_cmds--;
+    restore_flags(processor_flags);
     cmd->scsi_done(cmd);
+    cli();
   }
-  p->completeq.tail = NULL;
+  restore_flags(processor_flags);
 }
 
 /*+F*************************************************************************
@@ -1937,11 +2007,8 @@ static void
 aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   struct aic7xxx_hwscb *hscb;
-  long flags;
 
   hscb = scb->hscb;
-  save_flags(flags);
-  cli();
 
   scb->flags = SCB_FREE;
   scb->cmd = NULL;
@@ -1949,11 +2016,6 @@ aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
   hscb->target_status = 0;
 
   scbq_insert_head(&p->scb_data->free_scbs, scb);
-#ifdef AIC7XXX_DEBUG
-  p->activescbs--;  /* For debugging purposes. */
-#endif
-
-  restore_flags(flags);
 }
 
 /*+F*************************************************************************
@@ -1967,17 +2029,23 @@ static void
 aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
 {
   Scsi_Cmnd *cmd = scb->cmd;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_scb *scbp;
+  unsigned char queue_depth;
 
   if (scb->flags & SCB_RECOVERY_SCB)
   {
-    p->flags &= ~IN_TIMEOUT;
+    p->flags &= ~ABORT_PENDING;
   }
-  if (cmd->result == DID_OK)
+  if (scb->flags & SCB_RESET)
   {
-    if (scb->flags & SCB_ABORTED)
-    {
-      cmd->result = (DID_RESET << 16);
-    }
+      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
+       (cmd->result & 0xffff);
+  }
+  else if (scb->flags & SCB_ABORT)
+  {
+      cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24) | 
+       (cmd->result & 0xffff);
   }
   if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
   {
@@ -1985,7 +2053,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
     int message_error = FALSE;
 
     mask = 0x01 << TARGET_INDEX(scb->cmd);
-
     /*
      * Check to see if we get an invalid message or a message error
      * after failing to negotiate a wide or sync transfer message.
@@ -2016,6 +2084,34 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
       }
     }
   }
+  queue_depth = (p->device_status[tindex].timer.expires) ?
+                p->device_status[tindex].temp_queue_depth :
+                p->device_status[tindex].max_queue_depth;
+  scbp = p->device_status[tindex].delayed_scbs.head;
+  if ( (scbp != NULL) && 
+       (queue_depth > p->device_status[tindex].active_cmds) )
+  {
+    scbq_remove_head(&p->device_status[tindex].delayed_scbs);
+    scbq_insert_tail(&p->waiting_scbs, scbp);
+    scbp = p->device_status[tindex].delayed_scbs.head;
+    if ( (scbp != NULL) && 
+         (queue_depth > (p->device_status[tindex].active_cmds + 1)) )
+    {
+      scbq_remove_head(&p->device_status[tindex].delayed_scbs);
+      scbq_insert_tail(&p->waiting_scbs, scbp);
+    }
+  }
+  if ( (p->device_status[tindex].timer.expires) &&
+      ((p->device_status[tindex].active_cmds == 1) ||
+       (p->device_status[tindex].max_queue_depth ==
+       p->device_status[tindex].temp_queue_depth)) )
+  {
+    del_timer(&p->device_status[tindex].timer);
+    p->device_status[tindex].timer.expires = 0;
+    p->device_status[tindex].temp_queue_depth = 
+          p->device_status[tindex].max_queue_depth;
+  }
+  p->device_status[tindex].active_cmds--;
   aic7xxx_free_scb(p, scb);
   aic7xxx_queue_cmd_complete(p, cmd);
 
@@ -2030,8 +2126,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
      * XXX: for each command, but apparently that's too difficult.
      */
     actual = aic7xxx_length(cmd, 0);
-    if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
-        && (aic7xxx_error(cmd) == 0))
+    if ((actual > 0) && (((cmd->result >> 16) & 0xf) == DID_OK))
     {
       struct aic7xxx_xferstats *sp;
       long *ptr;
@@ -2082,20 +2177,25 @@ static void
 aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
 {
   struct aic7xxx_scb *scb;
-  int i;
+  int i, found = 0;
 
   for (i = 0; i < p->scb_data->numscbs; i++)
   {
     scb = p->scb_data->scb_array[i];
     if (scb->flags & SCB_QUEUED_FOR_DONE)
     {
-#ifdef AIC7XXX_DEBUG_ABORT
-      printk("(scsi%d:%d:%d) Aborting scb %d\n",
-             p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-#endif
+      if (aic7xxx_verbose > 3)
+        printk("(scsi%d:%d:%d:%d) Aborting scb %d\n",
+             p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+      found++;
       aic7xxx_done(p, scb);
     }
   }
+  if (aic7xxx_verbose > 1)
+  {
+    printk(KERN_WARNING "(scsi%d:-1:-1:-1) %d commands found and queued for "
+       "completion.\n", p->host_no, found);
+  }
   if (complete)
   {
     aic7xxx_done_cmds_complete(p);
@@ -2127,6 +2227,7 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
    * Clear the necessary fields
    */
   outb(0, p->base + SCB_CONTROL);
+  outb(SCB_LIST_NULL, p->base + SCB_TAG);
 
   aic7xxx_add_curscb_to_free_list(p);
 
@@ -2153,9 +2254,8 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
    * system that the command has been aborted.
    */
   outb(curscb, p->base + SCBPTR);
-  scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+  scb->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
   scb->flags &= ~SCB_ACTIVE;
-  scb->cmd->result = (DID_RESET << 16);
 
   return (next);
 }
@@ -2170,7 +2270,7 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
  *-F*************************************************************************/
 static int
 aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
-    int lun, unsigned char tag, int flags, int requeue)
+    int lun, unsigned char tag, int flags, int requeue, scb_queue_type *queue)
 {
   unsigned char saved_queue[AIC7XXX_MAXSCB];
   int      queued = inb(p->base + QINCNT) & p->qcntmask;
@@ -2196,12 +2296,7 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
        }
        else
        {
-         scbp->flags = flags;
-         scbp->flags &= ~SCB_ACTIVE;
-         /*
-          * XXX - Don't know what error to use here.
-          */
-         aic7xxx_error(scbp->cmd) = DID_RESET;
+         scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
        }
        i--;
        found++;
@@ -2220,8 +2315,12 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
       /*
        * XXX - Shouldn't we be adding this to the free list?
        */
-      scbq_insert_head(&p->waiting_scbs, scbp);
-      scbp->flags |= SCB_WAITINGQ;
+      if ( !(scbp->flags & SCB_WAITINGQ) )
+      {    /*  OK...we aren't already on a queue, so put us on there  */
+        p->device_status[TARGET_INDEX(scbp->cmd)].active_cmds--;
+        scbq_insert_head(queue, scbp);
+        scbp->flags |= SCB_WAITINGQ;
+      }
       scbp = removed_scbs.head;
     }
   }
@@ -2235,33 +2334,38 @@ aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
  *
  * Description:
  *   The device at the given target/channel has been reset.  Abort
- *   all active and queued scbs for that target/channel.
+ *   all active and queued scbs for that target/channel.  This function
+ *   need not worry about linked next pointers because if was a MSG_ABORT_TAG
+ *   then we had a tagged command (no linked next), if it was MSG_ABORT or
+ *   MSG_BUS_DEV_RESET then the device won't know about any commands any more
+ *   and no busy commands will exist, and if it was a bus reset, then nothing
+ *   knows about any linked next commands any more.  In all cases, we don't
+ *   need to worry about the linked next or busy scb, we just need to clear
+ *   them.
  *-F*************************************************************************/
-static int
+static void
 aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
                      int lun, unsigned char tag)
 {
   struct aic7xxx_scb *scbp;
   unsigned char active_scb;
-  int i = 0;
-  int found;
+  int i = 0, j, init_lists = FALSE;
 
   /*
    * Restore this when we're done
    */
   active_scb = inb(p->base + SCBPTR);
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
-         p->host_no, target, CHAN_TO_INT(channel), active_scb);
-#endif
-
+  if (aic7xxx_verbose > 2)
+    printk("(scsi%d:%d:%d:%d) Reset device, active_scb %d\n",
+         p->host_no, CHAN_TO_INT(channel), target, lun, active_scb);
   /*
    * Deal with the busy target and linked next issues.
    */
   {
     int min_target, max_target;
     unsigned char busy_scbid;
+    struct aic7xxx_scb *scbp, *prev_scbp;
 
     /* Make all targets 'relative' to bus A. */
     if (target == ALL_TARGETS)
@@ -2285,103 +2389,166 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
     }
     else
     { 
-      min_target = target + channel == 'B' ? 8 : 0;
+      min_target = target + ((channel == 'B') ? 8 : 0);
       max_target = min_target;
     }
 
+
     for (i = min_target; i <= max_target; i++)
     {
-      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
-      if (busy_scbid < p->scb_data->numscbs)
+      if (aic7xxx_verbose > 2)
+       printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning up status information "
+         "and delayed_scbs.\n", p->host_no, CHAN_TO_INT(channel), i, lun);
+      busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/ TRUE);
+      p->device_status[i].flags &= ~BUS_DEVICE_RESET_PENDING;
+      p->device_status[i].last_reset = jiffies;
+      p->device_status[i].last_queue_full_count = 0;
+      p->device_status[i].last_queue_full = 0;
+      p->device_status[i].temp_queue_depth =
+        p->device_status[i].max_queue_depth;
+      j = 0; 
+      prev_scbp = NULL; 
+      scbp = p->device_status[i].delayed_scbs.head;
+      while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
       {
-       struct aic7xxx_scb *busy_scb;
-       struct aic7xxx_scb *next_scb;
-       unsigned char next_scbid;
-
-       busy_scb = p->scb_data->scb_array[busy_scbid];
-  
-       next_scbid = busy_scb->hscb->data_count >> 24;
-
-       if (next_scbid == SCB_LIST_NULL)
+        prev_scbp = scbp;
+        scbp = scbp->q_next;
+        if ( prev_scbp == scbp )
+        {
+         if (aic7xxx_verbose)
+           printk(KERN_WARNING "(scsi%d:%d:%d:%d) Yikes!! scb->q_next == scb "
+             "in the delayed_scbs queue!\n", p->host_no, CHAN_TO_INT(channel),
+              i, lun);
+         scbp = NULL;
+         prev_scbp->q_next = NULL;
+         p->device_status[i].delayed_scbs.tail = prev_scbp;
+        }
+        if (aic7xxx_match_scb(prev_scbp, target, channel, lun, tag))
         {
-         busy_scbid = aic7xxx_find_scb(p, busy_scb);
+         scbq_remove(&p->device_status[i].delayed_scbs, prev_scbp);
+         if ( prev_scbp->flags & SCB_WAITINGQ )
+           p->device_status[i].active_cmds++;
+         prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        }
+      }
+      if ( j > p->scb_data->numscbs )
+      {
+        if (aic7xxx_verbose)
+         printk(KERN_WARNING "(scsi%d:%d:%d:%d) Yikes!! There's a loop in the "
+           "delayed_scbs queue!\n", p->host_no, CHAN_TO_INT(channel),
+            i, lun);
+        scbq_init(&p->device_status[i].delayed_scbs);
+      }
+      if ( (p->device_status[i].delayed_scbs.head == NULL) &&
+           (p->device_status[i].timer.expires) )
+      {
+        del_timer(&p->device_status[i].timer);
+        p->device_status[i].timer.expires = 0;
+      }
+    }
+  }
 
-         if (busy_scbid != SCB_LIST_NULL)
-          {
-           outb(busy_scbid, p->base + SCBPTR);
-           next_scbid = inb(p->base + SCB_LINKED_NEXT);
-         }
-       }
+  if (aic7xxx_verbose > 2)
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning QINFIFO.\n", p->host_no,
+       CHAN_TO_INT(channel), target, lun );
+  aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
 
-       if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
-        {
-         aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
-       }
+/*
+ *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
+ *  ABORT/RESET commands.
+ */
+  if (aic7xxx_verbose > 2)
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning waiting_scbs.\n",
+       p->host_no, CHAN_TO_INT(channel), target, lun );
+  {
+    struct aic7xxx_scb *scbp, *prev_scbp;
 
-       if (next_scbid != SCB_LIST_NULL)
-        {
-         next_scb = p->scb_data->scb_array[next_scbid];
-         if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
-          {
-           continue;
-          }
-         /* Requeue for later processing */
-         scbq_insert_head(&p->waiting_scbs, next_scb);
-         next_scb->flags |= SCB_WAITINGQ;
-       }
+    j = 0; 
+    prev_scbp = NULL; 
+    scbp = p->waiting_scbs.head;
+    while ( (scbp != NULL) && (j++ <= p->scb_data->numscbs) )
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if ( prev_scbp == scbp )
+      {
+       if (aic7xxx_verbose)
+         printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!! scb->q_next == scb "
+           "in the waiting_scbs queue!\n", p->host_no);
+       scbp = NULL;
+       prev_scbp->q_next = NULL;
+       p->waiting_scbs.tail = prev_scbp;
+      }
+      if (aic7xxx_match_scb(prev_scbp, target, channel, lun, tag))
+      {
+       scbq_remove(&p->waiting_scbs, prev_scbp);
+       if ( prev_scbp->flags & SCB_WAITINGQ )
+         p->device_status[TARGET_INDEX(prev_scbp->cmd)].active_cmds++;
+       prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+       prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
+    if ( j > p->scb_data->numscbs )
+    {
+      if (aic7xxx_verbose)
+       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!! There's a loop in the "
+         "waiting_scbs queue!\n", p->host_no);
+      scbq_init(&p->waiting_scbs);
+    }
   }
 
-  found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
-      SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
 
   /*
    * Search waiting for selection list.
    */
+  if (aic7xxx_verbose > 2)
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Cleaning waiting for selection "
+       "list.\n", p->host_no, CHAN_TO_INT(channel), target, lun);
   {
     unsigned char next, prev, scb_index;
 
     next = inb(p->base + WAITING_SCBH);  /* Start at head of list. */
     prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
       outb(next, p->base + SCBPTR);
       scb_index = inb(p->base + SCB_TAG);
       if (scb_index >= p->scb_data->numscbs)
       {
-        panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
-              scb_index, p->scb_data->numscbs);
+       if (aic7xxx_verbose)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Waiting List inconsistency; "
+               "SCB index=%d, numscbs=%d\n", p->host_no,
+                CHAN_TO_INT(channel), target, lun, scb_index,
+                p->scb_data->numscbs);
+       next = inb(p->base + SCB_NEXT);
+       aic7xxx_add_curscb_to_free_list(p);
       }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      else
       {
-        unsigned char linked_next;
-
-        next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
-        linked_next = inb(p->base + SCB_LINKED_NEXT);
-        if (linked_next != SCB_LIST_NULL)
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
         {
-          struct aic7xxx_scb *next_scb;
-          /*
-           * Requeue the waiting SCB via the waiting list.
-           */
-          next_scb = p->scb_data->scb_array[linked_next];
-          if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
-          {
-            scbq_insert_head(&p->waiting_scbs, next_scb);
-            next_scb->flags |= SCB_WAITINGQ;
-          }
+          next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+         scbp->flags &= ~SCB_ACTIVE;
+         scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+        }
+        else
+        {
+          prev = next;
+          next = inb(p->base + SCB_NEXT);
         }
-        found++;
-      }
-      else
-      {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
       }
     }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      if (aic7xxx_verbose)
+       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
+         "waiting for selection list!\n", p->host_no);
+      init_lists = TRUE;
+    }
   }
 
   /*
@@ -2393,45 +2560,106 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
 
     next = inb(p->base + DISCONNECTED_SCBH);
     prev = SCB_LIST_NULL;
-
-    while (next != SCB_LIST_NULL)
+    j = 0;
+    while ( (next != SCB_LIST_NULL) && (j++ <= p->scb_data->maxhscbs) )
     {
       outb(next, p->base + SCBPTR);
       scb_index = inb(p->base + SCB_TAG);
       if (scb_index > p->scb_data->numscbs)
       {
-        panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
-              "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
-      }
-      scbp = p->scb_data->scb_array[scb_index];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
-      {
-        next = aic7xxx_rem_scb_from_disc_list(p, next);
+       if (aic7xxx_verbose)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Waiting List inconsistency; "
+               "SCB index=%d, numscbs=%d\n", p->host_no,
+                CHAN_TO_INT(channel), target, lun, scb_index,
+                p->scb_data->numscbs);
+       next = aic7xxx_rem_scb_from_disc_list(p, next);
       }
       else
       {
-        prev = next;
-        next = inb(p->base + SCB_NEXT);
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_rem_scb_from_disc_list(p, next);
+         scbp->flags = SCB_RESET | SCB_QUEUED_FOR_DONE;
+         scbp->hscb->control = 0;
+        }
+        else
+        {
+          prev = next;
+          next = inb(p->base + SCB_NEXT);
+        }
       }
     }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      if (aic7xxx_verbose)
+       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
+         "disconnected list!\n", p->host_no);
+      init_lists = TRUE;
+    }
+  }
+
+  /*
+   * Walk the free list making sure no entries on the free list have
+   * a valid SCB_TAG value or SCB_CONTROL byte.
+   */
+  {
+    unsigned char next;
+
+    j = 0;
+    next = inb(p->base + FREE_SCBH);
+    while ( (next != SCB_LIST_NULL) && (j++ < p->scb_data->maxhscbs) )
+    {
+      outb(next, p->base + SCBPTR);
+      outb(SCB_LIST_NULL, p->base + SCB_TAG);
+      outb(0, p->base + SCB_CONTROL);
+      next = inb(p->base + SCB_NEXT);
+    }
+    if ( j > p->scb_data->maxhscbs )
+    {
+      if (aic7xxx_verbose)
+       printk(KERN_WARNING "(scsi%d:-1:-1:-1) Yikes!!  There is a loop in the "
+         "free list!\n", p->host_no);
+      init_lists = TRUE;
+    }
   }
 
   /*
    * Go through the hardware SCB array looking for commands that
    * were active but not on any list.
    */
-  for (i = 0; i < p->scb_data->maxhscbs; i++)
+  if (init_lists)
+  {
+    outb(SCB_LIST_NULL, p->base + FREE_SCBH);
+    outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
+    outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+  }
+  for (i = p->scb_data->maxhscbs; i >= 0; --i)
   {
     unsigned char scbid;
 
-    outb(i, p->base + SCBPTR);
-    scbid = inb(p->base + SCB_TAG);
-    if (scbid < p->scb_data->numscbs)
+    if (init_lists)
+    {
+      outb(SCB_LIST_NULL, p->base + SCB_TAG);
+      outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+      outb(SCB_LIST_NULL, p->base + SCB_PREV);
+      outb(SCB_LIST_NULL, p->base + SCB_LINKED_NEXT);
+      outb(0, p->base + SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    else
     {
-      scbp = p->scb_data->scb_array[scbid];
-      if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+      outb(i, p->base + SCBPTR);
+      scbid = inb(p->base + SCB_TAG);
+      if (scbid < p->scb_data->numscbs)
       {
-        aic7xxx_add_curscb_to_free_list(p);
+        scbp = p->scb_data->scb_array[scbid];
+        if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+        {
+         outb(0, p->base + SCB_CONTROL);
+         outb(SCB_LIST_NULL, p->base + SCB_TAG);
+          aic7xxx_add_curscb_to_free_list(p);
+        }
       }
     }
   }
@@ -2447,24 +2675,24 @@ aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
     if (((scbp->flags & SCB_ACTIVE) != 0) &&
         aic7xxx_match_scb(scbp, target, channel, lun, tag))
     {
-      scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       scbp->flags &= ~SCB_ACTIVE;
-      aic7xxx_error(scbp->cmd) = DID_RESET;
-
-      found++;
 
       if ((scbp->flags & SCB_WAITINGQ) != 0)
       {
         scbq_remove(&p->waiting_scbs, scbp);
+        scbq_remove(&p->device_status[TARGET_INDEX(scbp->cmd)].delayed_scbs,
+         scbp);
         scbp->flags &= ~SCB_WAITINGQ;
+       p->device_status[TARGET_INDEX(scbp->cmd)].active_cmds++;
       }
     }
   }
 
   outb(active_scb, p->base + SCBPTR);
-  return (found);
 }
 
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_clear_intstat
@@ -2521,20 +2749,18 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p)
  * Description:
  *   Reset the channel.
  *-F*************************************************************************/
-static int
+static void
 aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
 {
   unsigned long offset, offset_max;
-  int found;
   unsigned char sblkctl;
   char cur_channel;
 
-  pause_sequencer(p);
-  /*
-   * Clean up all the state information for the pending transactions
-   * on this bus.
-   */
-  found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+  if (aic7xxx_verbose > 1)
+    printk(KERN_WARNING "(scsi%d:%d:-1:-1) Reset channel called, %s initiate "
+       "reset.\n", p->host_no, CHAN_TO_INT(channel),
+       (initiate_reset == TRUE) ? "will" : "won't" );
+
 
   if (channel == 'B')
   {
@@ -2587,10 +2813,9 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
     /*
      * Case 1: Command for another bus is active
      */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Stealthily resetting channel %c\n",
-           p->host_no, channel);
-#endif
+    if (aic7xxx_verbose > 2)
+      printk(KERN_WARNING "(scsi%d:%d:-1:-1) Stealthily resetting idle "
+           "channel.\n", p->host_no, CHAN_TO_INT(channel));
     /*
      * Stealthily reset the other bus without upsetting the current bus.
      */
@@ -2599,52 +2824,50 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
-      /*
-       * Cause the mid-level SCSI code to delay any further 
-       * queueing by the bus settle time for us.
-       */
-      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
     }
     outb(0, p->base + SCSISEQ);
     aic7xxx_clear_intstat(p);
     outb(sblkctl, p->base + SBLKCTL);
-    unpause_sequencer(p, /* unpause_always */ FALSE);
   }
   else
   {
     /*
      * Case 2: A command from this bus is active or we're idle.
      */
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Resetting current channel %c\n",
-           p->host_no, channel);
-#endif
+    if (aic7xxx_verbose > 2)
+      printk(KERN_WARNING "(scsi%d:%d:-1:-1) Resetting currently active "
+       "channel.\n", p->host_no, CHAN_TO_INT(channel));
     outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     if (initiate_reset)
     {
       aic7xxx_reset_current_bus(p);
-      /*
-       * Cause the mid-level SCSI code to delay any further 
-       * queueing by the bus settle time for us.
-       */
-#if 0
-      p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-#endif
     }
     outb(0, p->base + SCSISEQ);
     aic7xxx_clear_intstat(p);
+  }
+  if (aic7xxx_verbose)
+    printk(KERN_WARNING "(scsi%d:%d:-1:-1) Channel reset\n",
+       p->host_no, CHAN_TO_INT(channel));
+  /*
+   * Clean up all the state information for the pending transactions
+   * on this bus.
+   */
+  aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+
+  if ( p->bus_type != AIC_TWIN )
+  {
     restart_sequencer(p);
-#ifdef AIC7XXX_DEBUG_ABORT
-    printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
-#endif
+    pause_sequencer(p);
   }
 
+  p->host->last_reset = jiffies + (HZ * AIC7XXX_RESET_DELAY);
+
   /*
    * Now loop through all the SCBs that have been marked for abortion,
    * and call the scsi_done routines.
    */
   aic7xxx_run_done_queue(p, /*complete*/ TRUE);
-  return (found);
+  return;
 }
 
 /*+F*************************************************************************
@@ -2659,14 +2882,16 @@ static inline void
 aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
 {
   struct aic7xxx_scb *scb;
+  int tindex;
+
 
   if (p->waiting_scbs.head == NULL)
     return;
 
-  pause_sequencer(p);
   /*
    * First handle SCBs that are waiting but have been assigned a slot.
    */
+  pause_sequencer(p);
   scb = p->waiting_scbs.head;
   while (scb != NULL)
   {
@@ -2682,26 +2907,73 @@ aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
     /*
      * We have some space.
      */
-    scbq_remove_head(&(p->waiting_scbs));
-    scb->flags &= ~SCB_WAITINGQ;
-
-    outb(scb->hscb->tag, p->base + QINFIFO);
-
-    if ((p->flags & PAGE_ENABLED) != 0)
+    scbq_remove_head(&p->waiting_scbs);
+    tindex = TARGET_INDEX(scb->cmd);
+    if ( p->device_status[tindex].active_cmds >=
+         p->device_status[tindex].temp_queue_depth )
     {
-      /*
-       * We only care about this statistic when paging
-       * since it's impossible to overflow the qinfifo
-       * in the non-paging case.
-       */
-      p->curqincnt++;
+        scbq_insert_tail(&p->device_status[tindex].delayed_scbs, scb);
+    }
+    else
+    {
+        scb->flags &= ~SCB_WAITINGQ;
+        p->device_status[tindex].active_cmds++;
+        outb(scb->hscb->tag, p->base + QINFIFO);
+        p->curqincnt++;
     }
     scb = p->waiting_scbs.head;
   }
-
   unpause_sequencer(p, FALSE);
 }
 
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_timer
+ *
+ * Description:
+ *   Take expired extries off of delayed queues and place on waiting queue
+ *   then run waiting queue to start commands.
+ ***************************************************************************/
+static void
+aic7xxx_timer(struct aic7xxx_host *p)
+{
+   int i;
+   unsigned long processor_flags;
+   struct aic7xxx_scb *scb;
+   
+   save_flags(processor_flags);
+   cli();
+   if (aic7xxx_verbose > 3)
+     printk(KERN_WARNING "(scsi%d:-1:-1:-1) Timer running.\n", p->host_no);
+   for(i=0; i<MAX_TARGETS; i++)
+   {
+     if ( (p->device_status[i].timer.expires) && 
+          (p->device_status[i].timer.expires <= jiffies) )
+     {
+       p->device_status[i].timer.expires = 0;
+       if ( (p->device_status[i].timer.prev != NULL) ||
+            (p->device_status[i].timer.next != NULL) )
+       {
+         del_timer(&p->device_status[i].timer);
+       }
+       p->device_status[i].temp_queue_depth = 
+        p->device_status[i].max_queue_depth;
+       scb = p->device_status[i].delayed_scbs.head;
+       while ( scb != NULL )
+       {
+         scbq_remove_head(&p->device_status[i].delayed_scbs);
+         scbq_insert_tail(&p->waiting_scbs, scb);
+         scb = p->device_status[i].delayed_scbs.head;
+       }
+     }
+   }
+   aic7xxx_run_waiting_queues(p);
+   unpause_sequencer(p, FALSE);
+   restore_flags(processor_flags);
+}
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_construct_sdtr
@@ -2777,11 +3049,11 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
               (hscb->residual_data_count[1] <<  8) |
               hscb->residual_data_count[0];
 
-    if (actual < cmd->underflow)
+    if ( (actual < cmd->underflow) && (aic7xxx_verbose) )
     {
-      printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Underflow - "
              "Wanted at least %u, got %u, residual SG count %d.\n",
-             p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
+             p->host_no, CTL_OF_SCB(scb), cmd->underflow, actual,
              hscb->residual_SG_segment_count);
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
       aic7xxx_status(cmd) = hscb->target_status;
@@ -2811,7 +3083,6 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
   unsigned short targ_mask;
   unsigned char  targ_scratch;
   int scratch_offset = target;
-  int found;
 
   if (channel == 'B')
   {
@@ -2828,9 +3099,10 @@ aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
   targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
   targ_scratch &= SXFR;
   outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
-  found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
-  printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
-         "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+  aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+  if (aic7xxx_verbose)
+    printk(KERN_WARNING "(scsi%d:%d:%d:-1) Bus Device Reset delivered.\n",
+         p->host_no, CHAN_TO_INT(channel), target);
   aic7xxx_run_done_queue(p, /*complete*/ TRUE);
 }
 
@@ -2846,7 +3118,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
 {
   struct aic7xxx_scb *scb;
   unsigned short target_mask;
-  unsigned char target, scratch_offset;
+  unsigned char target, scratch_offset, lun;
+  unsigned char queue_flag = FALSE;
   char channel;
 
   if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
@@ -2859,6 +3132,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
   }
   scratch_offset = target;
   channel = 'A';
+  lun = inb(p->base + SAVED_TCL) & 0x07;
   if (inb(p->base + SBLKCTL) & SELBUSB)
   {
     channel = 'B';
@@ -2900,19 +3174,20 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           {
             /*
              * We expected this.  Let the busfree handler take care
-             * of this when we the abort is finially sent.  Set
+             * of this when we the abort is finally sent.  Set
              * IDENTIFY_SEEN so that the busfree handler knows that
              * there is an SCB to cleanup.
              */
             outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
-            printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
-                   p->host_no, TC_OF_SCB(scb));
+           if (aic7xxx_verbose > 1)
+              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reconnect SCB abort "
+               "successful\n", p->host_no, CTL_OF_SCB(scb));
             break;
           }
         }
-        printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) No active SCB for reconnecting "
                "target - Issuing BUS DEVICE RESET.\n",
-               p->host_no, target, CHAN_TO_INT(channel));
+               p->host_no, CHAN_TO_INT(channel), target, lun);
 
         printk(KERN_WARNING "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
                inb(p->base + SAVED_TCL), arg1,
@@ -2932,9 +3207,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         scb_index = inb(p->base + CUR_SCBID);
         scb = p->scb_data->scb_array[scb_index];
 
-        panic("scsi%d:  Target %d, channel %c, Target busy link failure, "
+        panic("(scsi%d:%d:%d:%d) Target busy link failure, "
               "but busy SCB exists!\n",
-              p->host_no, target, channel);
+              p->host_no, CHAN_TO_INT(channel), target, lun );
       }
       break;
 
@@ -2943,10 +3218,11 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
         unsigned char rej_byte;
 
         rej_byte = inb(p->base + REJBYTE);
-        printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
-               "received from target, SEQ_FLAGS=0x%x\n",
-               p->host_no, target, CHAN_TO_INT(channel), rej_byte,
-               inb(p->base + SEQ_FLAGS));
+       if (aic7xxx_verbose > 1)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Rejecting unknown message "
+               "(0x%x) received from target, SEQ_FLAGS=0x%x\n",
+               p->host_no, CHAN_TO_INT(channel), target, lun,
+               rej_byte, inb(p->base + SEQ_FLAGS));
       }
       break;
 
@@ -2959,31 +3235,28 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
          * The only safe thing to do is to blow it away with a bus
          * reset.
          */
-        int found;
-
-        printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
-               "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
-               p->host_no, target, CHAN_TO_INT(channel),
+        if (aic7xxx_verbose)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target did not send an "
+               "IDENTIFY message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
+               p->host_no, CHAN_TO_INT(channel), target, lun,
                inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
 
-        found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+        aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
 
-        printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
-              "%d SCBs aborted\n", p->host_no, channel, found);
       }
       break;
 
     case BAD_PHASE:
       if (inb(p->base + LASTPHASE) == P_BUSFREE)
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
-               p->host_no, CHAN_TO_INT(channel), target);
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Missed busfree.\n",
+               p->host_no, CHAN_TO_INT(channel), target, lun);
         restart_sequencer(p);
       }
       else
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
-               "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Unknown scsi bus phase, "
+               "continuing\n", p->host_no, CHAN_TO_INT(channel), target, lun);
       }
       break;
 
@@ -3054,11 +3327,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               }
               else
               {
-               /* We went too low - force async. */
+               /*
+                 * We went too low - force async and disable future
+                 * sync negotiation
+                 */
+                p->needsdtr_copy &= ~target_mask;
                outb(SEND_REJ, p->base + RETURN_1);
               }
             }
-            else
+            else if ( offset != 0 )
             {
               /*
                * Send our own SDTR in reply.
@@ -3066,14 +3343,26 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                * We want to see this message as we don't expect a target
                * to send us a SDTR request first.
                */
-              printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
+              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Sending reply SDTR.\n",
+                p->host_no, CTL_OF_SCB(scb));
               aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
               outb(SEND_MSG, p->base + RETURN_1);
             }
+            else
+            {
+              /*
+               * The incoming SDTR was too low, reject it.
+               */
+              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Rejecting SDTR request.\n",
+                p->host_no, CTL_OF_SCB(scb));
+              outb(SEND_REJ, p->base + RETURN_1);
+              p->needsdtr_copy &= ~target_mask;
+            }
             /*
              * Clear the flags.
              */
             p->needsdtr &= ~target_mask;
+            p->sdtr_pending &= ~target_mask;
             break;
           }
 
@@ -3099,14 +3388,15 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               switch (bus_width)
               {
                case BUS_8_BIT:
+                  p->needwdtr_copy &= ~target_mask;
                  scratch &= 0x7F;
                  break;
 
                case BUS_16_BIT:
                   if (aic7xxx_verbose)
                   {
-                   printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
-                        "bit transfers.\n", p->host_no, target, channel);
+                   printk(KERN_INFO "(scsi%d:%d:%d:%d) Using 16 bit (Wide)"
+                        "transfers.\n", p->host_no, CTL_OF_SCB(scb));
                   }
                  scratch |= WIDEXFER;
                  break;
@@ -3114,9 +3404,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                case BUS_32_BIT:
                  outb(SEND_REJ, p->base + RETURN_1);
                   /* No verbose here!  We want to see this condition. */
-                 printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
+                 printk(KERN_WARNING "(scsi%d:%d:%d:%d) "
                        "requesting 32 bit transfers, rejecting...\n",
-                        p->host_no, target, channel);
+                        p->host_no, CTL_OF_SCB(scb));
                  break;
 
                default:
@@ -3133,6 +3423,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               switch (bus_width)
               {
                case BUS_8_BIT:
+                  p->needwdtr_copy &= ~target_mask;
                  scratch &= 0x7F;
                  break;
 
@@ -3140,8 +3431,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                case BUS_16_BIT:
                  if (p->bus_type == AIC_WIDE)
                  {
-                    printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
-                          "bit transfers.\n", p->host_no, target, channel);
+                    printk(KERN_INFO "(scsi%d:%d:%d:%d) Using 16 bit (Wide)"
+                          "transfers.\n", p->host_no, CTL_OF_SCB(scb));
                     bus_width = BUS_16_BIT;
                     scratch |= WIDEXFER;
                  }
@@ -3159,9 +3450,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               if (send_reject)
               {
                 outb(SEND_REJ, p->base + RETURN_1);
-                printk(KERN_WARNING "scsi%d: Target %d, channel %c, initiating "
-                       "wide negotiation on a narrow bus - rejecting!\n",
-                       p->host_no, target, channel);
+                printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target initiated "
+                       "wide negotiation on a narrow bus - rejecting!",
+                       p->host_no, CTL_OF_SCB(scb));
               }
               else
               {
@@ -3170,6 +3461,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               }
             }
             p->needwdtr &= ~target_mask;
+            p->wdtr_pending &= ~target_mask;
             outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
             outb(scratch, p->base + SCSIRATE);
             break;
@@ -3206,9 +3498,12 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
            */
           targ_scratch &= 0x7F;
           p->needwdtr &= ~target_mask;
-          printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+          p->needwdtr_copy &= ~target_mask;
+          p->wdtr_pending &= ~target_mask;
+          if (aic7xxx_verbose)
+            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Refusing WIDE "
                 "negotiation; using 8 bit transfers.\n",
-                p->host_no, target, channel);
+                p->host_no, CTL_OF_SCB(scb));
        }
        else
        {
@@ -3219,9 +3514,12 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
              */
             targ_scratch &= 0xF0;
             p->needsdtr &= ~target_mask;
-            printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
+            p->needsdtr_copy &= ~target_mask;
+            p->sdtr_pending &= ~target_mask;
+           if (aic7xxx_verbose)
+              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Refusing "
                   "synchronous negotiation; using asynchronous transfers.\n",
-                  p->host_no, target, channel);
+                  p->host_no, CTL_OF_SCB(scb));
           }
           /*
            * Otherwise, we ignore it.
@@ -3256,9 +3554,10 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
        outb(0, p->base + RETURN_1);
        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
        {
-          printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Invalid SCB during "
                 "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
-                intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
+                CHAN_TO_INT(channel), target, lun, intstat, scb_index,
+                 scb->flags, (unsigned int) scb->cmd);
        }
        else
        {
@@ -3271,8 +3570,8 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
           switch (status_byte(hscb->target_status))
           {
             case GOOD:
-             printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
-                     "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+             printk(KERN_WARNING "(scsi%d:%d:%d:%d) Interrupted for status of "
+                     "GOOD???\n", p->host_no, CTL_OF_SCB(scb));
               break;
 
             case CHECK_CONDITION:
@@ -3331,7 +3630,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
                 aic7xxx_busy_target(p, target, channel, hscb->tag);
                outb(SEND_SENSE, p->base + RETURN_1);
               }  /* first time sense, no errors */
-             else
+              else
              {
                if (aic7xxx_error(cmd) == 0)
                {
@@ -3341,56 +3640,94 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
               break;
 
             case QUEUE_FULL:
-#ifdef NOT_YET
-              if (scb->hscb->control & TAG_ENB)
+              queue_flag = TRUE;    /* Mark that this is a QUEUE_FULL and */
+            case BUSY:              /* drop through to here */
+            {
+              struct aic7xxx_scb *next_scbp, *prev_scbp;
+              int ti = TARGET_INDEX(scb->cmd);
+              
+              aic7xxx_search_qinfifo(p, target, channel, lun,
+                SCB_LIST_NULL, 0, TRUE,
+                &p->device_status[ti].delayed_scbs);
+              next_scbp = p->waiting_scbs.head;
+              while ( next_scbp != NULL )
               {
-               if (cmd->device->queue_depth > 2)
-               {
-                  cmd->device->queue_depth--;  /* Not correct */
-                  printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
-                        "reduced to %d\n", p->host_no,
-                        TC_OF_SCB(scb), cmd->device->queue_depth);
-               }
-               /*
-                * XXX - Requeue this unconditionally?
-                */
-
-               /*
-                * We'd like to be able to give the SCB some more time
-                * (untimeout, then timeout).
-                */
-               break;
+                prev_scbp = next_scbp;
+                next_scbp = next_scbp->q_next;
+                if ( aic7xxx_match_scb(prev_scbp, target, channel, lun,
+                     SCB_LIST_NULL) )
+                {
+                  scbq_remove(&p->waiting_scbs, prev_scbp);
+                  scbq_insert_tail(&p->device_status[ti].delayed_scbs,
+                    prev_scbp);
+                }
               }
-#endif
-              printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
+             scbq_insert_head(&p->device_status[ti].delayed_scbs, scb);
+             p->device_status[ti].active_cmds--;
+             scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY;
+                  
+              if (p->device_status[ti].timer.expires == 0) 
+              {
+               if ( p->device_status[ti].active_cmds )
+               {
+                  p->device_status[ti].timer.expires = jiffies + (HZ * 2);
+                  add_timer(&p->device_status[ti].timer);
+               }
+               else
+               {
+                  p->device_status[ti].timer.expires = jiffies + (HZ / 2);
+                  add_timer(&p->device_status[ti].timer);
+               }
+              }
+             if (aic7xxx_verbose > 1)
+              {
+                if (queue_flag)
+                  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queue full received; "
                      "queue depth %d, active %d\n", p->host_no,
-                     TC_OF_SCB(scb), cmd->device->queue_depth,
-                     p->device_status[TARGET_INDEX(cmd)].active_cmds);
+                     CTL_OF_SCB(scb), p->device_status[ti].max_queue_depth,
+                     p->device_status[ti].active_cmds);
+                else
+                  printk(KERN_WARNING "(scsi%d:%d:%d:%d) Target busy\n",
+                     p->host_no, CTL_OF_SCB(scb));
 
-              /* Else treat this as if it was a BUSY condition. */
-              scb->hscb->target_status = (BUSY << 1) |
-                  (scb->hscb->target_status & 0x01);
-              /* Fall through to the BUSY case. */
-
-            case BUSY:
-              printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
-                     p->host_no, TC_OF_SCB(scb));
-              if (!aic7xxx_error(cmd))
+              }
+              if (queue_flag)
               {
-               /*
-                * The mid-level SCSI code should be fixed to
-                * retry the command at a later time instead of
-                * trying right away.
-                */
-               aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
+               p->device_status[ti].temp_queue_depth = 
+                 p->device_status[ti].active_cmds;
+                if ( (p->device_status[ti].last_queue_full <
+                     (p->device_status[ti].active_cmds - 1)) ||
+                     (p->device_status[ti].last_queue_full >
+                     (p->device_status[ti].active_cmds + 1)) )
+                {
+                  p->device_status[ti].last_queue_full = 
+                      p->device_status[ti].active_cmds;
+                  p->device_status[ti].last_queue_full_count = 0;
+                }
+                else
+                {
+                  p->device_status[ti].last_queue_full_count++;
+                }
+                if ( (p->device_status[ti].last_queue_full_count > 14) &&
+                     (p->device_status[ti].active_cmds > 4) )
+                {
+                 if (aic7xxx_verbose)
+                    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queue depth reduced "
+                      "to %d\n", p->host_no, CTL_OF_SCB(scb), 
+                      p->device_status[ti].active_cmds);
+                  p->device_status[ti].max_queue_depth = 
+                      p->device_status[ti].active_cmds;
+                  p->device_status[ti].last_queue_full = 0;
+                  p->device_status[ti].last_queue_full_count = 0;
+                }
               }
-              udelay(1000);  /*  A small pause (1ms) to help the drive */
               break;
-
+            }
+            
             default:
-              printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
+              printk(KERN_WARNING "(scsi%d:%d:%d:%d) Unexpected target "
                      "status 0x%x.\n", p->host_no,
-                    TC_OF_SCB(scb), scb->hscb->target_status);
+                    CTL_OF_SCB(scb), scb->hscb->target_status);
               if (!aic7xxx_error(cmd))
               {
                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
@@ -3419,8 +3756,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
        {
           outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
           outb(1, p->base + MSG_LEN);
-          printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
-                p->host_no, TC_OF_SCB(scb));
+          if (aic7xxx_verbose > 1)
+            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset mailed.\n",
+                p->host_no, CTL_OF_SCB(scb));
        }
         else if (scb->flags & SCB_ABORT)
         {
@@ -3433,8 +3771,9 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
             outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
           }
           outb(message_offset + 1, p->base + MSG_LEN);
-          printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
-                 p->host_no, TC_OF_SCB(scb));
+          if (aic7xxx_verbose > 1)
+            printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort message mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
         }
        else if (scb->flags & SCB_MSGOUT_WDTR)
        {
@@ -3485,18 +3824,21 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
        overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
                  (inb(p->base + STCNT + 2) << 16);
        overrun = 0x00FFFFFF - overrun;
-       printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
-               "in %s phase, tag %d; forcing a retry.\n",
-               p->host_no, TC_OF_SCB(scb), overrun,
+        if (aic7xxx_verbose)
+        {
+         printk(KERN_WARNING "(scsi%d:%d:%d:%d) Data overrun of %d bytes "
+               "detected in %s phase, tag %d; forcing a retry.\n",
+               p->host_no, CTL_OF_SCB(scb), overrun,
                lastphase == P_DATAIN ? "Data-In" : "Data-Out",
                scb->hscb->tag);
-        printk(KERN_WARNING "%s seen Data Phase.  Length = %d, NumSGs = %d.\n",
+          printk(KERN_WARNING "%s seen Data Phase. Length=%d, NumSGs=%d.\n",
                inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
                aic7xxx_length(scb->cmd, 0), scb->sg_count);
-        for (i = 0; i < scb->sg_count; i++)
-        {
-          printk(KERN_INFO "     sg[%d] - Addr 0x%x : Length %d\n",
-                 i, scb->sg_list[i].address, scb->sg_list[i].length);
+          for (i = 0; i < scb->sg_count; i++)
+          {
+            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                   i, scb->sg_list[i].address, scb->sg_list[i].length);
+          }
         }
        /*
         * XXX - What do we really want to do on an overrun?  The
@@ -3606,21 +3948,14 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
       sindex = inb(p->base + SINDEX);
       message = inb(p->base + sindex - 1);
 
-      if (message == MSG_ABORT)
-      {
-        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
-                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
-        aic7xxx_run_done_queue(p, /* complete */ TRUE);
-        scb = NULL;
-        printerror = 0;
-      }
-      else if (message == MSG_ABORT_TAG)
+      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
       {
-        printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
-                   p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
-        aic7xxx_run_done_queue(p, /* complete */ TRUE);
+       if (aic7xxx_verbose > 1)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB %d abort delivered.\n",
+                   p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+               (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+       aic7xxx_run_done_queue(p, FALSE);
         scb = NULL;
         printerror = 0;
       }
@@ -3645,15 +3980,18 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
         {
           tag = SCB_LIST_NULL;
         }
-        aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
+       aic7xxx_run_done_queue(p, FALSE);
       }
       else
-      {
-        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+      {  /* Since we don't really know what happened here, we'll wait */
+        /* for the commands to timeout and get aborted if need be    */
+        aic7xxx_add_curscb_to_free_list(p);
       }
       printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
              "SEQADDR = 0x%x\n", p->host_no, lastphase,
              (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+      scb = NULL;
     }
     outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
     outb(CLRBUSFREE, p->base + CLRSINT1);
@@ -3784,8 +4122,8 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
      * A parity error has occurred during a data
      * transfer phase. Flag it and continue.
      */
-    printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
-           p->host_no, TC_OF_SCB(scb), phase);
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Parity error during phase %s.\n",
+           p->host_no, CTL_OF_SCB(scb), phase);
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -3825,7 +4163,6 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
   if (scb != NULL)
   {
     aic7xxx_done(p, scb);
-    aic7xxx_done_cmds_complete(p);
   }
 }
 
@@ -3845,6 +4182,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
   struct aic7xxx_host *p;
   unsigned char intstat;
   unsigned long flags;
+  unsigned int interrupts_cleared = 0;
 
   p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
 
@@ -3897,7 +4235,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
 
   if (p->flags & IN_ISR)
   {
-    printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
+    panic(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
            p->host_no);
     return;
   }
@@ -3906,7 +4244,6 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
    * Indicate that we're in the interrupt handler.
    */
   save_flags(flags);
-  cli();
   p->flags |= IN_ISR;
 
   if (intstat & CMDCMPLT)
@@ -3915,88 +4252,72 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
     Scsi_Cmnd *cmd;
     unsigned char qoutcnt;
     unsigned char scb_index;
-    int i, interrupts_cleared = 0;
+    int i;
 
     /*
      * The sequencer will continue running when it
      * issues this interrupt. There may be >1 commands
      * finished, so loop until we've processed them all.
      */
+    cli();
     qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
 
 #if 1
   if (qoutcnt >= p->qfullcount - 1)
-    printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
-           "qoutcnt = %d.\n", qoutcnt);
+    printk(KERN_WARNING "(scsi%d:-1:-1:-1) Command complete near Qfull count, "
+           "qoutcnt = %d.\n", p->host_no, qoutcnt);
 #endif
     while (qoutcnt > 0)
     {
-      if ((p->flags & PAGE_ENABLED) != 0)
+      for (i = 0; i < qoutcnt; i++)
       {
-        p->cmdoutcnt += qoutcnt;
-        if (p->cmdoutcnt >= p->qfullcount)
+        if (p->flags & PAGE_ENABLED)
         {
-          /*
-           * Since paging only occurs on aic78x0 chips, we can use
-           * Auto Access Pause to clear the command count.
-           */
-          outb(0, p->base + CMDOUTCNT);
-          p->cmdoutcnt = 0;
+          p->cmdoutcnt += qoutcnt;
+          if ( p->cmdoutcnt >= p->qfullcount )
+          {
+            outb(0, p->base + CMDOUTCNT);
+            p->cmdoutcnt = 0;
+          }
         }
-      }
-      for (i = 0; i < qoutcnt; i++)
-      {
         scb_index = inb(p->base + QOUTFIFO);
-        scb = p->scb_data->scb_array[scb_index];
+       if ( scb_index >= p->scb_data->numscbs )
+           scb = NULL;
+       else
+            scb = p->scb_data->scb_array[scb_index];
         if (scb == NULL)
         {
-         printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
-                "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
+         printk(KERN_WARNING "(scsi%d:-1:-1:-1) CMDCMPLT with invalid SCB "
+                "index %d, QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
                  inb(p->base + QOUTCNT), inb(p->base + QINCNT));
           continue;
         }
         else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
         {
-         printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
-                "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
+         printk(KERN_WARNING "(scsi%d:-1:-1:-1) CMDCMPLT without command for "
+                "SCB %d, QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
                  p->host_no, scb_index, inb(p->base + QOUTCNT),
                  inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
          continue;
         }
-        cmd = scb->cmd;
-        if (scb->hscb->residual_SG_segment_count != 0)
-        {
-          aic7xxx_calculate_residual(p, scb);
-        }
-        if ((scb->flags & SCB_QUEUED_ABORT) != 0)
-        {
-          /*
-           * Have to clean up any possible entries in the
-           * waiting queue and the QINFIFO.
-           */
-          int target;
-          char channel;
-          int lun;
-          unsigned char tag;
-
-          tag = SCB_LIST_NULL;
-          target = cmd->target;
-          lun = cmd->lun;
-          channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
-          if (scb->hscb->control & TAG_ENB)
-          {
-            tag = scb->hscb->tag;
-          }
-          aic7xxx_reset_device(p, target, channel, lun, tag);
-          /*
-           * Run the done queue, but don't complete the commands; we
-           * do this once at the end of the loop.
-           */
-          aic7xxx_run_done_queue(p, /*complete*/ FALSE);
-        }
-        cmd->result |= (aic7xxx_error(cmd) << 16);
-        p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-        aic7xxx_done(p, scb);
+       switch (status_byte(scb->hscb->target_status))
+       {
+         case QUEUE_FULL:
+         case BUSY:
+           scb->hscb->target_status = 0;
+            scb->cmd->result = 0;
+            aic7xxx_error(scb->cmd) = DID_OK;
+           break;
+         default:
+            cmd = scb->cmd;
+            if (scb->hscb->residual_SG_segment_count != 0)
+            {
+              aic7xxx_calculate_residual(p, scb);
+            }
+            cmd->result |= (aic7xxx_error(cmd) << 16);
+            p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
+            aic7xxx_done(p, scb);
+       }
       }
       /*
        * Clear interrupt status before checking the output queue again.
@@ -4014,8 +4335,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
     {
       outb(CLRCMDINT, p->base + CLRINT);
     }
-
-    aic7xxx_done_cmds_complete(p);
+    restore_flags(flags);
   }
 
   if (intstat & BRKADRINT)
@@ -4031,32 +4351,39 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
         printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
       }
     }
-    printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
-           inb(p->base + ERROR),
-           (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
-    aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
-    aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+    aic7xxx_reset_channel(p, 'A', TRUE);
+    if ( p->bus_type == AIC_TWIN )
+    {
+      aic7xxx_reset_channel(p, 'B', TRUE);
+      restart_sequencer(p);
+      pause_sequencer(p);
+    }
+    outb(CLRBRKADRINT, p->base + CLRINT);
   }
 
   if (intstat & SEQINT)
   {
+    cli();
     aic7xxx_handle_seqint(p, intstat);
+    restore_flags(flags);
   }
 
   if (intstat & SCSIINT)
   {
+    cli();
     aic7xxx_handle_scsiint(p, intstat);
+    restore_flags(flags);
   }
 
-  if (p->waiting_scbs.head != NULL)
-  {
-    aic7xxx_run_waiting_queues(p);
-  }
-
+  aic7xxx_done_cmds_complete(p);
+  cli();
+  aic7xxx_run_waiting_queues(p);
+  unpause_sequencer(p, TRUE);
   p->flags &= ~IN_ISR;
   restore_flags(flags);
 }
 
+
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_device_queue_depth
@@ -4078,6 +4405,9 @@ static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
   int default_depth = 2;
+  unsigned char tindex;
+
+  tindex = device->id | (device->channel << 3);
 
   device->queue_depth = default_depth;
 #ifdef AIC7XXX_TAGGED_QUEUEING
@@ -4103,9 +4433,9 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
  
     if (!(p->discenable & target_mask))
     {
-      printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+      printk(KERN_INFO "(scsi%d:%d:%d:%d) Disconnection disabled, unable to "
              "enable tagged queueing.\n",
-             p->host_no, device->id, device->channel);
+             p->host_no, device->channel, device->id, device->lun);
     }
     else
     {
@@ -4118,9 +4448,7 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
       }
       else
       {
-        unsigned char  tindex;
 
-        tindex = device->id | (device->channel << 3);
         if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
         {
           tag_enabled = FALSE;
@@ -4141,10 +4469,12 @@ aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
       {
         if (aic7xxx_verbose)
         {
-         printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
+         printk(KERN_INFO "(scsi%d:%d:%d:%d) Enabled tagged queuing, "
                 "queue depth %d.\n", p->host_no,
-                device->id, device->channel, device->queue_depth);
+                device->channel, device->id, device->lun, device->queue_depth);
         }
+        p->device_status[tindex].max_queue_depth = device->queue_depth;
+        p->device_status[tindex].temp_queue_depth = device->queue_depth;
         device->tagged_queue = 1;
         device->current_tag = SCB_LIST_NULL;
       }
@@ -5064,6 +5394,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   }
 
   p->host = host;
+  p->last_reset = 0;
   p->host_no = host->host_no;
   p->isr_count = 0;
   p->next = NULL;
@@ -5078,6 +5409,15 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
     p->device_status[i].flags = 0;
     p->device_status[i].active_cmds = 0;
     p->device_status[i].last_reset = 0;
+    p->device_status[i].last_queue_full = 0;
+    p->device_status[i].last_queue_full_count = 0;
+    p->device_status[i].max_queue_depth = 2;
+    p->device_status[i].temp_queue_depth = 2;
+    scbq_init(&p->device_status[i].delayed_scbs);
+    init_timer(&p->device_status[i].timer);
+    p->device_status[i].timer.expires = 0;
+    p->device_status[i].timer.data = (unsigned long)p;
+    p->device_status[i].timer.function = (void *)aic7xxx_timer;
   }
   if (aic7xxx_boards[p->irq] == NULL)
   {
@@ -5085,7 +5425,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
     int irq_flags = 0;
 
 #ifdef AIC7XXX_OLD_ISR_TYPE
-    irg_flags = SA_INTERRUPT;
+    irq_flags = SA_INTERRUPT;
 #endif
     /*
      * Warning! This must be done before requesting the irq.  It is
@@ -5108,6 +5448,12 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
     {
       result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
                 "aic7xxx", NULL));
+      if (result < 0)
+      {
+        irq_flags = (irq_flags & SA_INTERRUPT) ? 0 : SA_INTERRUPT;
+        result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
+                "aic7xxx", NULL));
+      }
     }
     if (result < 0)
     {
@@ -5365,6 +5711,7 @@ aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
   {
     outb(p->qfullcount, p->base + FIFODEPTH);
     outb(0, p->base + CMDOUTCNT);
+    p->cmdoutcnt = 0;
   }
 
   /*
@@ -5774,7 +6121,7 @@ aic7xxx_detect(Scsi_Host_Template *template)
   int slot, base;
   int chan_num = 0;
   unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
-  int i;
+  int i, print_info=TRUE;
   struct aic7xxx_host *p;
 
   /*
@@ -5818,6 +6165,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
     if (chip_type != AIC_NONE)
     {
 
+      if (print_info)
+      {
+       printk(KERN_INFO 
+"aic7xxx: Driver modifications performed by Doug Ledford, Aug-Nov, 1997\n"
+"aic7xxx: This version is not supported by the official aic7xxx maintainer\n"
+"aic7xxx: Please email problems/questions directly to dledford@dialnet.net\n"
+         );
+       print_info = FALSE;
+      }
       switch (chip_type)
       {
         case AIC_7770:
@@ -5849,7 +6205,6 @@ aic7xxx_detect(Scsi_Host_Template *template)
       else
         hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
       outb(hcntrl | PAUSE, base + HCNTRL);
-
       p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
       if (p == NULL)
       {
@@ -6091,6 +6446,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
           error += pcibios_read_config_dword(pci_bus, pci_device_fn,
                                              CLASS_PROGIF_REVID, &class_revid);
 
+          if (print_info)
+          {
+           printk(KERN_INFO 
+"aic7xxx: Driver modifications performed by Doug Ledford, Aug-Nov, 1997\n"
+"aic7xxx: This version is not supported by the official aic7xxx maintainer\n"
+"aic7xxx: Please email problems/questions directly to dledford@dialnet.net\n"
+             );
+           print_info = FALSE;
+          }
           printk("aic7xxx: <%s> at PCI %d\n",
                  board_names[chip_type], PCI_SLOT(pci_device_fn));
 
@@ -6303,10 +6667,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
     }
   }
 #endif CONFIG_PCI
-
   return (found);
 }
 
+static void
+aic7xxx_fake_scsi_done(Scsi_Cmnd *cmd)
+{
+  kfree(cmd);
+}
+
 
 /*+F*************************************************************************
  * Function:
@@ -6337,7 +6706,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     {
       cmd->tag = hscb->tag;
       p->device_status[TARGET_INDEX(cmd)].commands_sent++;
-      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+      if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 200)
       {
         hscb->control |= MSG_SIMPLE_Q_TAG;
       }
@@ -6349,12 +6718,45 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
     }
 #endif  /* Tagged queueing */
   }
-
   if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
   {
-    p->wdtr_pending |= mask;
-    hscb->control |= MK_MESSAGE;
-    scb->flags |= SCB_MSGOUT_WDTR;
+    if ( cmd->cmnd[0] == TEST_UNIT_READY )
+    {
+      p->wdtr_pending |= mask;
+      hscb->control |= MK_MESSAGE;
+      scb->flags |= SCB_MSGOUT_WDTR;
+    }
+    else
+    {
+      Scsi_Cmnd *cmd2, *cmd3;
+
+      cmd2 = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
+      cmd3 = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
+      if ((cmd2 == NULL) || (cmd3 == NULL))
+        panic("aic7xxx: unable to proceed with device negotiation.\n");
+      memcpy(cmd2, cmd, sizeof(Scsi_Cmnd));
+      memcpy(cmd3, cmd, sizeof(Scsi_Cmnd));
+      memset(&cmd2->cmnd[0], '\0', sizeof(cmd2->cmnd));
+      memset(&cmd3->cmnd[0], '\0', sizeof(cmd3->cmnd));
+      cmd2->cmnd[0] = TEST_UNIT_READY;
+      cmd3->cmnd[0] = TEST_UNIT_READY;
+      cmd2->cmd_len = 6;
+      cmd3->cmd_len = 6;
+      cmd2->bufflen = 0;
+      cmd3->bufflen = 0;
+      cmd2->request_bufflen = 0;
+      cmd3->request_bufflen = 0;
+      cmd2->buffer = NULL;
+      cmd3->buffer = NULL;
+      cmd2->request_buffer = NULL;
+      cmd3->request_buffer = NULL;
+      cmd2->use_sg = 0;
+      cmd3->use_sg = 0;
+      cmd2->underflow = 0;
+      cmd3->underflow = 0;
+      aic7xxx_queue(cmd2, aic7xxx_fake_scsi_done);
+      aic7xxx_queue(cmd3, aic7xxx_fake_scsi_done);
+    }
 #if 0
     printk("scsi%d: Sending WDTR request to target %d.\n",
            p->host_no, cmd->target);
@@ -6364,9 +6766,31 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
   {
     if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
     {
-      p->sdtr_pending |= mask;
-      hscb->control |= MK_MESSAGE;
-      scb->flags |= SCB_MSGOUT_SDTR;
+      if ( cmd->cmnd[0] == TEST_UNIT_READY )
+      {
+        p->sdtr_pending |= mask;
+        hscb->control |= MK_MESSAGE;
+        scb->flags |= SCB_MSGOUT_SDTR;
+      }
+      else
+      {
+        Scsi_Cmnd *cmd2;
+
+        cmd2 = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
+        if (cmd2 == NULL)
+          panic("aic7xxx: unable to proceed with device negotiation.\n");
+        memcpy(cmd2, cmd, sizeof(Scsi_Cmnd));
+        memset(&cmd2->cmnd[0], '\0', sizeof(cmd2->cmnd));
+        cmd2->cmnd[0] = TEST_UNIT_READY;
+        cmd2->cmd_len = 6;
+        cmd2->bufflen = 0;
+        cmd2->request_bufflen = 0;
+        cmd2->buffer = NULL;
+        cmd2->request_buffer = NULL;
+        cmd2->use_sg = 0;
+        cmd2->underflow = 0;
+        aic7xxx_queue(cmd2, aic7xxx_fake_scsi_done);
+      }
 #if 0
       printk("scsi%d: Sending SDTR request to target %d.\n",
              p->host_no, cmd->target);
@@ -6465,13 +6889,9 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
   long processor_flags;
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
+  int tindex = TARGET_INDEX(cmd);
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-  if (p->host != cmd->host)
-  {
-    printk(KERN_INFO "scsi%d: Internal host structure != scsi.c host "
-      "structure.\n", p->host_no);
-  }
 
   /*
    * Check to see if channel was scanned.
@@ -6496,11 +6916,14 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
        cmd->lun & 0x07);
 #endif
 
-  if (p->device_status[TARGET_INDEX(cmd)].active_cmds
-      > cmd->device->queue_depth)
+  if ( (p->device_status[tindex].active_cmds > cmd->device->queue_depth) &&
+      !(p->wdtr_pending & (0x1 << tindex)) && 
+      !(p->sdtr_pending & (0x1 << tindex)) )
   {
-    printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
-           p->host_no, cmd->target, cmd->channel);
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Commands queued exceeds queue "
+          "depth, active=%d\n",
+           p->host_no, CTL_OF_CMD(cmd), 
+          p->device_status[tindex].active_cmds);
   }
   scb = aic7xxx_allocate_scb(p);
   if (scb == NULL)
@@ -6548,13 +6971,20 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 
     save_flags(processor_flags);
     cli();
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
+    if (p->device_status[tindex].delayed_scbs.head != NULL) 
+    {
+        scbq_insert_tail(&p->device_status[tindex].delayed_scbs, scb);
+    }
+    else
+    {
+        scbq_insert_tail(&p->waiting_scbs, scb);
+    }
+    if ((p->flags & (IN_ISR | IN_ABORT | RESET_PENDING)) == 0)
     {
       aic7xxx_run_waiting_queues(p);
     }
-
     restore_flags(processor_flags);
+
 #if 0
     printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
            (long) cmd, (long) scb->cmd, scb->hscb->tag);
@@ -6579,103 +7009,57 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
   struct aic7xxx_scb   *scb;
   struct aic7xxx_hwscb *hscb;
-  unsigned char bus_state;
   int result = -1;
   char channel;
+  unsigned char saved_scbptr, lastphase;
+  unsigned char hscb_index, linked_next;
+  int disconnected;
 
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   hscb = scb->hscb;
 
-  /*
-   * Ensure that the card doesn't do anything behind our back.
-   * Also make sure that we didn't just miss an interrupt that
-   * could affect this abort/reset.
-   */
-  pause_sequencer(p);
-  while (inb(p->base + INTSTAT) & INT_PEND);
-  {
-    aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
-    pause_sequencer(p);
-  } 
-  if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
-  {
-    result = SCSI_RESET_NOT_RUNNING;
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-    return(result);
-  }
-
-
-  printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
-         p->host_no, TC_OF_SCB(scb), scb->flags);
-  bus_state = inb(p->base + LASTPHASE);
-
-  switch (bus_state)
+  lastphase = inb(p->base + LASTPHASE);
+  if (aic7xxx_verbose > 1)
   {
-    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(KERN_WARNING "(scsi%d:%d:%d:%d) Bus Device reset, scb flags 0x%x, ",
+         p->host_no, CTL_OF_SCB(scb), scb->flags);
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        printk("Data-Out phase, ");
+        break;
+      case P_DATAIN:
+        printk("Data-In phase, ");
+        break;
+      case P_COMMAND:
+        printk("Command phase, ");
+        break;
+      case P_MESGOUT:
+        printk("Message-Out phase, ");
+        break;
+      case P_STATUS:
+        printk("Status phase, ");
+        break;
+      case P_MESGIN:
+        printk("Message-In phase, ");
+        break;
+      default:
       /*
        * We're not in a valid phase, so assume we're idle.
        */
-      printk("while idle, LASTPHASE = 0x%x, ", bus_state);
-      break;
-  }
-  printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
+        printk("while idle, LASTPHASE = 0x%x, ", lastphase);
+        break;
+    }
+    printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
          inb(p->base + SCSISIGI),
          inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
          inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+  }
 
   channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
-  /*
-   * Determine our course of action.
-   */
-  if (scb->flags & SCB_ABORT)
-  {
-    /*
-     * Been down this road before; do a full bus reset.
-     */
-    scb->flags |= SCB_RECOVERY_SCB;
-    unpause_sequencer(p, /* unpause_always */ TRUE);
-    result = -1;
-  }
-#if 0
-  else if (hscb->control & TAG_ENB)
-    {
-      /*
-       * We could be starving this command; try sending and ordered tag
-       * command to the target we come from.
-       */
-      scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
-      p->orderedtag = p->orderedtag | 0xFF;
-      result = SCSI_RESET_PENDING;
-      unpause_sequencer(p, /* unpause_always */ TRUE);
-      printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
-             p->host_no);
-    }
-#endif
-  else
-  {
-    unsigned char active_scb_index, saved_scbptr;
-    struct aic7xxx_scb *active_scb;
 
     /*
-     * Send an Abort Message:
+     * Send a Device Reset Message:
      * The target that is holding up the bus may not be the same as
      * the one that triggered this timeout (different commands have
      * different timeout lengths).  Our strategy here is to queue an
@@ -6686,148 +7070,136 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
      * fails, we'll get another timeout a few seconds later which will
      * attempt a bus reset.
      */
-    saved_scbptr = inb(p->base + SCBPTR);
-    active_scb_index = inb(p->base + SCB_TAG);
-    active_scb = p->scb_data->scb_array[active_scb_index];
+  saved_scbptr = inb(p->base + SCBPTR);
+  disconnected = FALSE;
 
-    if (bus_state != P_BUSFREE)
+  if (lastphase != P_BUSFREE)
+  {
+    if (inb(p->base + SCB_TAG) >= p->scb_data->numscbs)
     {
-      if (active_scb_index >= p->scb_data->numscbs)
-      {
         /*
          * Perform a bus reset.
          *
          * XXX - We want to queue an abort for the timedout SCB
          *       instead.
          */
-        result = -1;
-        printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
-               "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
-      }
-      else
+      printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
+      return(SCSI_RESET_ERROR);
+    }
+    if (scb->hscb->tag == inb(p->base + SCB_TAG))
+    { 
+      if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
       {
         /* Send the abort message to the active SCB. */
         outb(1, p->base + MSG_LEN);
-        if (active_scb->hscb->control & TAG_ENB)
-        {
-          outb(MSG_ABORT_TAG, p->base + MSG_OUT);
-        }
-        else
-        {
-          outb(MSG_ABORT, p->base + MSG_OUT);
-        }
-        outb(bus_state | ATNO, p->base + SCSISIGO);
-        printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
-               p->host_no);
-        active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
-        if (active_scb != scb)
-        {
-          /*
-           * 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.
-           */
-          result = SCSI_RESET_PENDING;
-          aic7xxx_error(active_scb->cmd) = DID_RESET;
-        }
-        else
-        {
-          aic7xxx_error(scb->cmd) = DID_RESET;
-          result = SCSI_RESET_PENDING;
-        }
-        unpause_sequencer(p, /* unpause_always */ TRUE);
-      }
-    }
-    else
-    {
-      unsigned char hscb_index, linked_next;
-      int disconnected;
-
-      disconnected = FALSE;
-      hscb_index = aic7xxx_find_scb(p, scb);
-      if (hscb_index == SCB_LIST_NULL)
-      {
-        disconnected = TRUE;
-        linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+        outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
+        outb(lastphase | ATNO, p->base + SCSISIGO);
+       if (aic7xxx_verbose > 1)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Device reset message in "
+               "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+       p->device_status[TARGET_INDEX(scb->cmd)].flags &= 
+               ~DEVICE_SUCCESS;
+       p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
+               BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_PENDING);
       }
       else
       {
-        outb(hscb_index, p->base + SCBPTR);
-        if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
-        {
-          disconnected = TRUE;
-        }
-        linked_next = inb(p->base + SCB_LINKED_NEXT);
+       /* We want to send out the message, but it could screw an already */
+       /* in place and being used message.  Instead, we return an error  */
+       /* to try and start the bus reset phase since this command is     */
+        /* probably hung (aborts failed, and now reset is failing).  We   */
+        /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
+        /* any more on this device, but instead will escalate to a bus or */
+        /* host reset (additionally, we won't try to abort any more).     */
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Device reset, Message buffer "
+               "in use\n", p->host_no, CTL_OF_SCB(scb));
+       scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+        aic7xxx_error(scb->cmd) = DID_RESET;
+       p->device_status[TARGET_INDEX(scb->cmd)].flags &= 
+               ~DEVICE_SUCCESS;
+       p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
+               BUS_DEVICE_RESET_PENDING;
+        return(SCSI_RESET_ERROR);
       }
-      if (disconnected)
-      {
+    }
+  }
+  hscb_index = aic7xxx_find_scb(p, scb);
+  if (hscb_index == SCB_LIST_NULL)
+  {
+    disconnected = TRUE;
+    linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+  }
+  else
+  {
+    outb(hscb_index, p->base + SCBPTR);
+    if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+    {
+      disconnected = TRUE;
+    }
+    linked_next = inb(p->base + SCB_LINKED_NEXT);
+  }
+  if (disconnected)
+  {
         /*
          * Simply set the ABORT_SCB control bit and preserve the
          * linked next pointer.
          */
-        scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
-        scb->hscb->data_count &= ~0xFF000000;
-        scb->hscb->data_count |= linked_next << 24;
-        if ((p->flags & PAGE_ENABLED) == 0)
-        {
-          scb->hscb->control &= ~DISCONNECTED;
-        }
-        scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-        if (hscb_index != SCB_LIST_NULL)
-        {
-          unsigned char scb_control;
+    scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+    scb->hscb->data_count &= ~0xFF000000;
+    scb->hscb->data_count |= linked_next << 24;
+    if ((p->flags & PAGE_ENABLED) == 0)
+    {
+      scb->hscb->control &= ~DISCONNECTED;
+    }
+    scb->flags |= SCB_RESET | SCB_DEVICE_RESET | SCB_QUEUED_ABORT;
+    p->device_status[TARGET_INDEX(scb->cmd)].flags &= ~DEVICE_SUCCESS;
+    p->device_status[TARGET_INDEX(scb->cmd)].flags |= 
+       BUS_DEVICE_RESET_PENDING;
+    if (hscb_index != SCB_LIST_NULL)
+    {
+      unsigned char scb_control;
 
-          scb_control = inb(p->base + SCB_CONTROL);
-          outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
-        }
+      scb_control = inb(p->base + SCB_CONTROL);
+      outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+    }
         /*
          * Actually requeue this SCB in case we can select the
          * device before it reconnects.  If the transaction we
          * want to abort is not tagged, unbusy it first so that
          * we don't get held back from sending the command.
          */
-        if ((scb->hscb->control & TAG_ENB) == 0)
-        {
-          unsigned char target;
-          int lun;
-
-          target = scb->cmd->target;
-          lun = scb->cmd->lun;
-          aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
-              0, /* requeue */ TRUE);
-        }
-        printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
-               p->host_no, TC_OF_SCB(scb));
-        scbq_insert_head(&p->waiting_scbs, scb);
-        scb->flags |= SCB_WAITINGQ;
-        outb(saved_scbptr, p->base + SCBPTR);
-        if ((p->flags & IN_ISR) == 0)
-        {
-          /*
-           * Processing the waiting queue may unpause us.
-           */
-          aic7xxx_run_waiting_queues(p);
-          /*
-           * If we are using AAP, aic7xxx_run_waiting_queues() will not
-           * unpause us, so ensure we are unpaused.
-           */
-          unpause_sequencer(p, /*unpause_always*/ FALSE);
-        }
-        else
-        {
-          unpause_sequencer(p, /*unpause_always*/ TRUE);
-        }
-        result = SCSI_RESET_PENDING;
-      }
-      else
-      {
-        scb->flags |= SCB_RECOVERY_SCB;
-        unpause_sequencer(p, /* unpause_always */ TRUE);
-        result = -1;
-      }
+    if ((scb->hscb->control & TAG_ENB) == 0)
+    {
+      aic7xxx_search_qinfifo(p, cmd->target, channel, cmd->lun, 
+            SCB_LIST_NULL, 0, TRUE, &p->waiting_scbs);
+    }
+    if (aic7xxx_verbose > 1)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Queueing device reset command.\n",
+           p->host_no, CTL_OF_SCB(scb));
+    if ( !(scb->flags & SCB_WAITINGQ) ) /* Make sure we don't already have   */
+    {                                  /* an abort scb queued, or else we   */
+                                       /* corrupt the waiting queue and     */
+                                       /* active_cmds counter by queueing   */
+                                       /* again.                            */
+      scbq_insert_head(&p->waiting_scbs, scb);
+      scb->flags |= SCB_WAITINGQ;
+      p->device_status[TARGET_INDEX(scb->cmd)].active_cmds--;
+    }
+    else
+    {
+      scb->flags &= ~SCB_ABORT;
     }
+    result = SCSI_RESET_PENDING;
+  }
+  else if (result == -1)
+  {
+    result = SCSI_RESET_ERROR;
   }
+  outb(saved_scbptr, p->base + SCBPTR);
   return (result);
 }
 
@@ -6842,115 +7214,297 @@ aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 int
 aic7xxx_abort(Scsi_Cmnd *cmd)
 {
-#if 0
   struct aic7xxx_scb  *scb = NULL;
-#endif
   struct aic7xxx_host *p;
-#if 0
-  int    base, result;
+  int    result, found=0;
+  unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
   unsigned long processor_flags;
-#endif
+  Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
-#if 0
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
 
   save_flags(processor_flags);
+  pause_sequencer(p);
   cli();
-#endif
 
-#if 1
-  switch (aic7xxx_reset(cmd, 0) & 0x0f)
-  {
-    case SCSI_RESET_SNOOZE:
-      return(SCSI_ABORT_SNOOZE);
-    case SCSI_RESET_PENDING:
-      return(SCSI_ABORT_PENDING);
-    case SCSI_RESET_SUCCESS:
-      return(SCSI_ABORT_SUCCESS);
-    case SCSI_RESET_NOT_RUNNING:
-      return(SCSI_ABORT_NOT_RUNNING);
-    case SCSI_RESET_ERROR:
-      return(SCSI_ABORT_ERROR);
-    default:
-      printk(KERN_WARNING "scsi%d Unknown abort/reset return state.\n",
-        p->host_no);
-      return(SCSI_ABORT_ERROR);
-  }  /*  NOT REACHED */
-#else
+/*
+ *  Run the isr to grab any command in the QOUTFIFO and any other misc.
+ *  assundry tasks.  This should also set up the bh handler if there is
+ *  anything to be done, but it won't run until we are done here since
+ *  we are following a straight code path without entering the scheduler
+ *  code.
+ */
 
-#ifdef AIC7XXX_DEBUG_ABORT
-  if (scb != NULL)
+  while ( (inb(p->base + INTSTAT) & INT_PEND) && !(p->flags & IN_ISR) )
   {
-    printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL);
+    pause_sequencer(p);
   }
-  else
+
+  if (scb == NULL)    /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range.  The suspect scb hasn't been */
+                      /*  allocated yet.                                */
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called with bogus Scsi_Cmnd->"
+       "SCB mapping.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, TRUE);
+    restore_flags(processor_flags);
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
+  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
+                        /*  has already been recycled for another command   */
+                        /*  Either way, this SCB has nothing to do with this*/
+                        /*  command and we need to deal with cmd without    */
+                        /*  touching the SCB.                               */
+                        /*  The theory here is to return a value that will  */
+                        /*  make the queued for complete command actually   */
+                        /*  finish successfully, or to indicate that we     */
+                        /*  don't have this cmd any more and the mid level  */
+                        /*  code needs to find it.                          */
+    cmd_next = p->completeq.head;
+    cmd_prev = NULL;
+    while (cmd_next != NULL) 
+    {
+      if (cmd_next == cmd) 
+      {
+       if (aic7xxx_verbose > 1)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called for command "
+         "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+       if ( cmd_prev == NULL )
+         p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+       else
+         cmd_prev->host_scribble = cmd_next->host_scribble;
+       cmd_next->done(cmd_next);
+        unpause_sequencer(p, TRUE);
+       restore_flags(processor_flags);
+       return(SCSI_ABORT_SUCCESS);
+      }                                  
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Abort called for already completed"
+       " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    unpause_sequencer(p, TRUE);
+    restore_flags(processor_flags);
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+    
+/*   At this point we know the following:
+ *     the SCB pointer is valid
+ *     the command pointer passed in to us and the scb->cmd pointer match
+ *     this then means that the command we need to abort is the same as the
+ *     command held by the scb pointer and is a valid abort request.
+ *   Now, we just have to figure out what to do from here.  Current plan is:
+ *     if we have already been here on this command, escalate to a reset
+ *     if scb is on waiting list or QINFIFO, send it back as aborted
+ *     if scb is on WAITING_SCB list in sequencer, free scb and send back
+ *     if scb is disconnected and not completed, abort with abort message
+ *     if scb is currently running, then it may be causing the bus to hang
+ *       so we want a return value that indicates a reset would be appropriate
+ *       if the command does not finish shortly
+ *     if scb is already complete but not on completeq, we're screwed because
+ *       this can't happen (except if the command is in the QOUTFIFO, in which
+ *       case we would like it to complete successfully instead of having to
+ *       to be re-done)
+ *   All other scenarios already dealt with by previous code.
+ */
+
+  if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
   {
-    printk("aic7xxx: Abort called with no SCB for cmd.\n");
+    if (aic7xxx_verbose > 2)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB aborted once already, "
+       "escalating.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, TRUE);
+    restore_flags(processor_flags);
+    return(SCSI_ABORT_SNOOZE);
   }
-#endif
+  if ( (p->flags & (RESET_PENDING | ABORT_PENDING)) || 
+          (p->device_status[TARGET_INDEX(scb->cmd)].flags & 
+           BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose > 2)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset/Abort pending for this "
+       "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
+    unpause_sequencer(p, TRUE);
+    restore_flags(processor_flags);
+    return(SCSI_ABORT_PENDING);
+  }
+
+  found = 0;
+  p->flags |= IN_ABORT;
+  if (aic7xxx_verbose)
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+
+/*
+ *   First, let's check to see if the currently running command is our target
+ *    since if it is, the return is fairly easy and quick since we don't want
+ *    to touch the command in case it might complete, but we do want a timeout
+ *    in case it's actually hung, so we really do nothing, but tell the mid
+ *    level code to reset the timeout.
+ */
 
-  if (p->flags & IN_TIMEOUT)
+  if ( scb->hscb->tag == inb(p->base + SCB_TAG) )
   {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
-    {
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_PENDING);
-    }
-    else
+   /*
+    *  Check to see if the sequencer is just sitting on this command, or
+    *   if it's actively being run.
+    */
+    result = inb(p->base + LASTPHASE);
+    switch (result)
     {
-      /*
-       * This is the second time we've tried to abort the recovery
-       * SCB.  We want the mid-level SCSI code to call the reset
-       * function to reset the SCSI bus.
-       */
-      restore_flags(processor_flags);
-      return (SCSI_ABORT_NOT_RUNNING);
+      case P_DATAOUT:    /*    For any of these cases, we can assume we are */
+      case P_DATAIN:     /*    an active command and act according.  For    */
+      case P_COMMAND:    /*    anything else we are going to fall on through*/
+      case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
+      case P_MESGOUT:    /*    chances to finish and then escalate to a     */
+      case P_MESGIN:     /*    reset call                                   */
+       if (aic7xxx_verbose > 1)
+         printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB is currently active.  "
+               "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, TRUE);
+       p->flags &= ~IN_ABORT;
+       scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
+       p->flags |= ABORT_PENDING;      /*  here so we will know not to    */
+        restore_flags(processor_flags); /*  muck with other SCBs if this   */
+        return(SCSI_ABORT_PENDING);      /*  one doesn't complete and clear */
+        break;                          /*  out.                           */
+      default:
+        break;
     }
   }
-  if (cmd->serial_number != cmd->serial_number_at_timeout)
+
+  if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+      int tindex = TARGET_INDEX(cmd);
+     
+      if (aic7xxx_verbose > 1) 
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found on waiting list and "
+           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      scbq_remove(&p->waiting_scbs, scb);
+      scbq_remove(&p->device_status[tindex].delayed_scbs, scb);
+      p->device_status[tindex].active_cmds++;
+      scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+      scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+      found = 1;
   }
-  else if (scb == NULL)
+
+/*
+ *  We just checked the waiting_q, now for the QINFIFO
+ */
+  if ( found == 0 )
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+    if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
+                     INT_TO_CHAN(cmd->channel),
+                    cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                    FALSE, NULL)) != 0) && (aic7xxx_verbose > 1))
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found in QINFIFO and "
+        "aborted.\n", p->host_no, CTL_OF_SCB(scb));
   }
-  else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
+
+/*
+ *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
+ */
+
+  if ( found == 0 )
   {
-    result = SCSI_ABORT_NOT_RUNNING;
+    unsigned char scb_next_ptr;
+    prev_hscbptr = SCB_LIST_NULL;
+    saved_hscbptr = inb(p->base + SCBPTR);
+    next_hscbptr = inb(p->base + WAITING_SCBH);
+    while ( next_hscbptr != SCB_LIST_NULL )
+    {
+      outb( next_hscbptr, p->base + SCBPTR );
+      if ( scb->hscb->tag == inb(p->base + SCB_TAG) )
+      {
+        found = 1;
+       if (aic7xxx_verbose > 1)
+          printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB found on hardware waiting"
+           " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+       if ( prev_hscbptr == SCB_LIST_NULL )
+           outb(inb(p->base + SCB_NEXT), p->base + WAITING_SCBH);
+       else
+       {
+           scb_next_ptr = inb(p->base + SCB_NEXT);
+           outb(prev_hscbptr, p->base + SCBPTR);
+           outb(scb_next_ptr, p->base + SCB_NEXT);
+           outb(next_hscbptr, p->base + SCBPTR);
+       }
+       outb(SCB_LIST_NULL, p->base + SCB_TAG);
+       aic7xxx_add_curscb_to_free_list(p);
+       scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+        break;
+      }
+      prev_hscbptr = next_hscbptr;
+      next_hscbptr = inb(p->base + SCB_NEXT);
+    }
+    outb( saved_hscbptr, p->base + SCBPTR );
   }
-  else
+        
+/*
+ *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
+ *  OK...the sequencer's paused, interrupts are off, and we haven't found the
+ *  command anyplace where it could be easily aborted.  Time for the hard
+ *  work.  We also know the command is valid.  This essentially means the
+ *  command is disconnected, or connected but not into any phases yet, which
+ *  we know due to the tests we ran earlier on the current active scb phase.
+ *  At this point we can queue the abort tag and go on with life.
+ */
+
+  if ( found == 0 )
   {
-    /*
-     * XXX - Check use of IN_TIMEOUT to see if we're Doing the
-     *       Right Thing with it.
-     */
-    p->flags |= IN_TIMEOUT;
-    result = aic7xxx_bus_device_reset(p, scb->cmd);
-    switch (result)
+    p->flags |= ABORT_PENDING;
+    scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+    scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+    result=aic7xxx_find_scb(p, scb);
+    if ( result != SCB_LIST_NULL ) 
     {
-      case SCSI_RESET_NOT_RUNNING:
-        p->flags &= ~IN_TIMEOUT;
-        result = SCSI_ABORT_NOT_RUNNING;
-        break;
-      case SCSI_RESET_PENDING:
-        result = SCSI_ABORT_PENDING;
-        break;
-      default:
-        p->flags &= ~IN_TIMEOUT;
-        result = SCSI_ABORT_SNOOZE;
-        break;
-     }
+      saved_hscbptr = inb(p->base + SCBPTR);
+      outb(result, p->base + SCBPTR);
+      tmp_char = inb(p->base + SCB_CONTROL);
+      outb( tmp_char | MK_MESSAGE | ABORT_SCB, p->base + SCB_CONTROL);
+      outb(saved_hscbptr, p->base + SCBPTR);
+    }
+    if (aic7xxx_verbose > 1)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) SCB disconnected.  Queueing Abort"
+        " SCB.\n", p->host_no, CTL_OF_SCB(scb));
+    if ( (scb->hscb->control & TAG_ENB) == 0 )
+    {
+      aic7xxx_search_qinfifo(p, cmd->target, INT_TO_CHAN(cmd->channel),
+       cmd->lun, SCB_LIST_NULL, 0, TRUE, &p->waiting_scbs);
+    }
+    if ( !(scb->flags & SCB_WAITINGQ) )
+    {
+      scbq_insert_head(&p->waiting_scbs, scb);
+      scb->flags |= SCB_WAITINGQ;
+      p->device_status[TARGET_INDEX(scb->cmd)].active_cmds--;
+    }
   }
+  else
+  { 
+    scb->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+  }
+  aic7xxx_run_done_queue(p, TRUE);
+  aic7xxx_run_waiting_queues(p);
+  p->flags &= ~IN_ABORT;
   restore_flags(processor_flags);
-  return (result);
-#endif
+
+/*
+ *  On the return value.  If we found the command and aborted it, then we know
+ *  it's already sent back and there is no reason for a further timeout, so
+ *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
+ *  there hasn't been a bus hang or something that might keep the abort from
+ *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time this
+ *  is passed back, the timeout on the command gets extended, the second time
+ *  we pass this back, the mid level SCSI code calls our reset function, which
+ *  would shake loose a hung bus.
+ */
+  if ( found != 0 )
+    return(SCSI_ABORT_SUCCESS);
+  else
+    return(SCSI_ABORT_PENDING); 
 }
 
 
@@ -6969,189 +7523,225 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
 {
   struct aic7xxx_scb *scb = NULL;
   struct aic7xxx_host *p;
-  int    base, found, tindex, min_target, max_target;
+  int    tindex;
   int    result = -1;
   char   channel = 'A';
   unsigned long processor_flags;
+#define        DEVICE_RESET 0x01
+#define BUS_RESET    0x02
+#define HOST_RESET   0x04
+#define FAIL         0x08
+#define        RESET_DELAY  0x10
+  int  action;
+  Scsi_Cmnd *cmd_prev, *cmd_next;
 
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
-  base = p->base;
-  channel = cmd->channel ? 'B': 'A';
-  tindex = TARGET_INDEX(cmd);
 
-#ifdef 0   /* AIC7XXX_DEBUG_ABORT */
-  if (scb != NULL)
+  if ( cmd == NULL )
   {
-    printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
-           p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if (aic7xxx_verbose > 1)
+      printk(KERN_WARNING "(aic7xxx) Reset called with NULL Scsi_Cmnd "
+       "pointer, failing.\n");
+    return(SCSI_RESET_SNOOZE);
   }
-  else
-  {
-    printk("aic7xxx: Reset called with no SCB for cmd.\n");
-  }
-#endif
 
-  /* 
-   * This routine is called by scsi.c, in which case the interrupts
-   * very well may be on when we are called.  As such, we need to save
-   * the flags to be sure, then turn interrupts off, and then call our
-   * various method funtions which all assume interrupts are off.
-   */
+  p = (struct aic7xxx_host *) cmd->host->hostdata;
+  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  channel = INT_TO_CHAN(cmd->channel);
+  tindex = TARGET_INDEX(cmd);
+
   save_flags(processor_flags);
+  pause_sequencer(p);
   cli();
+  while ( (inb(p->base + INTSTAT) & INT_PEND) && !(p->flags & IN_ISR) )
+  {
+    aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL );
+    pause_sequencer(p);
+  }
 
-  if (scb->cmd != cmd)
-    scb = NULL;
-
-  if (p->flags & IN_TIMEOUT)
+  if (scb == NULL)
   {
-    /*
-     * We've already started a recovery operation.
-     */
-    if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+    if (aic7xxx_verbose)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called with bogus Scsi_Cmnd"
+          "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
-      restore_flags(processor_flags);
-      return (SCSI_RESET_PENDING);
+      action = HOST_RESET;
+    }
+    else
+    {
+      action = BUS_RESET;
     }
   }
-  else
+  else if (scb->cmd != cmd) 
   {
-    if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
-        && (scb != NULL))
+    if (aic7xxx_verbose > 1)
+    printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called with recycled SCB "
+       "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    cmd_prev = NULL;
+    cmd_next = p->completeq.head;
+    while ( cmd_next != NULL )
     {
-      /*
-       * 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_next == cmd)
       {
-       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->flags & SCB_ABORTED)
-          {
-            result = SCSI_RESET_PENDING;
-          }
-          else if (!(scb->flags & SCB_ACTIVE))
-          {
-            result = SCSI_RESET_NOT_RUNNING;
-          }
-        }
-
-        if (result == -1)
-        {
-          if ((flags & SCSI_RESET_SYNCHRONOUS) &&
-              (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
-          {
-            scb->flags |= SCB_ABORTED;
-            result = SCSI_RESET_PENDING;
-          }
-          else
-          {
-            p->flags |= IN_TIMEOUT;
-            result = aic7xxx_bus_device_reset(p, cmd);
-            if (result == 0)
-            {
-              p->flags &= ~IN_TIMEOUT;
-              result = SCSI_RESET_PENDING;
-            }
-          }
-       }
+       if (aic7xxx_verbose > 1)
+         printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset, found cmd on completeq"
+         ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+       if ( cmd_prev == NULL )
+         p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+       else
+         cmd_prev->host_scribble = cmd_next->host_scribble;
+       cmd_next->done(cmd_next);
+       unpause_sequencer(p, TRUE);
+       restore_flags(processor_flags);
+       return(SCSI_RESET_SUCCESS);
       }
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
+    {
+      if (aic7xxx_verbose)
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset, cmd not found,"
+         " failing.\n", p->host_no, CTL_OF_CMD(cmd));
+      unpause_sequencer(p, TRUE);
+      restore_flags(processor_flags);
+      return(SCSI_RESET_NOT_RUNNING);
+    }
+    else
+    {
+      if (aic7xxx_verbose)
+        printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called, no scb, "
+          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
+      scb = NULL;
+      action = HOST_RESET;
     }
   }
-  if (result == -1)
+  else
   {
-    /*
-     * The bus device reset failed; try resetting the channel.
-     */
-    if (!(flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
-        && (flags & SCSI_RESET_ASYNCHRONOUS))
+    if (aic7xxx_verbose)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called, scb %d, flags "
+        "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
-      if (scb == NULL)
-      {
-       result = SCSI_RESET_NOT_RUNNING;
-      }
-      else if (!(scb->flags & SCB_ACTIVE))
-      {
-       result = SCSI_RESET_NOT_RUNNING;
-      }
-      else if ((scb->flags & SCB_ABORTED) &&
-               (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
-      {
-       result = SCSI_RESET_PENDING;
-      }
+      action = HOST_RESET;
     }
-
-    if (result == -1)
+    else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
     {
-      /*
-       * The reset channel function assumes that the sequencer is paused.
-       */
-      pause_sequencer(p);
-      found = aic7xxx_reset_channel(p, channel, TRUE);
-      p->flags = p->flags & ~IN_TIMEOUT;
-
-      /*
-       * If this is a synchronous reset and there is no SCB for this
-       * command, perform completion processing.
-       *
-       */
-      if ((flags & SCSI_RESET_SYNCHRONOUS) && (scb == NULL))
+      action = BUS_RESET;
+    }
+    else 
+    {
+      action = DEVICE_RESET;
+    }
+  }
+  if ( ((jiffies - p->last_reset) < (HZ * AIC7XXX_RESET_DELAY)) &&
+    (action & (HOST_RESET | BUS_RESET | DEVICE_RESET)) )
+  {
+    if (aic7xxx_verbose > 1)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called too soon after "
+       "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = RESET_DELAY;
+  }
+  if ( ((jiffies - p->device_status[tindex].last_reset) < 
+       (HZ * AIC7XXX_RESET_DELAY)) && !(action & (HOST_RESET | BUS_RESET)))
+  {
+    if (aic7xxx_verbose > 1)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Reset called too soon after last "
+       "reset without requesting\n"
+       "(scsi%d:%d:%d:%d) bus or host reset, escalating.\n", p->host_no,
+       CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) && 
+       (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING) )
+  {
+    if (aic7xxx_verbose > 2)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset already sent to "
+       "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) &&
+       (scb->flags & SCB_QUEUED_ABORT) )
+  {
+    if (aic7xxx_verbose > 2)
+      printk(KERN_WARNING "(scsi%d:%d:%d:%d) Have already attempted to reach "
+       "device with queued\n(scsi%d:%d:%d:%d) message, will escalate to bus "
+       "reset.\n", p->host_no, CTL_OF_CMD(cmd), p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & DEVICE_RESET) && (p->flags & (RESET_PENDING | ABORT_PENDING)) )
+  {
+    if (aic7xxx_verbose > 2)
+     printk(KERN_WARNING "(scsi%d:%d:%d:%d) Bus device reset stupid when "
+       "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
+    action = BUS_RESET;
+  }
+  if ( (action & BUS_RESET) && (p->bus_type != AIC_TWIN) )
+  {
+    action = HOST_RESET;
+  }
+  if ( (action & (BUS_RESET | HOST_RESET)) && (p->flags & RESET_PENDING)
+       && ((jiffies - p->reset_start) > (2 * HZ * AIC7XXX_RESET_DELAY)) )
+  {
+    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));
+    restore_flags(processor_flags);
+    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.
+ */
+  switch (action)
+  {
+    case RESET_DELAY:
+      return(SCSI_RESET_PENDING);
+      break;
+    case FAIL:
+      return(SCSI_RESET_ERROR);
+      break;
+    case DEVICE_RESET:
+      p->flags |= RESET_PENDING;
+      result = aic7xxx_bus_device_reset(p, cmd);
+      aic7xxx_run_done_queue(p, TRUE);
+      aic7xxx_run_waiting_queues(p);
+      p->flags &= ~RESET_PENDING;
+      restore_flags(processor_flags);
+      return(result);
+      break;
+    case BUS_RESET:
+    case HOST_RESET:
+    default:
+      p->reset_start = jiffies;
+      p->flags |= RESET_PENDING;
+      aic7xxx_reset_channel(p, channel, TRUE);
+      if ( (p->bus_type == AIC_TWIN) && (action & HOST_RESET) )
       {
-       cmd->result = DID_RESET << 16;
-       cmd->scsi_done(cmd);
+        aic7xxx_reset_channel(p, (channel == 'A') ? 'B' : 'A', TRUE);
+        restart_sequencer(p);
+       pause_sequencer(p);
       }
-
-      switch (p->bus_type)
+      if (scb == NULL)
       {
-       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;
+       cmd->result = DID_RESET << 16;
+        cmd->done(cmd);
       }
-
-      for (tindex = min_target; tindex <= max_target; tindex++)
+      p->last_reset = jiffies;
+      if (action != HOST_RESET)
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+      else
       {
-       p->device_status[tindex].last_reset = jiffies;
+        result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+        while (inb(p->base + QOUTCNT)) inb(p->base + QOUTFIFO);
+        if (p->flags & PAGE_ENABLED) outb(0, p->base + CMDOUTCNT);
+        aic7xxx_clear_intstat(p);
       }
-
-      result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-      p->flags &= ~IN_TIMEOUT;
-    }
+      p->flags &= ~RESET_PENDING;
+      aic7xxx_run_waiting_queues(p);
+      restore_flags(processor_flags);
+      return(result);
+      break;
   }
-  aic7xxx_run_waiting_queues(p);
-  restore_flags(processor_flags);
-  return (result);
 }
 
 /*+F*************************************************************************
index 3a1effc968df675e0d7f9301d425a4a905795de4..074f4d2bc1a626cb2ee72cf376d9eb5f8e547865 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _aic7xxx_h
 #define _aic7xxx_h
 
-#define AIC7XXX_H_VERSION  "$Revision: 3.2 $"
+#define AIC7XXX_H_VERSION  "$Revision: 3.2.1 $"
 
 /*
  * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
@@ -57,8 +57,8 @@ extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
 extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
 extern int aic7xxx_detect(Scsi_Host_Template *);
 extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_abort(Scsi_Cmnd *);
 extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
+extern int aic7xxx_abort(Scsi_Cmnd *);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
 
index 201a99c0e0469853d7a7c431f553a7df6f3adc45..9966646e83326e6ac549c95d6f6649d90bda8306 100644 (file)
@@ -1121,15 +1121,10 @@ return_error:
 dequeue_disc_scb:
        mov     SCBPTR, DISCONNECTED_SCBH;
 /*
- * If we have a residual, then we are in the middle of some I/O
- * and we have to send this SCB back up to the kernel so that the
- * saved data pointers and residual information isn't lost.
+ * Whenever we are going to dequeue a disconnected SCB and wipe it out
+ * with a new SCB, we always send the SCB back to the kernel to make sure
+ * any residual info and any save/restore pointers are saved for later use..
  */
-       test    SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
-       and     SCB_CONTROL, ~MUST_DMAUP_SCB;
-       jmp     dma_up_scb;
-       test    SCB_RESID_SGCNT,0xff    jnz dma_up_scb;
-       cmp     SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
 dma_up_scb:
        mvi     DMAPARAMS, FIFORESET;
        mov     SCB_TAG         call dma_scb;
index 855a204411ac09c97b48c236acb883f14e5f866f..92b5afa54e9019eab515cfac99de4f08e8513b86 100644 (file)
 #define                ACTNEGEN                0x02
 #define                STPWEN                  0x01
 
-#define        SCSISIGI                        0x03
-#define                ATNI                    0x10
-#define                SELI                    0x08
-#define                BSYI                    0x04
-#define                REQI                    0x02
-#define                ACKI                    0x01
-
 #define        SCSISIGO                        0x03
 #define                CDO                     0x80
 #define                IOO                     0x40
 #define                REQO                    0x02
 #define                ACKO                    0x01
 
+#define        SCSISIGI                        0x03
+#define                ATNI                    0x10
+#define                SELI                    0x08
+#define                BSYI                    0x04
+#define                REQI                    0x02
+#define                ACKI                    0x01
+
 #define        SCSIRATE                        0x04
 #define                WIDEXFER                0x80
 #define                SXFR                    0x70
 
 #define        CMDOUTCNT                       0x5a
 
+#define        FIFODEPTH                       0x5b
+
 #define        SCSICONF2                       0x5b
 #define                RESET_SCSI              0x40
 
-#define        FIFODEPTH                       0x5b
-
 #define        HOSTCONF                        0x5d
 
 #define        HA_274_BIOSCTRL                 0x5f
-#define                BIOSDISABLED            0x30
 #define                BIOSMODE                0x30
+#define                BIOSDISABLED            0x30
 #define                CHANNEL_B_PRIMARY       0x08
 
 #define        SEQCTL                          0x60
 
 #define        STACK                           0x6f
 
+#define        BCTL                            0x84
+#define                ACE                     0x08
+#define                ENABLE                  0x01
+
 #define        DSCOMMAND                       0x84
 #define                CACHETHEN               0x80
 #define                DPARCKEN                0x40
 #define                MPARCKEN                0x20
 #define                EXTREQLCK               0x10
 
-#define        BCTL                            0x84
-#define                ACE                     0x08
-#define                ENABLE                  0x01
-
 #define        BUSTIME                         0x85
 #define                BOFF                    0xf0
 #define                BON                     0x0f
 #define                BAD_PHASE               0x01
 #define                SEQINT                  0x01
 
-#define        ERROR                           0x92
-#define                PARERR                  0x08
-#define                ILLOPCODE               0x04
-#define                ILLSADDR                0x02
-#define                ILLHADDR                0x01
-
 #define        CLRINT                          0x92
 #define                CLRBRKADRINT            0x08
 #define                CLRSCSIINT              0x04
 #define                CLRCMDINT               0x02
 #define                CLRSEQINT               0x01
 
+#define        ERROR                           0x92
+#define                PARERR                  0x08
+#define                ILLOPCODE               0x04
+#define                ILLSADDR                0x02
+#define                ILLHADDR                0x01
+
 #define        DFCNTRL                         0x93
 
 #define        DFSTATUS                        0x94
 
 #define        QOUTCNT                         0x9e
 
-#define        SCB_BASE                        0xa0
-
 #define        SCB_CONTROL                     0xa0
 #define                MK_MESSAGE              0x80
 #define                DISCENB                 0x40
 #define                DISCONNECTED            0x04
 #define                SCB_TAG_TYPE            0x03
 
+#define        SCB_BASE                        0xa0
+
 #define        SCB_TCL                         0xa1
 #define                TID                     0xf0
 #define                SELBUSB                 0x08
 #define                DI_2840                 0x01
 
 
-#define        MAX_OFFSET_16BIT        0x08
 #define        BUS_8_BIT       0x00
+#define        MAX_OFFSET_8BIT 0x0f
+#define        BUS_16_BIT      0x01
+#define        MAX_OFFSET_16BIT        0x08
 #define        SCB_LIST_NULL   0xff
 #define        SG_SIZEOF       0x08
-#define        MAX_OFFSET_8BIT 0x0f
 #define        BUS_32_BIT      0x02
-#define        BUS_16_BIT      0x01
index 78359fb4e90d97ee73ff87c7f654a1f5ab798980..dc07e2a98ff3d9b9871b82733760bf5f25117983 100644 (file)
@@ -34,7 +34,7 @@ static u_int8_t seqprog[] = {
        0xff, 0x65, 0x1f, 0x18,
        0x51, 0x6a, 0x91, 0x00,
        0xff, 0x58, 0xb3, 0x02,
-       0x00, 0x65, 0xbb, 0x17,
+       0x00, 0x65, 0xb6, 0x17,
        0x10, 0x6a, 0x60, 0x00,
        0x00, 0x65, 0x03, 0x10,
        0xff, 0x59, 0x90, 0x02,
@@ -260,7 +260,7 @@ static u_int8_t seqprog[] = {
        0x10, 0x4c, 0x03, 0x00,
        0x00, 0x65, 0xcf, 0x10,
        0x04, 0xa0, 0xa0, 0x00,
-       0x00, 0x65, 0xbb, 0x17,
+       0x00, 0x65, 0xb6, 0x17,
        0x00, 0x65, 0x69, 0x10,
        0x10, 0x41, 0xcf, 0x1e,
        0xff, 0x43, 0xa3, 0x02,
@@ -431,15 +431,10 @@ static u_int8_t seqprog[] = {
        0xff, 0x53, 0xba, 0x02,
        0xff, 0x6a, 0xb9, 0x00,
        0xff, 0x90, 0x53, 0x03,
-       0xff, 0x53, 0xb9, 0x19,
+       0xff, 0x53, 0xb4, 0x19,
        0xff, 0x52, 0xb0, 0x19,
        0xff, 0x6a, 0x65, 0x01,
        0xff, 0x52, 0x90, 0x02,
-       0x10, 0xa0, 0xb4, 0x1f,
-       0xef, 0xa0, 0xa0, 0x02,
-       0x00, 0x65, 0xb6, 0x11,
-       0xff, 0xa8, 0xb6, 0x1b,
-       0xff, 0xb3, 0xb8, 0x1d,
        0x01, 0x6a, 0x3d, 0x00,
        0x00, 0xb9, 0x77, 0x17,
        0x00, 0x90, 0x61, 0x11,
@@ -478,6 +473,6 @@ struct patch {
        { 0x00000004, 0, 0x128, 0x12a },
        { 0x00000004, 0, 0x152, 0x16c },
        { 0x00000004, 1, 0x16c, 0x16d },
-       { 0x00000004, 0, 0x1ad, 0x1c2 },
+       { 0x00000004, 0, 0x1ad, 0x1bd },
        { 0x00000000, 0, 0x000, 0x000 }
 };
index 4939e05de77eedd31a2a155bb544f0dc62bd2906..ed101ec0241cd46f9ac97951bd24812da3f42892 100644 (file)
@@ -601,6 +601,8 @@ static void put_unused_buffer_head(struct buffer_head * bh)
        nr_unused_buffer_heads++;
        bh->b_next_free = unused_list;
        unused_list = bh;
+       if (!waitqueue_active(&buffer_wait))
+               return;
        wake_up(&buffer_wait);
 }
 
@@ -983,6 +985,7 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
 
 static void get_more_buffer_heads(void)
 {
+       struct wait_queue wait = { current, NULL };
        struct buffer_head * bh;
 
        while (!unused_list) {
@@ -1011,11 +1014,18 @@ static void get_more_buffer_heads(void)
                 * finishing IO..
                 */
                run_task_queue(&tq_disk);
-               sleep_on(&buffer_wait);
+
                /*
-                * After we wake up, check for released async buffer heads.
+                * Set our state for sleeping, then check again for buffer heads.
+                * This ensures we won't miss a wake_up from an interrupt.
                 */
+               add_wait_queue(&buffer_wait, &wait);
+               current->state = TASK_UNINTERRUPTIBLE;
+               if (!unused_list && !reuse_list)
+                       schedule();
                recover_reusable_buffer_heads();
+               remove_wait_queue(&buffer_wait, &wait);
+               current->state = TASK_RUNNING;
        }
 
 }
@@ -1192,13 +1202,13 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
                 * and unlock_buffer(). */
        } else {
                unsigned long flags;
-               clear_bit(PG_locked, &page->flags);
-               set_bit(PG_uptodate, &page->flags);
-               wake_up(&page->wait);
                save_flags(flags);
                cli();
                free_async_buffers(bh);
                restore_flags(flags);
+               clear_bit(PG_locked, &page->flags);
+               set_bit(PG_uptodate, &page->flags);
+               wake_up(&page->wait);
                after_unlock_page(page);
                if (waitqueue_active(&buffer_wait))
                        wake_up(&buffer_wait);
index db4f181ac604d509cf836cab4831773f61fb4bcd..f7dd51ddc5811b5ce24fe56a67630ad81f73762d 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -397,7 +397,12 @@ static int exec_mmap(void)
 
                old_mm = current->mm;
                current->mm = mm;
-               new_page_tables(current);
+               if (new_page_tables(current)) {
+                       current->mm = old_mm;
+                       exit_mmap(mm);
+                       kfree(mm);
+                       return -ENOMEM;
+               }
 
                if ((old_mm != &init_mm) && (!--old_mm->count)) {
                        /*
index 357d309fa23c158a8802e07e21d83329454599e7..a075e92bd7ed48a4e909a711db06f26931e23290 100644 (file)
@@ -38,7 +38,7 @@ extern __inline__ void prim_spin_lock(struct spinlock *sp)
                         *      Wait for any invalidates to go off
                         */
                         
-                       if(smp_invalidate_needed&(1<<processor));
+                       if(smp_invalidate_needed&(1<<processor))
                                while(lock_clear_bit(processor,&smp_invalidate_needed))
                                        local_flush_tlb();
                        sp->spins++;
index 2aae0b9927d41f4fb26cecae359e491b55f5bb50..99552fc1771157db4a6b7b98ad86ae0f72f941f1 100644 (file)
@@ -28,6 +28,7 @@ int getrusage(struct task_struct *, int, struct rusage *);
 
 static inline void generate(unsigned long sig, struct task_struct * p)
 {
+       unsigned long flags;
        unsigned long mask = 1 << (sig-1);
        struct sigaction * sa = sig + p->sig->action - 1;
 
@@ -36,18 +37,24 @@ static inline void generate(unsigned long sig, struct task_struct * p)
         * be handled immediately (ie non-blocked and untraced)
         * and that is ignored (either explicitly or by default)
         */
+       save_flags(flags); cli();
        if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
                /* don't bother with ignored signals (but SIGCHLD is special) */
-               if (sa->sa_handler == SIG_IGN && sig != SIGCHLD)
+               if (sa->sa_handler == SIG_IGN && sig != SIGCHLD) {
+                       restore_flags(flags);
                        return;
+               }
                /* some signals are ignored by default.. (but SIGCONT already did its deed) */
                if ((sa->sa_handler == SIG_DFL) &&
-                   (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG))
+                   (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG)) {
+                       restore_flags(flags);
                        return;
+               }
        }
        p->signal |= mask;
        if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
                wake_up_process(p);
+       restore_flags(flags);
 }
 
 /*
@@ -58,20 +65,26 @@ void force_sig(unsigned long sig, struct task_struct * p)
 {
        sig--;
        if (p->sig) {
+               unsigned long flags;
                unsigned long mask = 1UL << sig;
                struct sigaction *sa = p->sig->action + sig;
+
+               save_flags(flags); cli();
                p->signal |= mask;
                p->blocked &= ~mask;
                if (sa->sa_handler == SIG_IGN)
                        sa->sa_handler = SIG_DFL;
                if (p->state == TASK_INTERRUPTIBLE)
                        wake_up_process(p);
+               restore_flags(flags);
        }
 }
                
 
 int send_sig(unsigned long sig,struct task_struct * p,int priv)
 {
+       unsigned long flags;
+
        if (!p || sig > 32)
                return -EINVAL;
        if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
@@ -86,6 +99,7 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv)
         */
        if (!p->sig)
                return 0;
+       save_flags(flags); cli();
        if ((sig == SIGKILL) || (sig == SIGCONT)) {
                if (p->state == TASK_STOPPED)
                        wake_up_process(p);
@@ -95,6 +109,8 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv)
        }
        if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
                p->signal &= ~(1<<(SIGCONT-1));
+       restore_flags(flags);
+
        /* Actually generate the signal */
        generate(sig,p);
        return 0;
@@ -402,8 +418,13 @@ static inline void close_files(struct files_struct * files)
                if (i >= NR_OPEN)
                        break;
                while (set) {
-                       if (set & 1)
-                               close_fp(files->fd[i]);
+                       if (set & 1) {
+                               struct file * file = files->fd[i];
+                               if (file) {
+                                       files->fd[i] = NULL;
+                                       close_fp(file);
+                               }
+                       }
                        i++;
                        set >>= 1;
                }
index 1e0aa1704737b1ed0018033bebd41b7bdb304dcb..3750b8322be1e5d7a82fb44996016cb0b3a32307 100644 (file)
@@ -86,7 +86,7 @@ static inline int dup_mmap(struct mm_struct * mm)
        for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
                tmp = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
                if (!tmp) {
-                       exit_mmap(mm);
+                       /* exit_mmap is called by the caller */
                        return -ENOMEM;
                }
                *tmp = *mpnt;
@@ -101,12 +101,10 @@ static inline int dup_mmap(struct mm_struct * mm)
                        tmp->vm_prev_share = mpnt;
                }
                if (copy_page_range(mm, current->mm, tmp)) {
-                       if (mpnt->vm_next_share == tmp) {
-                               tmp->vm_prev_share->vm_next_share = tmp->vm_next_share;
-                               tmp->vm_next_share->vm_prev_share = tmp->vm_prev_share; 
-                       }
-                       kfree(tmp);
-                       exit_mmap(mm);
+                       /* link into the linked list for exit_mmap */
+                       *p = tmp;
+                       p = &tmp->vm_next;
+                       /* exit_mmap is called by the caller */
                        return -ENOMEM;
                }
                if (tmp->vm_ops && tmp->vm_ops->open)
index ce81c12ca22a5927aed02b110c07d8741c854eab..dd653740e39677c81e7ea855431b32278b089690 100644 (file)
@@ -1194,9 +1194,7 @@ int generic_file_mmap(struct inode * inode, struct file * file, struct vm_area_s
 static int msync_interval(struct vm_area_struct * vma,
        unsigned long start, unsigned long end, int flags)
 {
-       if (!vma->vm_inode)
-               return 0;
-       if (vma->vm_ops->sync) {
+       if (vma->vm_inode && vma->vm_ops && vma->vm_ops->sync) {
                int error;
                error = vma->vm_ops->sync(vma, start, end-start, flags);
                if (error)
index cf68b18ff5e2f3424251a9dcb1dc0f0b5c0a6a1e..cca6b56ed6e160e8c3819bef2f3f4c5460cb22a0 100644 (file)
@@ -320,6 +320,7 @@ void swap_in(struct task_struct * tsk, struct vm_area_struct * vma,
                return;
        }
        if (!page) {
+               printk("swap_in:");
                set_pte(page_table, BAD_PAGE);
                swap_free(entry);
                oom(tsk);
index c61c779d178b54d96c252d30509c36c969c99866..e37748f9b2e97b2153e9952d22a50ec8fa4bb753 100644 (file)
@@ -143,8 +143,10 @@ static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned lo
                pte_t * pte = pte_alloc_kernel(pmd, address);
                if (!pte)
                        return -ENOMEM;
-               if (alloc_area_pte(pte, address, end - address))
+               if (alloc_area_pte(pte, address, end - address)) {
+                       pte_free_kernel(pte);
                        return -ENOMEM;
+               }
                address = (address + PMD_SIZE) & PMD_MASK;
                pmd++;
        }
@@ -162,8 +164,10 @@ static int alloc_area_pages(unsigned long address, unsigned long size)
                pmd_t *pmd = pmd_alloc_kernel(dir, address);
                if (!pmd)
                        return -ENOMEM;
-               if (alloc_area_pmd(pmd, address, end - address))
+               if (alloc_area_pmd(pmd, address, end - address)) {
+                       pmd_free_kernel(pmd);
                        return -ENOMEM;
+               }
                set_pgdir(address, *dir);
                address = (address + PGDIR_SIZE) & PGDIR_MASK;
                dir++;
@@ -224,8 +228,10 @@ static int remap_area_pages(unsigned long address, unsigned long offset, unsigne
                pmd_t *pmd = pmd_alloc_kernel(dir, address);
                if (!pmd)
                        return -ENOMEM;
-               if (remap_area_pmd(pmd, address, end - address, offset + address))
+               if (remap_area_pmd(pmd, address, end - address, offset + address)) {
+                       pmd_free_kernel(pmd);
                        return -ENOMEM;
+               }
                set_pgdir(address, *dir);
                address = (address + PGDIR_SIZE) & PGDIR_MASK;
                dir++;
index 4af23f644f4fb2d0be608a1c661824fcc00061f9..9251a21909c4be3d7d505f12bcc72af921ff0852 100644 (file)
@@ -328,6 +328,11 @@ static int swap_out(unsigned int priority, int dma, int wait, int can_do_io)
                        shfrv =  8;
                        break;
        }
+       /*
+        * kswapd should be more friendly to other processes.
+        */
+       if (kswapd_awake)
+               shfrv = 10;
 #endif
 
        counter = ((PAGEOUT_WEIGHT * nr_tasks) >> shfrv) >> priority;
@@ -453,7 +458,7 @@ void kswapd_setup(void)
  */
 int kswapd(void *unused)
 {
-       int i, j;
+       int i, reserved_pages;
        
        current->session = 1;
        current->pgrp = 1;
@@ -491,12 +496,15 @@ int kswapd(void *unused)
                swapstats.wakeups++;
                /* Protect our reserved pages: */
                i = 0;
-               j = (min_free_pages >= 48 ? min_free_pages-12 : min_free_pages);
-               if (nr_free_pages <= j)
-                       i = (1+j) - nr_free_pages;
+               reserved_pages = min_free_pages;
+               if (min_free_pages >= 48)
+                       reserved_pages -= (12 + (reserved_pages>>3));
+               if (nr_free_pages <= reserved_pages)
+                       i = (1+reserved_pages) - nr_free_pages;
                /* Do the background pageout: */
                for (i += kswapd_ctl.maxpages; i > 0; i--)
-                       try_to_free_page(GFP_KERNEL, 0, (nr_free_pages <= j));
+                       try_to_free_page(GFP_KERNEL, 0,
+                                        (nr_free_pages <= min_free_pages));
        }
 }
 
index 564ff9246881715458aabc299073e62e9d0fde7c..0d004abf192b24da29c3ceca468ff59880319712 100644 (file)
@@ -321,6 +321,17 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
        if (dev2->flags & IFF_UP)
        {
 #ifdef CONFIG_IP_MASQUERADE
+               __u32   premasq_saddr = iph->saddr;
+               __u16   premasq_sport = 0;
+               __u16   *portptr;
+               long    premasq_len_diff = skb->len;
+
+               if (iph->protocol==IPPROTO_UDP ||
+                    iph->protocol==IPPROTO_TCP) {
+                       portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+                       premasq_sport = portptr[0];
+               }
+
                /*
                 * If this fragment needs masquerading, make it so...
                 * (Don't masquerade de-masqueraded fragments)
@@ -341,6 +352,28 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag,
                if (skb->len+encap > dev2->mtu && (iph->frag_off & htons(IP_DF))) 
                {
                        ip_statistics.IpFragFails++;
+#ifdef CONFIG_IP_MASQUERADE
+                       /* If we're demasquerading, put the correct daddr back */
+                       if (is_frag&IPFWD_MASQUERADED)
+                               iph->daddr = dev->pa_addr;
+
+                       /* If we're masquerading, put the correct source back */
+                       else if (fw_res==FW_MASQUERADE) {
+                               iph->saddr = premasq_saddr;
+                               if (premasq_sport)
+                                       portptr[0] = premasq_sport;
+                       }
+                       /* If the packet has got larger and this has caused it to
+                          exceed the MTU, then we'll claim that our MTU just got
+                          smaller and hope it works */
+                       premasq_len_diff -= skb->len;
+
+                       if (premasq_len_diff < 0)
+                               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+                                         htonl(dev2->mtu+premasq_len_diff), dev);
+                       else
+#endif
                        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(dev2->mtu), dev);
                        if(rt)
                                ip_rt_put(rt);
index e7727b5e0273165687fa1fa532bfb02ce53c10d8..a25fe622dab967e35b1bef283bdafa2f597ed0d4 100644 (file)
@@ -67,6 +67,9 @@ static struct symbol_table net_syms = {
        X(sock_register),
        X(sock_unregister),
 
+       X(sock_alloc),
+       X(sock_release),
+
        /* Socket layer support routines */
        X(memcpy_fromiovec),
        X(sock_setsockopt),