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

Next file: linux/drivers/scsi/aic7xxx_seq.c
Previous file: linux/drivers/scsi/aic7xxx/aic7xxx.seq
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.16/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.28"
+#define AIC7XXX_C_VERSION  "5.1.31"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -576,7 +576,7 @@
  * AIC-7770 I/O range to reserve for a card
  */
 #define MINREG                0xC00
-#define MAXREG                0xCBF
+#define MAXREG                0xCFF
 
 #define INTDEF                0x5C      /* Interrupt Definition Register */
 
@@ -1491,10 +1491,10 @@
   {
     outb(val, p->base + port);
     mb(); /* locked operation in order to force ordering */
-    inb(p->base + HCNTRL); /* dummy read to flush the write */
   }
 #else
   outb(val, p->base + port);
+  mb(); /* locked operation in order to force ordering */
 #endif
 }
 
@@ -1664,6 +1664,10 @@
   {
     ;
   }
+  if(p->features & AHC_ULTRA2)
+  {
+    aic_inb(p, CCSCBCTL);
+  }
 }
 
 /*+F*************************************************************************
@@ -2133,7 +2137,7 @@
      * Use async transfers for this target
      */
     *options = 0;
-    *period = 0;
+    *period = 255;
     syncrate = NULL;
   }
   return (syncrate);
@@ -2901,6 +2905,7 @@
 #define WIDE_INQUIRY_BITS 0x60
 #define SYNC_INQUIRY_BITS 0x10
 #define SCSI_VERSION_BITS 0x07
+#define SCSI_DT_BIT       0x04
       if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
            (p->features & AHC_WIDE) )
       {
@@ -2919,61 +2924,66 @@
                                                    AHC_TRANS_CUR) );
         unpause_sequencer(p, FALSE);
       }
-      if (buffer[7] & SYNC_INQUIRY_BITS)
+      if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+            p->transinfo[tindex].user_offset )
       {
-        p->needsdtr |= (1<<tindex);
-        p->needsdtr_copy |= (1<<tindex);
-
         p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
         p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
-        if (p->transinfo[tindex].user_offset)
+        if (p->features & AHC_ULTRA2)
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+        else
+          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
+               (buffer[56] & SCSI_DT_BIT) ||
+	       (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+               (p->transinfo[tindex].user_period <= 9) &&
+               (p->transinfo[tindex].user_options) )
         {
-          if (p->features & AHC_ULTRA2)
-            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
-          else
-            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+          p->needppr |= (1<<tindex);
+          p->needppr_copy |= (1<<tindex);
+          p->needsdtr &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->needwdtr &= ~(1<<tindex);
+          p->needwdtr_copy &= ~(1<<tindex);
+          p->dev_flags[tindex] |= DEVICE_SCSI_3;
+        }
+        else
+        {
+          p->needsdtr |= (1<<tindex);
+          p->needsdtr_copy |= (1<<tindex);
+          p->transinfo[tindex].goal_period = 
+            MAX(10, p->transinfo[tindex].goal_period);
+          p->transinfo[tindex].goal_options = 0;
         }
       }
       else
       {
         p->needsdtr &= ~(1<<tindex);
         p->needsdtr_copy &= ~(1<<tindex);
-        p->transinfo[tindex].goal_period = 0;
+        p->transinfo[tindex].goal_period = 255;
         p->transinfo[tindex].goal_offset = 0;
         p->transinfo[tindex].goal_options = 0;
       }
