aic7xxx-5.0.9 second test patch

Doug Ledford (dledford@dialnet.net)
Thu, 26 Mar 1998 17:37:29 -0600


This is a multi-part message in MIME format.
--------------B76E117DDF9ACE1461CFD49E
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

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@dialnet.net> Opinions expressed are my own, but they should be everybody's. --------------B76E117DDF9ACE1461CFD49E Content-Type: text/plain; charset=us-ascii; name="aic7xxx.test.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="aic7xxx.test.patch"

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;

--------------B76E117DDF9ACE1461CFD49E--

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu