aic7xxx-5.0.9 second test patch

Doug Ledford dledford at dialnet.net
Thu Mar 26 15:39:57 PST 1998


I'm attaching my second 5.0.9-pre test patch to this email.  It applies
against a clean 5.0.8, not against the last pre patch.  It should solve
peoples problems with hangs during bootup.  I've done some pretty extensive
testing/rebooting in order to get the reqinit handler to something I'm happy
with.  I've even verified that a Zip drive works with this, and since that's
what most people with the lockup problem had, that should be a pretty good
indicator.  Let me know if there are problems.

-- 

 Doug Ledford  <dledford at dialnet.net>
  Opinions expressed are my own, but
     they should be everybody's.
-------------- next part --------------
diff -U 3 -rN linux-5.0.8/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- linux-5.0.8/drivers/scsi/aic7xxx.c	Sun Mar 15 18:30:30 1998
+++ linux/drivers/scsi/aic7xxx.c	Thu Mar 26 17:35:44 1998
@@ -170,6 +170,7 @@
 #include <stdarg.h>
 #include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -208,7 +209,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.0.8"
+#define AIC7XXX_C_VERSION  "5.0.9"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -990,6 +991,14 @@
                                               * to cards that have cable
                                               * detection logic and a SEEPROM
                                               */
+static int aic7xxx_panic_on_abort = 0;       /*
+                                              * Set this to non-0 in order
+                                              * to force the driver to panic
+                                              * the kernel and print out
+                                              * debugging info on an abort
+                                              * or reset call into the
+                                              * driver.
+                                              */
 
 /*
  * So that insmod can find the variable and make it point to something
@@ -1065,6 +1074,7 @@
  *
  ***************************************************************************/
 
+
 static inline unsigned char
 aic_inb(struct aic7xxx_host *p, long port)
 {
@@ -1140,6 +1150,7 @@
     { "reverse_scan",&aic7xxx_reverse_scan },
     { "7895_irq_hack", &aic7xxx_7895_irq_hack },
     { "override_term", &aic7xxx_override_term },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
     { "tag_info",    NULL }
   };
 
@@ -1587,9 +1598,11 @@
   unsigned char response_period;
   unsigned char tindex;
   unsigned short target_mask;
+  unsigned char lun;
 
   tindex = target | (channel << 3);
   target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
 
   response_period = *period;
 
@@ -1642,7 +1655,7 @@
              (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
         {
           printk(INFO_LEAD "Synchronous at %sMHz, "
-                 "offset %d.\n", p->host_no, channel, target, 0,
+                 "offset %d.\n", p->host_no, channel, target, lun,
                  aic7xxx_syncrates[i].english, *offset);
           p->dev_flags[tindex] &= ~ DEVICE_PRINT_SDTR;
         }
@@ -1664,7 +1677,7 @@
          (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
     {
       printk(INFO_LEAD "Using asynchronous transfers.\n",
-             p->host_no, channel, target, 0);
+             p->host_no, channel, target, lun);
       p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
     }
   }
@@ -2027,9 +2040,15 @@
 
     /*
      * Optimize for 30 scbs at a time, but allow a final allocation of
-     * fewer than 30 scbs
+     * fewer than 30 scbs.  Except on 64 bit platforms, we optimize for
+     * 29 SCBs at a time because a pointer is 4 bytes larger and we don't
+     * want to overrun this suppossedly 32K allocation to 64K and waste
+     * tons of space.
      */
-    scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+    if( sizeof(void *) == sizeof(int) )
+      scb_count = MIN(30, p->scb_data->maxscbs - p->scb_data->numscbs);
+    else
+      scb_count = MIN(29, p->scb_data->maxscbs - p->scb_data->numscbs);
     
     scb_ap = (struct aic7xxx_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
     if (scb_ap != NULL)
@@ -3068,7 +3087,8 @@
     if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
       printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
         channel, -1, -1);
-    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), SIMODE1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
     p->msg_type = MSG_TYPE_NONE;
     p->msg_len = 0;
@@ -3151,9 +3171,14 @@
   }
   if (sent)
   {
-    pause_sequencer(p);
-    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-    unpause_sequencer(p, FALSE);
+    if(p->type & AHC_AIC78x0)
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
+    }
     if (p->activescbs > p->max_activescbs)
       p->max_activescbs = p->activescbs;
   }
@@ -3558,8 +3583,7 @@
             aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
           }
         }
-        else if ( (last_msg == MSG_IDENTIFYFLAG) &&
-                  (scb->flags & SCB_MSGOUT_SDTR) )
+        else if (scb->flags & SCB_MSGOUT_SDTR)
         {
          /*
           * note asynch xfers and clear flag
@@ -4318,8 +4342,12 @@
           /* Time to end the message */
           p->msg_len = 0;
           p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
           aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
-          aic_outb(p, CLRREQINIT, CLRSINT1);
           aic_outb(p, CLRSCSIINT, CLRINT);
           p->flags &= ~AHC_HANDLING_REQINITS;
 
@@ -4368,8 +4396,7 @@
           p->msg_len = 0;
           p->msg_type = MSG_TYPE_NONE;
           p->flags &= ~AHC_HANDLING_REQINITS;
-          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1 );
-          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
           aic_outb(p, CLRSCSIINT, CLRINT);
           unpause_sequencer(p, TRUE);
         }