-      if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+      /*
+       * This is needed to work around a sequencer bug for now.  Regardless
+       * of the controller in use, if we have a Quantum drive, we need to
+       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
+       * of the sequencer, this code will get yanked.
+       */
+      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
+         p->transinfo[tindex].goal_options )
       {
-        p->dev_flags[tindex] |= DEVICE_SCSI_3;
-        /*
-         * OK, we are a SCSI 3 device and we are in need of negotiation.
-         * Use PPR messages instead of WDTR and SDTR messages.
-         */
-        if ( (p->needsdtr & (1<<tindex)) ||
-             (p->needwdtr & (1<<tindex)) )
-        {
-          p->needppr |= (1<<tindex);
-          p->needppr_copy |= (1<<tindex);
-        }
-        p->needwdtr &= ~(1<<tindex);
-        p->needwdtr_copy &= ~(1<<tindex);
-        p->needsdtr &= ~(1<<tindex);
-        p->needsdtr_copy &= ~(1<<tindex);
-        /*
-         * This is needed to work around a sequencer bug for now.  Regardless
-         * of the controller in use, if we have a Quantum drive, we need to
-         * limit the speed to 80MByte/sec.  As soon as I get a fixed version
-         * of the sequencer, this code will get yanked.
-         */
-        if(!strncmp(buffer + 8, "QUANTUM", 7) &&
-           p->transinfo[tindex].goal_options )
-        {
-          p->transinfo[tindex].goal_period = 
-            MAX(p->transinfo[tindex].goal_period, 10);
-          p->transinfo[tindex].goal_options = 0;
-        }
+        p->transinfo[tindex].goal_period = 
+          MAX(p->transinfo[tindex].goal_period, 10);
+        p->transinfo[tindex].goal_options = 0;
+        p->needppr &= ~(1<<tindex);
+        p->needppr_copy &= ~(1<<tindex);
+        p->needsdtr |= (1<<tindex);
+        p->needsdtr_copy |= (1<<tindex);
+        p->needwdtr |= (1<<tindex);
+        p->needwdtr_copy |= (1<<tindex);
       }
       /*
        * Get the INQUIRY checksum.  We use this on Ultra 160/m
@@ -3003,6 +3013,7 @@
 #undef WIDE_INQUIRY_BITS
 #undef SYNC_INQUIRY_BITS
 #undef SCSI_VERSION_BITS
+#undef SCSI_DT_BIT
     }
   }
   else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
@@ -4639,7 +4650,9 @@
            * As per the draft specs, any device capable of supporting any of
            * the option values other than 0 are not allowed to reject the
            * PPR message.  Instead, they must negotiate out what they do
-           * support instead of rejecting our offering.
+           * support instead of rejecting our offering or else they cause
+           * a parity error during msg_out phase to signal that they don't
+           * like our settings.
            */
           p->needppr &= ~target_mask;
           p->needppr_copy &= ~target_mask;
@@ -4817,51 +4830,6 @@
                 scb->sg_count = hscb->SG_segment_count = 1;
                 scb->sg_length = sizeof(cmd->sense_buffer);
                 scb->tag_action = 0;
-                /*
-                 * This problem could be caused if the target has lost power
-                 * or found some other way to loose the negotiation settings,
-                 * so if needed, we'll re-negotiate while doing the sense cmd.
-                 * However, if this SCB already was attempting to negotiate,
-                 * then we assume this isn't the problem and skip this part.
-                 */
-                if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
-                     (p->dev_flags[tindex] & DEVICE_SCANNED) &&
-                     !(p->dtr_pending & target_mask) ) 
-                {
-                  p->needppr |= (p->needppr_copy & target_mask);
-                  p->needwdtr |= (p->needwdtr_copy & target_mask);
-                  p->needsdtr |= (p->needsdtr_copy & target_mask);
-                }
-                else if ( scb->cmd == p->dev_dtr_cmnd[tindex] )
-                {
-                  /*
-                   * This is already a negotiation command, so we must have
-                   * already done PPR, WDTR or SDTR.  Since our negotiation
-                   * could have gotten rejected, we don't really know the
-                   * full state of things.  Don't do anything here, and allow
-                   * the negotiation_complete() handler to do the right
-                   * thing.
-                   */
-
-                  /*
-                   * This is the important part though.  We are getting sense
-                   * info back from this device.  It's going into a fake
-                   * command.  We need to put that into the real command
-                   * instead so that the mid level SCSI code can act upon it.
-                   * So, when we set up these fake commands, the next pointer
-                   * is used to point to the real command.  Use that to change
-                   * the address of our sense_buffer[] to the real command.
-                   * However, don't do this if the real command is also a
-                   * TEST_UNIT_READY as it will most likely pull down its own
-                   * SENSE information anyway.
-                   */
-                  if (cmd->next->cmnd[0] != TEST_UNIT_READY)
-                  {
-                    scb->sg_list[0].address = 
-                      cpu_to_le32(VIRT_TO_BUS(&cmd->next->sense_buffer[0]));
-                    hscb->data_pointer = scb->sg_list[0].address;
-                  }
-                }
                 scb->flags |= SCB_SENSE;
                 /*
                  * Ensure the target is busy since this will be an
@@ -4884,7 +4852,7 @@
                 aic7xxx_error(cmd) = DID_OK;
                 break;
               }  /* first time sense, no errors */
