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