@@ -4413,6 +4440,26 @@
     scb = NULL;
   }
 
+
+  if ( (p->flags & AHC_HANDLING_REQINITS) && (status & REQINIT) )
+  {
+    if (scb)
+    {
+      aic7xxx_handle_reqinit(p, scb);
+    }
+    else
+    {
+      p->flags &= ~AHC_HANDLING_REQINITS;
+      aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+      aic_outb(p, CLRREQINIT, CLRSINT1);
+      aic_outb(p, CLRSCSIINT, CLRINT);
+      p->msg_type = MSG_TYPE_NONE;
+      p->msg_index = 0;
+      p->msg_len = 0;
+    }
+    return;
+  }
+
   if ((status & SCSIRSTI) != 0)
   {
     int channel;
@@ -4494,9 +4541,10 @@
              (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
       scb = NULL;
     }
-    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), SIMODE1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
-    aic_outb(p, CLRBUSFREE, CLRSINT1);
+    aic_outb(p, CLRBUSFREE | CLRREQINIT, CLRSINT1);
     aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
     unpause_sequencer(p, TRUE);
@@ -4586,7 +4634,7 @@
     aic_outb(p, 0, SCSISEQ);
     aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
     p->flags &= ~AHC_HANDLING_REQINITS;
-    aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE | CLRREQINIT, CLRSINT1);
     aic_outb(p, CLRSCSIINT, CLRINT);
     restart_sequencer(p);
     unpause_sequencer(p, TRUE);
@@ -4608,11 +4656,6 @@
     unpause_sequencer(p, /* unpause always */ TRUE);
     scb = NULL;
   }
-  else if ((status & REQINIT) != 0)
-  {
-    aic7xxx_handle_reqinit(p, scb);
-    scb = NULL;
-  }
   else if (status & SCSIPERR)
   {
     /*
@@ -4856,6 +4899,7 @@
    * Indicate that we're in the interrupt handler.
    */
   p->flags |= AHC_IN_ISR;
+  restore_flags(flags);
   while ( (intstat = aic_inb(p, INTSTAT)) &
           (CMDCMPLT | SCSIINT | SEQINT | BRKADRINT) )
   {
@@ -4925,6 +4969,8 @@
               p->dev_flags[TARGET_INDEX(cmd)] |= 
                  DEVICE_SUCCESS | DEVICE_PRESENT;
             aic7xxx_done(p, scb);
+            aic7xxx_done_cmds_complete(p);
+            aic7xxx_run_waiting_queues(p);
             break;
         }      
       }
@@ -4956,18 +5002,19 @@
 
     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->flags & AHC_HANDLING_REQINITS) )
-    unpause_sequencer(p, TRUE);
-  restore_flags(flags);
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
   p->flags &= ~AHC_IN_ISR;
@@ -6027,11 +6074,11 @@
    */
   detect_maxscb(p);
   printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
-  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%x, IO Mem 0x%x, "
-    "IO Addr 0x%x, IRQ %d\n", p->host_no,
-    (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
-    p->base, p->mbase, (unsigned int)p->maddr, p->irq);
-
+  printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%x, IRQ %d\n",
+    p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+    p->base, p->irq);
+  printk(KERN_INFO "(scsi%d) IO Memory at 0x%08x, MMAP Memory at 0x%08x\n",
+    p->host_no, p->mbase, (unsigned int)p->maddr);
 
 
   if (aic7xxx_boards[p->irq] == NULL)
@@ -6251,6 +6298,7 @@
         target_settings &= 0x7F;
       }
     }
+
     aic_outb(p, target_settings, TARG_SCRATCH + i);
     if (p->needsdtr_copy & (0x01 << i))
     {
@@ -7159,11 +7207,12 @@
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, 19 }
     };
 
-    int error;
     int done = 0;
     unsigned short index = 0;
-    unsigned char pci_bus, pci_device_fn;
-    unsigned int  devconfig;
+    unsigned char pci_bus, pci_device_fn, command;
+    unsigned int  devconfig, exromctl;
+    unsigned long page_offset;
+    unsigned long base;
     struct aic7xxx_host *first_7895 = NULL;
 
     for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -7206,15 +7255,22 @@
           /*
            * Read sundry information from PCI BIOS.
            */