-              aic7xxx_error(cmd) = DID_OK;
+              aic7xxx_error(cmd) = DID_ERROR;
               scb->flags &= ~SCB_SENSE;
               break;
 
@@ -5135,51 +5103,14 @@
         }
         else if (scb->flags & SCB_MSGOUT_PPR)
         {
-          unsigned int max_sync, period;
-          unsigned char options = 0;
-
-          if (p->features & AHC_ULTRA2)
-          {
-            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-            {
-              if( (p->features & AHC_ULTRA3) &&
-                  (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
-                  (p->transinfo[tindex].goal_width ==
-                   MSG_EXT_WDTR_BUS_16_BIT) &&
-                  (p->transinfo[tindex].goal_options != 0) )
-              {
-                max_sync = AHC_SYNCRATE_ULTRA3;
-                options = p->transinfo[tindex].goal_options;
-              }
-              else
-              {
-                max_sync = AHC_SYNCRATE_ULTRA2;
-              }
-            }
-            else
-            {
-              max_sync = AHC_SYNCRATE_ULTRA;
-            }
-          }
-          else if (p->features & AHC_ULTRA)
-          {
-            max_sync = AHC_SYNCRATE_ULTRA;
-          }
-          else
-          {
-            max_sync = AHC_SYNCRATE_FAST;
-          }
-          period = p->transinfo[tindex].goal_period;
-          aic7xxx_find_syncrate(p, &period, max_sync, &options);
-          p->transinfo[tindex].goal_period = period;
-          p->transinfo[tindex].goal_options = options;
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
-                   p->host_no, CTL_OF_SCB(scb), period,
+                   p->host_no, CTL_OF_SCB(scb),
+                   p->transinfo[tindex].goal_period,
                    p->transinfo[tindex].goal_offset,
-                   p->transinfo[tindex].goal_width, options);
+                   p->transinfo[tindex].goal_width,
+                   p->transinfo[tindex].goal_options);
           }
           aic7xxx_construct_ppr(p, scb);
         }
@@ -5225,8 +5156,7 @@
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
-                   CTL_OF_SCB(scb),
-                   p->transinfo[tindex].goal_period,
+                   CTL_OF_SCB(scb), period,
                    p->transinfo[tindex].goal_offset);
           }
           aic7xxx_construct_sdtr(p, period,
@@ -5339,7 +5269,7 @@
         resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
         resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
           (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
-          (aic_inb(p, SCB_RESID_DCNT + 2) << 24);
+          (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
         index = scb->sg_count - (resid_sgcnt + 1);
         native_addr = le32_to_cpu(scb->sg_list[index].address);
         native_length = le32_to_cpu(scb->sg_list[index].length);
@@ -5347,7 +5277,7 @@
          * Make sure this is a valid sg_seg for the given pointer
          */
         if(cur_addr < native_addr ||
-           cur_addr > (native_addr + native_length))
+           cur_addr > (native_addr + native_length + 1))
         {
           printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
                  p->host_no, CTL_OF_SCB(scb), cur_addr);
@@ -5364,16 +5294,31 @@
                    p->host_no, CTL_OF_SCB(scb),
                    le32_to_cpu(scb->sg_list[index + 1].address),
                    le32_to_cpu(scb->sg_list[index + 1].length));
+          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
+                 p->host_no, CTL_OF_SCB(scb),
+                 cur_addr, resid_dcnt);
           break;
         }
 
-        /*
-         * If our current address matches the sg_seg->address then we
-         * have to back up the sg array to the previous segment and set
-         * it up to have only one byte of transfer left to go.
-         */
-        if(cur_addr == native_addr)
+        if( (resid_sgcnt == 0) &&
+            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
         {
+          /*
+           * We are at the end of the transfer and this is about a byte
+           * we ignored already (because the sequencer knew this was
+           * the last segment and set the adapter to ignore any wide
+           * residue bytes that might come through, which is only done
+           * on the last scatter gather segment of transfers).
+           */
+          break;
+        }
+        else if(cur_addr == native_addr)
+        {
+          /*
+           * If our current address matches the sg_seg->address then we
+           * have to back up the sg array to the previous segment and set
+           * it up to have only one byte of transfer left to go.
+           */
           if(index == 0)
           {
             printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
@@ -5403,39 +5348,6 @@
           aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
           aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
           aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
-          /*
-           * The sequencer actually wants to find the new address and byte
-           * count in the SHCNT and SHADDR register sets.  These registers
-           * are a shadow of the regular HCNT and HADDR registers.  On the
-           * Ultra2 controllers, these registers are read only and the way
-           * we have to set their values is to put the values we want into
-           * the HCNT and HADDR registers and then output PRELOADEN into
-           * the DFCNTRL register which causes the card to latch the current
-           * values in the HADDR and HCNT registers and drop it through to
-           * the shadow registers.  On older cards we copy them directly
-           * across by hand.
-           */
-          if(p->features & AHC_ULTRA2)
-          {
-            aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-            i=0;
-            udelay(1);
-            while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
-            {
-              aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-              udelay(1);
-            }
-          }
-          else
-          {
-            aic_outb(p, 1, STCNT); 
-            aic_outb(p, 0, STCNT + 1); 
-            aic_outb(p, 0, STCNT + 2); 
-            aic_outb(p, cur_addr & 0xff, SHADDR);
-            aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
-            aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
-            aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
-          }
         }
         else
         {
@@ -5455,28 +5367,46 @@
           aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
           aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
           aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
-          if(p->features & AHC_ULTRA2)
+        }
+        /*
+         * The sequencer actually wants to find the new address and byte
+         * count in the SHCNT and SHADDR register sets.  These registers
+         * are a shadow of the regular HCNT and HADDR registers.  On the
+         * Ultra2 controllers, these registers are read only and the way
+         * we have to set their values is to put the values we want into
+         * the HCNT and HADDR registers and then output PRELOADEN into
+         * the DFCNTRL register which causes the card to latch the current
+         * values in the HADDR and HCNT registers and drop it through to
+         * the shadow registers.  On older cards we copy them directly
+         * across by hand.
+         */
+        if(p->features & AHC_ULTRA2)
+        {
+          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+          i=0;
+          udelay(1);
+          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
           {
-            aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-            i=0;
             udelay(1);
-            while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
-            {
-              aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-              udelay(1);
-            }
           }
-          else
+          aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
+          i=0;
+          udelay(1);
+          while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
           {
-            aic_outb(p, resid_dcnt & 0xff, STCNT); 
-            aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
-            aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
-            aic_outb(p, cur_addr & 0xff, SHADDR);
-            aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
-            aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
-            aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+            udelay(1);
           }
         }
+        else
+        {
+          aic_outb(p, resid_dcnt & 0xff, STCNT); 
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
+          aic_outb(p, cur_addr & 0xff, SHADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+        }
       }
       break;
 
@@ -5885,6 +5815,7 @@
           reply = TRUE;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_PPR;
+	  p->dev_flags[tindex] |= DEVICE_SCSI_3;
           if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
           {
             /*
@@ -5918,7 +5849,6 @@
               p->transinfo[tindex].user_width;
             p->transinfo[tindex].goal_options =
               p->transinfo[tindex].user_options;
-            p->needppr_copy |= target_mask;
           }
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
@@ -5952,6 +5882,25 @@
               break;
             }
           }
+          if ( (p->transinfo[tindex].goal_period > 9) ||
+               (p->transinfo[tindex].goal_options == 0) )
+          {
+            scb->flags &= ~SCB_MSGOUT_BITS;
+            reject = TRUE;
+            reply = FALSE;
+            p->needppr &= ~(1 << tindex);
+            p->needppr_copy &= ~(1 << tindex);
+            if ( p->transinfo[tindex].goal_offset )
+            {
+              p->needsdtr |= (1 << tindex);
+              p->needsdtr_copy |= (1 << tindex);
+            }
+            if ( p->transinfo[tindex].goal_width )
+            {
+              p->needwdtr |= (1 << tindex);
+              p->needwdtr_copy |= (1 << tindex);
+            }
+          }
         }
         else
         {
@@ -5959,7 +5908,7 @@
           {
             default:
             {
-              reply = TRUE;
+              reject = TRUE;
               if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
                    ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
                     (aic7xxx_verbose > 0xffff)) )
@@ -5985,27 +5934,18 @@
           }
         }
 
-        aic7xxx_set_width(p, target, channel, lun, bus_width,
-                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
-                                         &new_trans_options);
-        aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
-        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, new_trans_options,
-                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-
-        if( (offset != saved_offset) ||
-            (trans_options != new_trans_options) ||
-            ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
-             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) )
+        if ( !reject )
         {
           aic7xxx_set_width(p, target, channel, lun, bus_width,
-                            AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
           aic7xxx_set_syncrate(p, syncrate, target, channel, period,
                                offset, new_trans_options,
-                               AHC_TRANS_GOAL|AHC_TRANS_QUITE);
-          reply = TRUE;
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
+
         p->dtr_pending &= ~target_mask;
         p->needppr &= ~target_mask;
         if(reply)
@@ -6411,20 +6351,14 @@
     /*
      * Keep the sequencer from trying to restart any selections
      */
-    aic_outb(p, 0, SCSISEQ);
+    aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
     /*
      * Make sure the data bits on the bus are released
+     * Don't do this on 7770 chipsets, it makes them give us
+     * a BRKADDRINT and kills the card.
      */
-    if(p->features & AHC_WIDE)
-      aic_outb(p, 0, SCSIBUSH);
-    aic_outb(p, 0, SCSIBUSL);
-    /*
-     * Clear the target id bit from the SCSI bus
-     */
-    if(p->features & AHC_ULTRA2)
-      aic_outb(p, aic_inb(p, SCSIID_ULTRA2) & 0x0f, SCSIID_ULTRA2);
-    else
-      aic_outb(p, aic_inb(p, SCSIID) & 0x0f, SCSIID);
+    if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+      aic_outb(p, 0, SCSIBUSL);
 
     /*
      * Delay for the selection timeout delay period then stop the selection
@@ -6507,7 +6441,9 @@
      * A parity error has occurred during a data
      * transfer phase. Flag it and continue.
      */
-    if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) )
+    if( (p->features & AHC_ULTRA3) && 
+        (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) &&
+        (lastphase == P_DATAIN) )
     {
       printk(WARN_LEAD "CRC error during %s phase.\n",
              p->host_no, CTL_OF_SCB(scb), phase);
@@ -6532,13 +6468,50 @@
                p->host_no, CTL_OF_SCB(scb));
       }
     }