-          error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-                               PCI_BASE_ADDRESS_0, &temp_p->base);
-          error += pcibios_read_config_byte(pci_bus, pci_device_fn,
-                               PCI_INTERRUPT_LINE, &temp_p->irq);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                               PCI_BASE_ADDRESS_1, &temp_p->mbase);
-          error += pcibios_read_config_dword(pci_bus, pci_device_fn,
-                               DEVCONFIG, &devconfig);
-
+          pcibios_read_config_dword(pci_bus, pci_device_fn,
+            PCI_BASE_ADDRESS_0, &temp_p->base);
+          pcibios_read_config_byte(pci_bus, pci_device_fn,
+            PCI_INTERRUPT_LINE, &temp_p->irq);
+          pcibios_read_config_dword(pci_bus, pci_device_fn,
+            PCI_BASE_ADDRESS_1, &temp_p->mbase);
+          pcibios_read_config_dword(pci_bus, pci_device_fn,
+            DEVCONFIG, &devconfig);
+          pcibios_read_config_dword(pci_bus, pci_device_fn,
+            PCI_ROM_ADDRESS, &exromctl);
+          pcibios_write_config_dword(pci_bus, pci_device_fn,
+            PCI_ROM_ADDRESS, exromctl & ~(PCI_ROM_ADDRESS_ENABLE));
+          pcibios_read_config_byte(pci_bus, pci_device_fn,
+            PCI_COMMAND + 1, &command);
+          pcibios_write_config_byte(pci_bus, pci_device_fn,
+            PCI_COMMAND + 1, command | 0x03);
           /*
            * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
            * we mask it off.
@@ -7224,10 +7280,15 @@
           temp_p->unpause = (aic_inb(temp_p, HCNTRL) & IRQMS) | INTEN;
           temp_p->pause = temp_p->unpause | PAUSE;
 
-          temp_p->maddr = 0;   /* for now, until we get the remap code
-                                * up and running, this makes sure we use
-                                * regular programmed I/O. 
-                                */
+          base = temp_p->mbase & PAGE_MASK;
+          page_offset = temp_p->mbase - base;
+          /*
+           * replace the next line with this one if you are using 2.1.x:
+           * temp_p->maddr = ioremap(base, page_offset + 256);
+           */
+          temp_p->maddr = vremap(base, page_offset + 256);
+          if(temp_p->maddr)
+            temp_p->maddr += page_offset;
 
           aic_outb(temp_p, temp_p->pause, HCNTRL);
           while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
@@ -7932,8 +7993,7 @@
     {
         scbq_insert_tail(&p->waiting_scbs, scb);
     }
-    if (  (p->flags & 
-          (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
     {
       aic7xxx_run_waiting_queues(p);
     }
@@ -8135,6 +8195,40 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+void
+aic7xxx_panic_abort(struct aic7xxx_host *p)
+{
+  int i;
+
+  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  for(i=0; i<MAX_TARGETS; i++)
+  {
+    if(p->dev_flags[i] & DEVICE_PRESENT)
+    {
+      printk(INFO_LEAD "dev_flags=0x%x, WDTR:%s, SDTR:%s, q_depth=%d:%d\n",
+        p->host_no, 0, i, 0, p->dev_flags[i],
+        (p->needwdtr_copy & (1 << i)) ? "Yes" : "No",
+        (p->needsdtr_copy & (1 << i)) ? "Yes" : "No",
+        p->dev_max_queue_depth[i], p->dev_mid_level_queue_depth[i]);
+    }
+  }
+  printk("SIMODE0=0x%x, SIMODE1=0x%x, SSTAT0=0x%x, SSTAT1=0x%x, INTSTAT=0x%x\n",
+    aic_inb(p, SIMODE0), aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+    aic_inb(p, SSTAT1), aic_inb(p, INTSTAT) );
+  printk("p->flags=0x%x, p->type=0x%x, sequencer %s paused\n",
+     p->flags, p->type,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  panic("Stopping to debug\n");
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_abort
  *
  * Description:
@@ -8153,8 +8247,18 @@
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
 
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
   save_flags(processor_flags);
-  pause_sequencer(p);
   cli();
 
 /*
@@ -8165,7 +8269,17 @@
  *  code.
  */
 
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR) )
+  while( (p->flags & AHC_IN_ISR) )
+  {
+    /*
+     * Oops, we're in the interrupt routine, return an error
+     */
+    restore_flags(processor_flags);
+    return(SCSI_ABORT_BUSY);
+  } 
+
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) )
   {
     aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL);
     pause_sequencer(p);
@@ -8477,10 +8591,31 @@
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   tindex = TARGET_INDEX(cmd);
 
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * usefull information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p);
+
   save_flags(processor_flags);
-  pause_sequencer(p);
   cli();
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR) )
+
+  if( (p->flags & AHC_IN_ISR) )
+  {
+    /*
+     * Oops, we're in the interrupt routine, return an error
+     */
+    restore_flags(processor_flags);
+    return(SCSI_RESET_ERROR);
+  } 
+
+  pause_sequencer(p);
+  while ( (aic_inb(p, INTSTAT) & INT_PEND) )
   {
     aic7xxx_isr(p->irq, (void *)NULL, (void *)NULL );
     pause_sequencer(p);
@@ -8666,9 +8801,9 @@
       else
       {
         result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-        aic7xxx_clear_intstat(p);
         aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
           SIMODE1);
+        aic7xxx_clear_intstat(p);
         p->flags &= ~AHC_HANDLING_REQINITS;
         p->msg_type = MSG_TYPE_NONE;
         p->msg_index = 0;


More information about the aic7xxx mailing list