-    else
+    else if( (lastphase == P_MESGOUT) &&
+             (cmd == p->dev_dtr_cmnd[tindex]) &&
+             (scb->flags & SCB_MSGOUT_PPR) )
     {
-      printk(WARN_LEAD "Parity error during %s phase.\n",
-             p->host_no, CTL_OF_SCB(scb), phase);
+      /*
+       * As per the draft specs, any device capable of supporting any of
+       * the option values other than 0 are not allowed to reject the
+       * PPR message.  Instead, they must negotiate out what they do
+       * support instead of rejecting our offering or else they cause
+       * a parity error during msg_out phase to signal that they don't
+       * like our settings.
+       */
+      p->needppr &= ~(1 << tindex);
+      p->needppr_copy &= ~(1 << tindex);
+      aic7xxx_set_width(p, scb->cmd->target, scb->cmd->channel, scb->cmd->lun,
+                        MSG_EXT_WDTR_BUS_8_BIT,
+                        (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+      aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
+                           0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+      p->transinfo[tindex].goal_options = 0;
+      p->dtr_pending &= ~(1 << tindex);
+      scb->flags &= ~SCB_MSGOUT_BITS;
+      if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+      {
+        printk(INFO_LEAD "parity error during PPR message, reverting "
+               "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
+      }
+      if ( p->transinfo[tindex].goal_width )
+      {
+        p->needwdtr |= (1 << tindex);
+        p->needwdtr_copy |= (1 << tindex);
+      }
+      if ( p->transinfo[tindex].goal_offset )
+      {
+        if( p->transinfo[tindex].goal_period <= 9 )
+        {
+          p->transinfo[tindex].goal_period = 10;
+        }
+        p->needsdtr |= (1 << tindex);
+        p->needsdtr_copy |= (1 << tindex);
+      }
+      scb = NULL;
     }
-
-    if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
     {
       struct aic7xxx_syncrate *syncrate;
       unsigned int period = p->transinfo[tindex].cur_period;
@@ -6550,6 +6523,8 @@
        * instead of slowing down if those exist.  That's hard to do with simple
        * checksums though.
        */
+      printk(WARN_LEAD "Parity error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
       if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
       {
         syncrate++;
@@ -6557,20 +6532,59 @@
             (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
         {
           p->transinfo[tindex].goal_period = syncrate->period;
-          if( !(syncrate->sxfr_ultra2 & 0x40) )
+          if( p->transinfo[tindex].goal_period > 9 )
           {
             p->transinfo[tindex].goal_options = 0;
+            p->needppr &= ~(1<<tindex);
+            p->needsdtr |= (1<<tindex);
+            p->needppr_copy &= ~(1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
+            if (p->transinfo[tindex].goal_width)
+            {
+              p->needwdtr |= (1<<tindex);
+              p->needwdtr_copy |= (1<<tindex);
+            }
+          }
+        }
+        else if (p->transinfo[tindex].goal_width)
+        {
+          p->transinfo[tindex].goal_width = 0;
+          p->needwdtr &= ~(1<<tindex);
+          p->needwdtr_copy &= ~(1<<tindex);
+          p->transinfo[tindex].goal_offset =
+            p->transinfo[tindex].user_offset;
+          p->transinfo[tindex].goal_period =
+            p->transinfo[tindex].user_period;
+          p->transinfo[tindex].goal_options =
+            p->transinfo[tindex].user_options;
+          if( p->transinfo[tindex].goal_period <= 9 )
+          {
+            p->needppr |= (1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needppr_copy |= (1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+          }
+          else
+          {
+            p->needppr &= ~(1<<tindex);
+            p->needsdtr |= (1<<tindex);
+            p->needppr_copy &= ~(1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
           }
         }
         else
         {
           p->transinfo[tindex].goal_offset = 0;
-          p->transinfo[tindex].goal_period = 0;
+          p->transinfo[tindex].goal_period = 255;
           p->transinfo[tindex].goal_options = 0;
+          p->transinfo[tindex].goal_width = 0;
+          p->needppr &= ~(1<<tindex);
+          p->needsdtr &= ~(1<<tindex);
+          p->needwdtr &= ~(1<<tindex);
+          p->needppr_copy &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->needwdtr_copy &= ~(1<<tindex);
         }
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
       }
       p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
     }
@@ -6588,6 +6602,7 @@
     if (mesg_out != MSG_NOOP)
     {
       aic_outb(p, mesg_out, MSG_OUT);
+      aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
       scb = NULL;
     }
     aic_outb(p, CLRSCSIPERR, CLRSINT1);
@@ -6779,7 +6794,7 @@
 {
   struct aic7xxx_scb *scb = NULL;
   Scsi_Cmnd *cmd;
-  unsigned char scb_index;
+  unsigned char scb_index, tindex;
 
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
   if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
@@ -6805,23 +6820,21 @@
     scb_index = p->qoutfifo[p->qoutfifonext];
     p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
     if ( scb_index >= p->scb_data->numscbs )
-      scb = NULL;
-    else
-      scb = p->scb_data->scb_array[scb_index];
-    if (scb == NULL)
     {
       printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
         -1, -1, -1, scb_index);
       continue;
     }
-    else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+    scb = p->scb_data->scb_array[scb_index];
+    if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
     {
       printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
         "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
         (unsigned long) scb->cmd);
       continue;
     }
-    else if (scb->flags & SCB_QUEUED_ABORT)
+    tindex = TARGET_INDEX(scb->cmd);
+    if (scb->flags & SCB_QUEUED_ABORT)
     {
       pause_sequencer(p);
       if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
@@ -6844,6 +6857,43 @@
        */
       scb->flags &= ~(SCB_ABORT|SCB_RESET);
     }
+    else if (scb->flags & SCB_SENSE)
+    {
+      char *buffer = &scb->cmd->sense_buffer[0];
+      if (scb->cmd == p->dev_dtr_cmnd[tindex])
+      {
+        struct aic7xxx_scb *old_scb;
+        /*
+         * We have valid sense data, send it back immediately.
+         */
+        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
+        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
+        old_scb->hscb->target_status = scb->hscb->target_status;
+        old_scb->cmd->result = scb->hscb->target_status;
+        old_scb->cmd->result |= (DID_ERROR << 16);
+        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
+        scbq_remove(&p->waiting_scbs, old_scb);
+        scbq_remove(&p->delayed_scbs[tindex], old_scb);
+        scb->cmd->next = NULL;
+	aic7xxx_done(p, scb);
+        aic7xxx_done(p, old_scb);
+	continue;
+      } 
+      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+      {
+        /*
+         * SCSI errors, run domain validation and re-run negotiation
+         */
+        p->needdv |= (1<<tindex);
+        /*
+         * Signal that we need to re-negotiate things, this also gets us our
+         * INQUIRY command to re-checksum off of.
+         */
+        p->needppr |= (p->needppr_copy & (1<<tindex));
+        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+      }
+    }
     switch (status_byte(scb->hscb->target_status))
     {
       case QUEUE_FULL:
@@ -6973,6 +7023,13 @@
 
   if (intstat & SEQINT)
   {
+    /*
+     * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
+     */
+    if(p->features & AHC_ULTRA2)
+    {
+      aic_inb(p, CCSCBCTL);
+    }
     aic7xxx_handle_seqint(p, intstat);
   }
 
@@ -7055,7 +7112,7 @@
  *   with queue depths for individual devices.  It also allows tagged
  *   queueing to be [en|dis]abled for a specific adapter.
  *-F*************************************************************************/
-static void
+static int
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
   int default_depth = 3;
@@ -7065,6 +7122,14 @@
   tindex = device->id | (device->channel << 3);
   target_mask = (1 << tindex);
 
+  if (p->dev_max_queue_depth[tindex] > 1)
+  {
+    /*
+     * We've already scanned this device, leave it alone
+     */
+    return(p->dev_max_queue_depth[tindex]);
+  }
+
   device->queue_depth = default_depth;
   p->dev_temp_queue_depth[tindex] = 1;
   p->dev_max_queue_depth[tindex] = 1;
@@ -7133,6 +7198,7 @@
       }
     }
   }
+  return(p->dev_max_queue_depth[tindex]);
 }
 
 /*+F*************************************************************************
@@ -7160,8 +7226,7 @@
   {
     if (device->host == host)
     {
-      aic7xxx_device_queue_depth(p, device);
-      scbnum += device->queue_depth;
+      scbnum += aic7xxx_device_queue_depth(p, device);
     }
   }
   while (scbnum > p->scb_data->numscbs)
@@ -8371,23 +8436,8 @@
   }
   aic_outb(p, 0, SEQ_FLAGS);
 
-  /*
-   * We are starting to do real work on the card....it's possible we could
-   * generate some spurious interrupts at this point, especially in the
-   * event of a PCI error or some such.  If there are other devices already
-   * registered on the same interrupt as us, this could cause the machine
-   * to lock up.  So, we disable the interrupt this card is on until we
-   * finish our card setup.  We only need to do this for modules, if we are
-   * compiled into the kernel then interrupts are already off during this
-   * part of the code.
-   */
-#ifdef MODULE
-  disable_irq(p->irq);
-#endif
-
   detect_maxscb(p);
 
-
   printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
   if (aic7xxx_verbose & VERBOSE_PROBE2)
   {
@@ -8616,9 +8666,6 @@
       printk("(scsi%d) Unable to allocate hardware SCB array; "
              "failing detection.\n", p->host_no);
       aic_outb(p, 0, SIMODE1);
-#ifdef MODULE
-      enable_irq(p->irq);
-#endif
       p->irq = 0;
       return(0);
     }
@@ -8796,9 +8843,6 @@
     printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
            "controller.\n", p->host_no, p->irq);
     aic_outb(p, 0, SIMODE1);
-#ifdef MODULE
-    enable_irq(p->irq);
-#endif
     p->irq = 0;
     return (0);
   }
@@ -8808,10 +8852,6 @@
       p->host_no, -1, -1 , -1);
   aic7xxx_clear_intstat(p);
 
-#ifdef MODULE
-  enable_irq(p->irq);
-#endif
-
   unpause_sequencer(p, /* unpause_always */ TRUE);
 
   return (found);
@@ -8920,7 +8960,7 @@
     p->orderedtag = 0;
     for (i=0; i<MAX_TARGETS; i++)
     {
-      p->transinfo[i].goal_period = 0;
+      p->transinfo[i].goal_period = 255;
       p->transinfo[i].goal_offset = 0;
       p->transinfo[i].goal_options = 0;
       p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
@@ -9709,7 +9749,8 @@
           {
             if ( ((current_p->pci_bus == temp_p->pci_bus) &&
                   (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
-                  (current_p->base == temp_p->base) )
+                 (temp_p->base && (current_p->base == temp_p->base)) ||
+                 (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
             {
               /* duplicate PCI entry, skip it */
               kfree(temp_p);
@@ -9769,7 +9810,8 @@
           {
             if ( ((current_p->pci_bus == temp_p->pci_bus) &&
                   (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
-                  (current_p->base == temp_p->base) )
+                 (temp_p->base && (current_p->base == temp_p->base)) ||
+                 (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
             {
               /* duplicate PCI entry, skip it */
               kfree(temp_p);
@@ -9812,7 +9854,7 @@
 #endif /* AIC7XXX_STRICT_PCI_SETUP */
 #endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
 
-          if(check_region(temp_p->base, MAXREG - MINREG))
+          if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
           {
             printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
               board_names[aic_pdevs[i].board_name_index],
@@ -9843,7 +9885,7 @@
           }
 
 #ifdef MMAPIO
-          if ( !(temp_p->flags & AHC_MULTI_CHANNEL) ||
+          if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
                ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
                 (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
           {
@@ -9881,6 +9923,18 @@
                 vfree((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
 #endif
                 temp_p->maddr = 0;
+                if(temp_p->base == 0)
+                {
+                  printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+                  kfree(temp_p);
+                  temp_p = NULL;
+                  continue;
+                }
               }
             }
           }
@@ -9889,7 +9943,8 @@
           /*
            * Lock out other contenders for our i/o space.
            */
-          request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
+          if(temp_p->base)
+            request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
 
           /*
            * We HAVE to make sure the first pause_sequencer() and all other
@@ -10801,20 +10856,59 @@
               (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
           {
             p->transinfo[tindex].goal_period = syncrate->period;
-            if( !(syncrate->sxfr_ultra2 & 0x40) )
+            if( p->transinfo[tindex].goal_period > 9 )
             {
               p->transinfo[tindex].goal_options = 0;
+              p->needppr &= ~(1<<tindex);
+              p->needsdtr |= (1<<tindex);
+              p->needppr_copy &= ~(1<<tindex);
+              p->needsdtr_copy |= (1<<tindex);
+              if (p->transinfo[tindex].goal_width)
+              {
+                p->needwdtr |= (1<<tindex);
+                p->needwdtr_copy |= (1<<tindex);
+              }
+            }
+          }
+          else if (p->transinfo[tindex].goal_width)
+          {
+            p->transinfo[tindex].goal_width = 0;
+            p->needwdtr &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
+            p->transinfo[tindex].goal_offset =
+              p->transinfo[tindex].user_offset;
+            p->transinfo[tindex].goal_period =
+              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_options =
+              p->transinfo[tindex].user_options;
+            if( p->transinfo[tindex].goal_period <= 9 )
+            {
+              p->needppr |= (1<<tindex);
+              p->needsdtr &= ~(1<<tindex);
+              p->needppr_copy |= (1<<tindex);
+              p->needsdtr_copy &= ~(1<<tindex);
+            }
+            else
+            {
+              p->needppr &= ~(1<<tindex);
+              p->needsdtr |= (1<<tindex);
+              p->needppr_copy &= ~(1<<tindex);
+              p->needsdtr_copy |= (1<<tindex);
             }
           }
           else
           {
             p->transinfo[tindex].goal_offset = 0;
-            p->transinfo[tindex].goal_period = 0;
+            p->transinfo[tindex].goal_period = 255;
             p->transinfo[tindex].goal_options = 0;
+            p->transinfo[tindex].goal_width = 0;
+            p->needppr &= ~(1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needwdtr &= ~(1<<tindex);
+            p->needppr_copy &= ~(1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
           }
-          p->needppr |= (p->needppr_copy & (1<<tindex));
-          p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-          p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
         }
         p->needdv &= ~(1<<tindex);
       }
@@ -10865,8 +10959,16 @@
    * and we didn't follow up with SDTR yet, then this will get it started.
    * For all other cases, this should work out to be a no-op, unless we are
    * doing domain validation and happen to need a new negotiation command.
+   *
+   * In case we don't want this to go any further, the cmdcmplt interrupt
+   * handler will NULL out the cmd->next entry so that the real SCSI command
+   * can be sent back to the mid layer code with SENSE data intact.  We'll
+   * finish things up when the cmd gets sent back down to us, so no worries.
    */
-  aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+  if(cmd->next)
+  {
+    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
+  }
   return;
 }
 
@@ -10988,13 +11090,13 @@
    */
   hscb->control = 0;
   scb->tag_action = 0;
+  cmd->tag = hscb->tag;
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
     if ( (p->tagenable & mask) &&
          (cmd->cmnd[0] != TEST_UNIT_READY) )
     {
-      cmd->tag = hscb->tag;
       p->dev_commands_sent[tindex]++;
       if (p->dev_commands_sent[tindex] < 200)
       {
@@ -12275,7 +12377,8 @@
 
   if(p->irq)
     free_irq(p->irq, p);
-  release_region(p->base, MAXREG - MINREG);
+  if(p->base)
+    release_region(p->base, MAXREG - MINREG);
 #ifdef MMAPIO
   if(p->maddr)
   {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)