aic7xxx_old.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:392k
- scarray, p->sc_size, C56_66);
- else
- have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
- scarray, p->sc_size, C46);
- }
- if (!have_seeprom)
- {
- p->sc_size = 128;
- have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
- scarray, p->sc_size, p->sc_type);
- if (!have_seeprom)
- {
- if(p->sc_type == C46)
- have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
- scarray, p->sc_size, C56_66);
- else
- have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
- scarray, p->sc_size, C46);
- }
- }
- break;
- }
- if (!have_seeprom)
- {
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("naic7xxx: No SEEPROM available.n");
- }
- p->flags |= AHC_NEWEEPROM_FMT;
- if (aic_inb(p, SCSISEQ) == 0)
- {
- p->flags |= AHC_USEDEFAULTS;
- p->flags &= ~AHC_BIOS_ENABLED;
- p->scsi_id = p->scsi_id_b = 7;
- *sxfrctl1 |= STPWEN;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("aic7xxx: Using default values.n");
- }
- }
- else if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("aic7xxx: Using leftover BIOS values.n");
- }
- if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
- {
- p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
- sc->adapter_control &= ~CFAUTOTERM;
- sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
- }
- if (aic7xxx_extended)
- p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
- else
- p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
- }
- else
- {
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("donen");
- }
- /*
- * Note things in our flags
- */
- p->flags |= AHC_SEEPROM_FOUND;
- /*
- * Update the settings in sxfrctl1 to match the termination settings.
- */
- *sxfrctl1 = 0;
- /*
- * Get our SCSI ID from the SEEPROM setting...
- */
- p->scsi_id = (sc->brtime_id & CFSCSIID);
- /*
- * First process the settings that are different between the VLB
- * and PCI adapter seeproms.
- */
- if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770)
- {
- /* VLB adapter seeproms */
- if (sc->bios_control & CF284XEXTEND)
- p->flags |= AHC_EXTEND_TRANS_A;
- if (sc->adapter_control & CF284XSTERM)
- {
- *sxfrctl1 |= STPWEN;
- p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
- }
- }
- else
- {
- /* PCI adapter seeproms */
- if (sc->bios_control & CFEXTEND)
- p->flags |= AHC_EXTEND_TRANS_A;
- if (sc->bios_control & CFBIOSEN)
- p->flags |= AHC_BIOS_ENABLED;
- else
- p->flags &= ~AHC_BIOS_ENABLED;
- if (sc->adapter_control & CFSTERM)
- {
- *sxfrctl1 |= STPWEN;
- p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
- }
- }
- memcpy(&p->sc, sc, sizeof(struct seeprom_config));
- }
- p->discenable = 0;
-
- /*
- * Limit to 16 targets just in case. The 2842 for one is known to
- * blow the max_targets setting, future cards might also.
- */
- max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
- if (have_seeprom)
- {
- for (i = 0; i < max_targets; i++)
- {
- if( ((p->features & AHC_ULTRA) &&
- !(sc->adapter_control & CFULTRAEN) &&
- (sc->device_flags[i] & CFSYNCHISULTRA)) ||
- (sc->device_flags[i] & CFNEWULTRAFORMAT) )
- {
- p->flags |= AHC_NEWEEPROM_FMT;
- break;
- }
- }
- }
- for (i = 0; i < max_targets; i++)
- {
- mask = (0x01 << i);
- if (!have_seeprom)
- {
- if (aic_inb(p, SCSISEQ) != 0)
- {
- /*
- * OK...the BIOS set things up and left behind the settings we need.
- * Just make our sc->device_flags[i] entry match what the card has
- * set for this device.
- */
- p->discenable =
- ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
- p->ultraenb =
- (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) );
- sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
- if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER)
- sc->device_flags[i] |= CFWIDEB;
- if (p->features & AHC_ULTRA2)
- {
- if (aic_inb(p, TARG_OFFSET + i))
- {
- sc->device_flags[i] |= CFSYNCH;
- sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07);
- if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 )
- sc->device_flags[i] |= CFSYNCHISULTRA;
- }
- }
- else
- {
- if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER)
- {
- sc->device_flags[i] |= CFSYNCH;
- if (p->features & AHC_ULTRA)
- sc->device_flags[i] |= ((p->ultraenb & mask) ?
- CFSYNCHISULTRA : 0);
- }
- }
- }
- else
- {
- /*
- * Assume the BIOS has NOT been run on this card and nothing between
- * the card and the devices is configured yet.
- */
- sc->device_flags[i] = CFDISC;
- if (p->features & AHC_WIDE)
- sc->device_flags[i] |= CFWIDEB;
- if (p->features & AHC_ULTRA3)
- sc->device_flags[i] |= 2;
- else if (p->features & AHC_ULTRA2)
- sc->device_flags[i] |= 3;
- else if (p->features & AHC_ULTRA)
- sc->device_flags[i] |= CFSYNCHISULTRA;
- sc->device_flags[i] |= CFSYNCH;
- aic_outb(p, 0, TARG_SCSIRATE + i);
- if (p->features & AHC_ULTRA2)
- aic_outb(p, 0, TARG_OFFSET + i);
- }
- }
- if (sc->device_flags[i] & CFDISC)
- {
- p->discenable |= mask;
- }
- if (p->flags & AHC_NEWEEPROM_FMT)
- {
- if ( !(p->features & AHC_ULTRA2) )
- {
- /*
- * I know of two different Ultra BIOSes that do this differently.
- * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
- * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s
- * while on the IBM Netfinity 5000 they want the same thing
- * to be something else, while flags[i] & CFXFER == 0x03 and
- * SYNCHISULTRA false should be 40MByte/s. So, we set both to
- * 40MByte/s and the lower speeds be damned. People will have
- * to select around the conversely mapped lower speeds in order
- * to select lower speeds on these boards.
- */
- if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
- ((sc->device_flags[i] & CFXFER) == 0x03) )
- {
- sc->device_flags[i] &= ~CFXFER;
- sc->device_flags[i] |= CFSYNCHISULTRA;
- }
- if (sc->device_flags[i] & CFSYNCHISULTRA)
- {
- p->ultraenb |= mask;
- }
- }
- else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) &&
- (p->features & AHC_ULTRA2) &&
- (sc->device_flags[i] & CFSYNCHISULTRA) )
- {
- p->ultraenb |= mask;
- }
- }
- else if (sc->adapter_control & CFULTRAEN)
- {
- p->ultraenb |= mask;
- }
- if ( (sc->device_flags[i] & CFSYNCH) == 0)
- {
- sc->device_flags[i] &= ~CFXFER;
- p->ultraenb &= ~mask;
- p->transinfo[i].user_offset = 0;
- p->transinfo[i].user_period = 0;
- p->transinfo[i].user_options = 0;
- p->transinfo[i].cur_offset = 0;
- p->transinfo[i].cur_period = 0;
- p->transinfo[i].cur_options = 0;
- p->needsdtr_copy &= ~mask;
- }
- else
- {
- if (p->features & AHC_ULTRA3)
- {
- p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
- p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
- if( (sc->device_flags[i] & CFXFER) < 0x03 )
- {
- scsirate = (sc->device_flags[i] & CFXFER);
- p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
- if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
- {
- p->transinfo[i].cur_options =
- ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
- MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
- }
- else
- {
- p->transinfo[i].cur_options = 0;
- }
- }
- else
- {
- scsirate = (sc->device_flags[i] & CFXFER) |
- ((p->ultraenb & mask) ? 0x18 : 0x10);
- p->transinfo[i].user_options = 0;
- p->transinfo[i].cur_options = 0;
- }
- p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
- AHC_SYNCRATE_ULTRA3);
- p->transinfo[i].cur_period = aic7xxx_find_period(p,
- aic_inb(p, TARG_SCSIRATE + i),
- AHC_SYNCRATE_ULTRA3);
- }
- else if (p->features & AHC_ULTRA2)
- {
- p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
- p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
- scsirate = (sc->device_flags[i] & CFXFER) |
- ((p->ultraenb & mask) ? 0x18 : 0x10);
- p->transinfo[i].user_options = 0;
- p->transinfo[i].cur_options = 0;
- p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
- AHC_SYNCRATE_ULTRA2);
- p->transinfo[i].cur_period = aic7xxx_find_period(p,
- aic_inb(p, TARG_SCSIRATE + i),
- AHC_SYNCRATE_ULTRA2);
- }
- else
- {
- scsirate = (sc->device_flags[i] & CFXFER) << 4;
- p->transinfo[i].user_options = 0;
- p->transinfo[i].cur_options = 0;
- p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
- if (p->features & AHC_ULTRA)
- {
- short ultraenb;
- ultraenb = aic_inb(p, ULTRA_ENB) |
- (aic_inb(p, ULTRA_ENB + 1) << 8);
- p->transinfo[i].user_period = aic7xxx_find_period(p,
- scsirate,
- (p->ultraenb & mask) ?
- AHC_SYNCRATE_ULTRA :
- AHC_SYNCRATE_FAST);
- p->transinfo[i].cur_period = aic7xxx_find_period(p,
- aic_inb(p, TARG_SCSIRATE + i),
- (ultraenb & mask) ?
- AHC_SYNCRATE_ULTRA :
- AHC_SYNCRATE_FAST);
- }
- else
- p->transinfo[i].user_period = aic7xxx_find_period(p,
- scsirate, AHC_SYNCRATE_FAST);
- }
- p->needsdtr_copy |= mask;
- }
- if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) )
- {
- p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_16_BIT;
- p->needwdtr_copy |= mask;
- }
- else
- {
- p->transinfo[i].user_width = MSG_EXT_WDTR_BUS_8_BIT;
- p->needwdtr_copy &= ~mask;
- }
- p->transinfo[i].cur_width =
- (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) ?
- MSG_EXT_WDTR_BUS_16_BIT : MSG_EXT_WDTR_BUS_8_BIT;
- }
- aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
- aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
- p->needppr = p->needppr_copy = 0;
- p->needwdtr = p->needwdtr_copy;
- p->needsdtr = p->needsdtr_copy;
- p->dtr_pending = 0;
- /*
- * We set the p->ultraenb from the SEEPROM to begin with, but now we make
- * it match what is already down in the card. If we are doing a reset
- * on the card then this will get put back to a default state anyway.
- * This allows us to not have to pre-emptively negotiate when using the
- * no_reset option.
- */
- if (p->features & AHC_ULTRA)
- p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8);
-
- scsi_conf = (p->scsi_id & HSCSIID);
- if(have_seeprom)
- {
- p->adapter_control = sc->adapter_control;
- p->bios_control = sc->bios_control;
- switch (p->chip & AHC_CHIPID_MASK)
- {
- case AHC_AIC7895:
- case AHC_AIC7896:
- case AHC_AIC7899:
- if (p->adapter_control & CFBPRIMARY)
- p->flags |= AHC_CHANNEL_B_PRIMARY;
- default:
- break;
- }
- if (sc->adapter_control & CFSPARITY)
- scsi_conf |= ENSPCHK;
- }
- else
- {
- scsi_conf |= ENSPCHK | RESET_SCSI;
- }
- /*
- * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card.
- * The 2842 and 2742 cards already have these registers set and we don't
- * want to muck with them since we don't set all the bits they do.
- */
- if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
- {
- /* Set the host ID */
- aic_outb(p, scsi_conf, SCSICONF);
- /* In case we are a wide card */
- aic_outb(p, p->scsi_id, SCSICONF + 1);
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_configure_bugs
- *
- * Description:
- * Take the card passed in and set the appropriate bug flags based upon
- * the card model. Also make any changes needed to device registers or
- * PCI registers while we are here.
- *-F*************************************************************************/
- static void
- aic7xxx_configure_bugs(struct aic7xxx_host *p)
- {
- unsigned short tmp_word;
-
- switch(p->chip & AHC_CHIPID_MASK)
- {
- case AHC_AIC7860:
- p->bugs |= AHC_BUG_PCI_2_1_RETRY;
- /* fall through */
- case AHC_AIC7850:
- case AHC_AIC7870:
- p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
- break;
- case AHC_AIC7880:
- p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
- AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
- break;
- case AHC_AIC7890:
- p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
- break;
- case AHC_AIC7892:
- p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
- break;
- case AHC_AIC7895:
- p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
- AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
- break;
- case AHC_AIC7896:
- p->bugs |= AHC_BUG_CACHETHEN_DIS;
- break;
- case AHC_AIC7899:
- p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
- break;
- default:
- /* Nothing to do */
- break;
- }
- /*
- * Now handle the bugs that require PCI register or card register tweaks
- */
- pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
- if(p->bugs & AHC_BUG_PCI_MWI)
- {
- tmp_word &= ~PCI_COMMAND_INVALIDATE;
- }
- else
- {
- tmp_word |= PCI_COMMAND_INVALIDATE;
- }
- pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
- if(p->bugs & AHC_BUG_CACHETHEN)
- {
- aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
- }
- else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
- {
- aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
- }
- return;
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_detect
- *
- * Description:
- * Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
- *
- * XXX - This should really be called aic7xxx_probe(). A sequence of
- * probe(), attach()/detach(), and init() makes more sense than
- * one do-it-all function. This may be useful when (and if) the
- * mid-level SCSI code is overhauled.
- *-F*************************************************************************/
- int
- aic7xxx_detect(Scsi_Host_Template *template)
- {
- struct aic7xxx_host *temp_p = NULL;
- struct aic7xxx_host *current_p = NULL;
- struct aic7xxx_host *list_p = NULL;
- int found = 0;
- #if defined(__i386__) || defined(__alpha__)
- ahc_flag_type flags = 0;
- int type;
- #endif
- unsigned char sxfrctl1;
- #if defined(__i386__) || defined(__alpha__)
- unsigned char hcntrl, hostconf;
- unsigned int slot, base;
- #endif
- #ifdef MODULE
- /*
- * If we are called as a module, the aic7xxx pointer may not be null
- * and it would point to our bootup string, just like on the lilo
- * command line. IF not NULL, then process this config string with
- * aic7xxx_setup
- */
- if(aic7xxx)
- aic7xxx_setup(aic7xxx);
- if(dummy_buffer[0] != 'P')
- printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
- "/scsi/README.aic7xxxn"
- "aic7xxx: to see the proper way to specify options to the aic7xxx "
- "modulen"
- "aic7xxx: Specifically, don't use any commas when passing arguments ton"
- "aic7xxx: insmod or else it might trash certain memory areas.n");
- #endif
- template->proc_name = "aic7xxx";
- template->sg_tablesize = AIC7XXX_MAX_SG;
- #ifdef CONFIG_PCI
- /*
- * PCI-bus probe.
- */
- if (pci_present())
- {
- struct
- {
- unsigned short vendor_id;
- unsigned short device_id;
- ahc_chip chip;
- ahc_flag_type flags;
- ahc_feature features;
- int board_name_index;
- unsigned short seeprom_size;
- unsigned short seeprom_type;
- } const aic_pdevs[] = {
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
- AHC_FNONE, AHC_FENONE, 1,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
- AHC_PAGESCBS, AHC_AIC7850_FE, 5,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
- AHC_PAGESCBS, AHC_AIC7850_FE, 6,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 7,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 7,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 7,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 7,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
- AHC_AIC7860_FE, 7,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 8,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
- AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
- AHC_AIC7870_FE, 9,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870,
- AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7870_FE, 11,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870,
- AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7870_FE, 12,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
- AHC_AIC7880_FE, 14,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7880_FE, 16,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7880_FE, 17,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
- AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7895_FE, 20,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 21,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 21,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 22,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7890_FE, 23,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 24,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 25,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 26,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN,
- AHC_AIC7860_FE, 27,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 28,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 28,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 28,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7892_FE, 28,
- 32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 29,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 29,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 29,
- 32, C56_66 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
- AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7899_FE, 29,
- 32, C56_66 },
- };
- unsigned short command;
- unsigned int devconfig, i, oldverbose;
- struct pci_dev *pdev = NULL;
- for (i = 0; i < NUMBER(aic_pdevs); i++)
- {
- pdev = NULL;
- while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
- aic_pdevs[i].device_id,
- pdev))) {
- if (pci_enable_device(pdev))
- continue;
- if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
- {
- if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
- {
- printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
- "supported byn");
- printk(KERN_INFO " this driver, we are ignoring it.n");
- }
- }
- else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
- GFP_ATOMIC)) != NULL )
- {
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
- temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
- temp_p->flags = aic_pdevs[i].flags;
- temp_p->features = aic_pdevs[i].features;
- temp_p->board_name_index = aic_pdevs[i].board_name_index;
- temp_p->sc_size = aic_pdevs[i].seeprom_size;
- temp_p->sc_type = aic_pdevs[i].seeprom_type;
- /*
- * Read sundry information from PCI BIOS.
- */
- temp_p->irq = pdev->irq;
- temp_p->pdev = pdev;
- temp_p->pci_bus = pdev->bus->number;
- temp_p->pci_device_fn = pdev->devfn;
- temp_p->base = pci_resource_start(pdev, 0);
- temp_p->mbase = pci_resource_start(pdev, 1);
- current_p = list_p;
- while(current_p && temp_p)
- {
- if ( ((current_p->pci_bus == temp_p->pci_bus) &&
- (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
- (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);
- temp_p = NULL;
- }
- current_p = current_p->next;
- }
- if ( temp_p == NULL )
- continue;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at PCI %d/%dn",
- board_names[aic_pdevs[i].board_name_index],
- PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
- pci_read_config_word(pdev, PCI_COMMAND, &command);
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("aic7xxx: Initial PCI_COMMAND value was 0x%xn",
- (int)command);
- }
- #ifdef AIC7XXX_STRICT_PCI_SETUP
- command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
- #else
- command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
- #endif
- command &= ~PCI_COMMAND_INVALIDATE;
- if (aic7xxx_pci_parity == 0)
- command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
- pci_write_config_word(pdev, PCI_COMMAND, command);
- #ifdef AIC7XXX_STRICT_PCI_SETUP
- pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk("aic7xxx: Initial DEVCONFIG value was 0x%xn", devconfig);
- }
- devconfig |= 0x80000040;
- pci_write_config_dword(pdev, DEVCONFIG, devconfig);
- #endif /* AIC7XXX_STRICT_PCI_SETUP */
- if(temp_p->base && check_region(temp_p->base, MAXREG - MINREG))
- {
- printk("aic7xxx: <%s> at PCI %d/%d/%dn",
- 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: I/O ports already in use, ignoring.n");
- kfree(temp_p);
- temp_p = NULL;
- continue;
- }
- temp_p->unpause = INTEN;
- temp_p->pause = temp_p->unpause | PAUSE;
- if ( ((temp_p->base == 0) &&
- (temp_p->mbase == 0)) ||
- (temp_p->irq == 0) )
- {
- printk("aic7xxx: <%s> at PCI %d/%d/%dn",
- 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;
- }
- #ifdef MMAPIO
- if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
- ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
- (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
- {
- unsigned long page_offset, base;
- base = temp_p->mbase & PAGE_MASK;
- page_offset = temp_p->mbase - base;
- temp_p->maddr = ioremap_nocache(base, page_offset + 256);
- if(temp_p->maddr)
- {
- temp_p->maddr += page_offset;
- /*
- * We need to check the I/O with the MMAPed address. Some machines
- * simply fail to work with MMAPed I/O and certain controllers.
- */
- if(aic_inb(temp_p, HCNTRL) == 0xff)
- {
- /*
- * OK.....we failed our test....go back to programmed I/O
- */
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%dn",
- 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(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
- "Programmed I/O.n");
- iounmap((void *) (((unsigned long) temp_p->maddr) & PAGE_MASK));
- temp_p->maddr = 0;
- if(temp_p->base == 0)
- {
- printk("aic7xxx: <%s> at PCI %d/%d/%dn",
- 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;
- }
- }
- }
- }
- #endif
- /*
- * Lock out other contenders for our i/o space.
- */
- if(temp_p->base)
- request_region(temp_p->base, MAXREG - MINREG, "aic7xxx");
- /*
- * We HAVE to make sure the first pause_sequencer() and all other
- * subsequent I/O that isn't PCI config space I/O takes place
- * after the MMAPed I/O region is configured and tested. The
- * problem is the PowerPC architecture that doesn't support
- * programmed I/O at all, so we have to have the MMAP I/O set up
- * for this pause to even work on those machines.
- */
- pause_sequencer(temp_p);
- /*
- * Clear out any pending PCI error status messages. Also set
- * verbose to 0 so that we don't emit strange PCI error messages
- * while cleaning out the current status bits.
- */
- oldverbose = aic7xxx_verbose;
- aic7xxx_verbose = 0;
- aic7xxx_pci_intr(temp_p);
- aic7xxx_verbose = oldverbose;
- temp_p->bios_address = 0;
- /*
- * Remember how the card was setup in case there is no seeprom.
- */
- if (temp_p->features & AHC_ULTRA2)
- temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID;
- else
- temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
- /*
- * Get current termination setting
- */
- sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
- if (aic7xxx_chip_reset(temp_p) == -1)
- {
- release_region(temp_p->base, MAXREG - MINREG);
- kfree(temp_p);
- temp_p = NULL;
- continue;
- }
- /*
- * Very quickly put the term setting back into the register since
- * the chip reset may cause odd things to happen. This is to keep
- * LVD busses with lots of drives from draining the power out of
- * the diffsense line before we get around to running the
- * configure_termination() function. Also restore the STPWLEVEL
- * bit of DEVCONFIG
- */
- aic_outb(temp_p, sxfrctl1, SXFRCTL1);
- pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
- sxfrctl1 &= STPWEN;
- /*
- * We need to set the CHNL? assignments before loading the SEEPROM
- * The 3940 and 3985 cards (original stuff, not any of the later
- * stuff) are 7870 and 7880 class chips. The Ultra2 stuff falls
- * under 7896 and 7897. The 7895 is in a class by itself :)
- */
- switch (temp_p->chip & AHC_CHIPID_MASK)
- {
- case AHC_AIC7870: /* 3840 / 3985 */
- case AHC_AIC7880: /* 3840 UW / 3985 UW */
- if(temp_p->flags & AHC_MULTI_CHANNEL)
- {
- switch(PCI_SLOT(temp_p->pci_device_fn))
- {
- case 5:
- temp_p->flags |= AHC_CHNLB;
- break;
- case 8:
- temp_p->flags |= AHC_CHNLB;
- break;
- case 12:
- temp_p->flags |= AHC_CHNLC;
- break;
- default:
- break;
- }
- }
- break;
- case AHC_AIC7895: /* 7895 */
- case AHC_AIC7896: /* 7896/7 */
- case AHC_AIC7899: /* 7899 */
- if (PCI_FUNC(pdev->devfn) != 0)
- {
- temp_p->flags |= AHC_CHNLB;
- }
- /*
- * The 7895 is the only chipset that sets the SCBSIZE32 param
- * in the DEVCONFIG register. The Ultra2 chipsets use
- * the DSCOMMAND0 register instead.
- */
- if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
- {
- pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
- devconfig |= SCBSIZE32;
- pci_write_config_dword(pdev, DEVCONFIG, devconfig);
- }
- break;
- default:
- break;
- }
- /*
- * Loading of the SEEPROM needs to come after we've set the flags
- * to indicate possible CHNLB and CHNLC assigments. Otherwise,
- * on 394x and 398x cards we'll end up reading the wrong settings
- * for channels B and C
- */
- switch (temp_p->chip & AHC_CHIPID_MASK)
- {
- case AHC_AIC7892:
- case AHC_AIC7899:
- aic_outb(temp_p, 0, SCAMCTL);
- /*
- * Switch to the alt mode of the chip...
- */
- aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
- /*
- * Set our options...the last two items set our CRC after x byte
- * count in target mode...
- */
- aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
- aic_outb(temp_p, 0x00, 0x0b);
- aic_outb(temp_p, 0x10, 0x0a);
- /*
- * switch back to normal mode...
- */
- aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
- aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
- TARGCRCENDEN | TARGCRCCNTEN,
- CRCCONTROL1);
- aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
- MPARCKEN | CIOPARCKEN | CACHETHEN) &
- ~DPARCKEN), DSCOMMAND0);
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- case AHC_AIC7890:
- case AHC_AIC7896:
- aic_outb(temp_p, 0, SCAMCTL);
- aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
- CACHETHEN | MPARCKEN | USCBSIZE32 |
- CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- case AHC_AIC7850:
- case AHC_AIC7860:
- /*
- * Set the DSCOMMAND0 register on these cards different from
- * on the 789x cards. Also, read the SEEPROM as well.
- */
- aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
- CACHETHEN | MPARCKEN) & ~DPARCKEN,
- DSCOMMAND0);
- /* FALLTHROUGH */
- default:
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- case AHC_AIC7880:
- /*
- * Check the rev of the chipset before we change DSCOMMAND0
- */
- pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
- if ((devconfig & 0xff) >= 1)
- {
- aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
- CACHETHEN | MPARCKEN) & ~DPARCKEN,
- DSCOMMAND0);
- }
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- }
-
- /*
- * and then we need another switch based on the type in order to
- * make sure the channel B primary flag is set properly on 7895
- * controllers....Arrrgggghhh!!! We also have to catch the fact
- * that when you disable the BIOS on the 7895 on the Intel DK440LX
- * motherboard, and possibly others, it only sets the BIOS disabled
- * bit on the A channel...I think I'm starting to lean towards
- * going postal....
- */
- switch(temp_p->chip & AHC_CHIPID_MASK)
- {
- case AHC_AIC7895:
- case AHC_AIC7896:
- case AHC_AIC7899:
- current_p = list_p;
- while(current_p != NULL)
- {
- if ( (current_p->pci_bus == temp_p->pci_bus) &&
- (PCI_SLOT(current_p->pci_device_fn) ==
- PCI_SLOT(temp_p->pci_device_fn)) )
- {
- if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
- {
- temp_p->flags |=
- (current_p->flags & AHC_CHANNEL_B_PRIMARY);
- temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
- temp_p->flags |=
- (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
- }
- else
- {
- current_p->flags |=
- (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
- current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
- current_p->flags |=
- (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
- }
- }
- current_p = current_p->next;
- }
- break;
- default:
- break;
- }
- /*
- * We only support external SCB RAM on the 7895/6/7 chipsets.
- * We could support it on the 7890/1 easy enough, but I don't
- * know of any 7890/1 based cards that have it. I do know
- * of 7895/6/7 cards that have it and they work properly.
- */
- switch(temp_p->chip & AHC_CHIPID_MASK)
- {
- default:
- break;
- case AHC_AIC7895:
- case AHC_AIC7896:
- case AHC_AIC7899:
- pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
- if (temp_p->features & AHC_ULTRA2)
- {
- if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
- (aic7xxx_scbram) )
- {
- aic_outb(temp_p,
- aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
- DSCOMMAND0);
- temp_p->flags |= AHC_EXTERNAL_SRAM;
- devconfig |= EXTSCBPEN;
- }
- else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
- {
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%dn",
- 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: external SCB RAM detected, "
- "but not enabledn");
- }
- }
- else
- {
- if ((devconfig & RAMPSM) && (aic7xxx_scbram))
- {
- devconfig &= ~SCBRAMSEL;
- devconfig |= EXTSCBPEN;
- temp_p->flags |= AHC_EXTERNAL_SRAM;
- }
- else if (devconfig & RAMPSM)
- {
- printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%dn",
- 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: external SCB RAM detected, "
- "but not enabledn");
- }
- }
- pci_write_config_dword(pdev, DEVCONFIG, devconfig);
- if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
- (temp_p->flags & AHC_CHNLB) )
- aic_outb(temp_p, 1, CCSCBBADDR);
- break;
- }
- /*
- * Take the LED out of diagnostic mode
- */
- aic_outb(temp_p,
- (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
- SBLKCTL);
- /*
- * We don't know where this is set in the SEEPROM or by the
- * BIOS, so we default to 100%. On Ultra2 controllers, use 75%
- * instead.
- */
- if (temp_p->features & AHC_ULTRA2)
- {
- aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
- }
- else
- {
- aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
- }
- /*
- * Call our function to fixup any bugs that exist on this chipset.
- * This may muck with PCI settings and other device settings, so
- * make sure it's after all the other PCI and device register
- * tweaks so it can back out bad settings on specific broken cards.
- */
- aic7xxx_configure_bugs(temp_p);
- if ( list_p == NULL )
- {
- list_p = current_p = temp_p;
- }
- else
- {
- current_p = list_p;
- while(current_p->next != NULL)
- current_p = current_p->next;
- current_p->next = temp_p;
- }
- temp_p->next = NULL;
- found++;
- } /* Found an Adaptec PCI device. */
- else /* Well, we found one, but we couldn't get any memory */
- {
- printk("aic7xxx: Found <%s>n",
- board_names[aic_pdevs[i].board_name_index]);
- printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
- "skipping.n");
- }
- } /* while(pdev=....) */
- } /* for PCI_DEVICES */
- } /* PCI BIOS present */
- #endif /* CONFIG_PCI */
- #if defined(__i386__) || defined(__alpha__)
- /*
- * EISA/VL-bus card signature probe.
- */
- slot = MINSLOT;
- while ( (slot <= MAXSLOT) &&
- !(aic7xxx_no_probe) )
- {
- base = SLOTBASE(slot) + MINREG;
- if (check_region(base, MAXREG - MINREG))
- {
- /*
- * Some other driver has staked a
- * claim to this i/o region already.
- */
- slot++;
- continue; /* back to the beginning of the for loop */
- }
- flags = 0;
- type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
- if (type == -1)
- {
- slot++;
- continue;
- }
- temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
- if (temp_p == NULL)
- {
- printk(KERN_WARNING "aic7xxx: Unable to allocate device space.n");
- slot++;
- continue; /* back to the beginning of the while loop */
- }
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(base, MAXREG - MINREG, "aic7xxx");
- /*
- * Pause the card preserving the IRQ type. Allow the operator
- * to override the IRQ trigger.
- */
- if (aic7xxx_irq_trigger == 1)
- hcntrl = IRQMS; /* Level */
- else if (aic7xxx_irq_trigger == 0)
- hcntrl = 0; /* Edge */
- else
- hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
- memset(temp_p, 0, sizeof(struct aic7xxx_host));
- temp_p->unpause = hcntrl | INTEN;
- temp_p->pause = hcntrl | PAUSE | INTEN;
- temp_p->base = base;
- temp_p->mbase = 0;
- temp_p->maddr = 0;
- temp_p->pci_bus = 0;
- temp_p->pci_device_fn = slot;
- aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
- while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
- if (aic7xxx_chip_reset(temp_p) == -1)
- temp_p->irq = 0;
- else
- temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
- temp_p->flags |= AHC_PAGESCBS;
- switch (temp_p->irq)
- {
- case 9:
- case 10:
- case 11:
- case 12:
- case 14:
- case 15:
- break;
- default:
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
- "level %d, ignoring.n", temp_p->irq);
- kfree(temp_p);
- release_region(base, MAXREG - MINREG);
- slot++;
- continue; /* back to the beginning of the while loop */
- }
- /*
- * We are commited now, everything has been checked and this card
- * has been found, now we just set it up
- */
- /*
- * Insert our new struct into the list at the end
- */
- if (list_p == NULL)
- {
- list_p = current_p = temp_p;
- }
- else
- {
- current_p = list_p;
- while (current_p->next != NULL)
- current_p = current_p->next;
- current_p->next = temp_p;
- }
- switch (type)
- {
- case 0:
- temp_p->board_name_index = 2;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %dn",
- board_names[2], slot);
- /* FALLTHROUGH */
- case 1:
- {
- temp_p->chip = AHC_AIC7770 | AHC_EISA;
- temp_p->features |= AHC_AIC7770_FE;
- temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
- /*
- * Get the primary channel information. Right now we don't
- * do anything with this, but someday we will be able to inform
- * the mid-level SCSI code which channel is primary.
- */
- if (temp_p->board_name_index == 0)
- {
- temp_p->board_name_index = 3;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at EISA %dn",
- board_names[3], slot);
- }
- if (temp_p->bios_control & CHANNEL_B_PRIMARY)
- {
- temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
- }
- if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
- {
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- }
- else
- {
- temp_p->flags &= ~AHC_USEDEFAULTS;
- temp_p->flags |= AHC_BIOS_ENABLED;
- if ( (temp_p->bios_control & 0x20) == 0 )
- {
- temp_p->bios_address = 0xcc000;
- temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
- }
- else
- {
- temp_p->bios_address = 0xd0000;
- temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
- }
- }
- temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
- temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
- if (temp_p->features & AHC_WIDE)
- {
- temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
- temp_p->scsi_id_b = temp_p->scsi_id;
- }
- else
- {
- temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
- temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
- }
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- break;
- }
- case 2:
- case 3:
- temp_p->chip = AHC_AIC7770 | AHC_VL;
- temp_p->features |= AHC_AIC7770_FE;
- if (type == 2)
- temp_p->flags |= AHC_BIOS_ENABLED;
- else
- temp_p->flags &= ~AHC_BIOS_ENABLED;
- if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
- sxfrctl1 = STPWEN;
- aic7xxx_load_seeprom(temp_p, &sxfrctl1);
- temp_p->board_name_index = 4;
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk("aic7xxx: <%s> at VLB %dn",
- board_names[2], slot);
- switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
- {
- case 0x00:
- temp_p->bios_address = 0xe0000;
- break;
- case 0x20:
- temp_p->bios_address = 0xc8000;
- break;
- case 0x40:
- temp_p->bios_address = 0xd0000;
- break;
- case 0x60:
- temp_p->bios_address = 0xd8000;
- break;
- default:
- break; /* can't get here */
- }
- break;
- default: /* Won't get here. */
- break;
- }
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- {
- printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)n",
- (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
- temp_p->irq,
- (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.n",
- (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
- }
- /*
- * All the 7770 based chipsets have this bug
- */
- temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
- /*
- * Set the FIFO threshold and the bus off time.
- */
- hostconf = aic_inb(temp_p, HOSTCONF);
- aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
- aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
- slot++;
- found++;
- }
- #endif /* defined(__i386__) || defined(__alpha__) */
- /*
- * Now, we re-order the probed devices by BIOS address and BUS class.
- * In general, we follow this algorithm to make the adapters show up
- * in the same order under linux that the computer finds them.
- * 1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
- * address, going from lowest to highest.
- * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS
- * address, going from lowest to highest.
- * 3: Remaining VLB/EISA controllers going in slot order.
- * 4: Remaining PCI controllers, going in PCI device order (reversable)
- */
- {
- struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL };
- struct aic7xxx_host *vlb, *pci;
- struct aic7xxx_host *prev_p;
- struct aic7xxx_host *p;
- unsigned char left;
- prev_p = vlb = pci = NULL;
- temp_p = list_p;
- while (temp_p != NULL)
- {
- switch(temp_p->chip & ~AHC_CHIPID_MASK)
- {
- case AHC_EISA:
- case AHC_VL:
- {
- p = temp_p;
- if (p->flags & AHC_BIOS_ENABLED)
- vlb = sort_list[0];
- else
- vlb = sort_list[2];
- if (vlb == NULL)
- {
- vlb = temp_p;
- temp_p = temp_p->next;
- vlb->next = NULL;
- }
- else
- {
- current_p = vlb;
- prev_p = NULL;
- while ( (current_p != NULL) &&
- (current_p->bios_address < temp_p->bios_address))
- {
- prev_p = current_p;
- current_p = current_p->next;
- }
- if (prev_p != NULL)
- {
- prev_p->next = temp_p;
- temp_p = temp_p->next;
- prev_p->next->next = current_p;
- }
- else
- {
- vlb = temp_p;
- temp_p = temp_p->next;
- vlb->next = current_p;
- }
- }
-
- if (p->flags & AHC_BIOS_ENABLED)
- sort_list[0] = vlb;
- else
- sort_list[2] = vlb;
-
- break;
- }
- default: /* All PCI controllers fall through to default */
- {
- p = temp_p;
- if (p->flags & AHC_BIOS_ENABLED)
- pci = sort_list[1];
- else
- pci = sort_list[3];
- if (pci == NULL)
- {
- pci = temp_p;
- temp_p = temp_p->next;
- pci->next = NULL;
- }
- else
- {
- current_p = pci;
- prev_p = NULL;
- if (!aic7xxx_reverse_scan)
- {
- while ( (current_p != NULL) &&
- ( (PCI_SLOT(current_p->pci_device_fn) |
- (current_p->pci_bus << 8)) <
- (PCI_SLOT(temp_p->pci_device_fn) |
- (temp_p->pci_bus << 8)) ) )
- {
- prev_p = current_p;
- current_p = current_p->next;
- }
- }
- else
- {
- while ( (current_p != NULL) &&
- ( (PCI_SLOT(current_p->pci_device_fn) |
- (current_p->pci_bus << 8)) >
- (PCI_SLOT(temp_p->pci_device_fn) |
- (temp_p->pci_bus << 8)) ) )
- {
- prev_p = current_p;
- current_p = current_p->next;
- }
- }
- /*
- * Are we dealing with a 7895/6/7/9 where we need to sort the
- * channels as well, if so, the bios_address values should
- * be the same
- */
- if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
- (temp_p->pci_bus == current_p->pci_bus) &&
- (PCI_SLOT(temp_p->pci_device_fn) ==
- PCI_SLOT(current_p->pci_device_fn)) )
- {
- if (temp_p->flags & AHC_CHNLB)
- {
- if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
- {
- prev_p = current_p;
- current_p = current_p->next;
- }
- }
- else
- {
- if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
- {
- prev_p = current_p;
- current_p = current_p->next;
- }
- }
- }
- if (prev_p != NULL)
- {
- prev_p->next = temp_p;
- temp_p = temp_p->next;
- prev_p->next->next = current_p;
- }
- else
- {
- pci = temp_p;
- temp_p = temp_p->next;
- pci->next = current_p;
- }
- }
- if (p->flags & AHC_BIOS_ENABLED)
- sort_list[1] = pci;
- else
- sort_list[3] = pci;
- break;
- }
- } /* End of switch(temp_p->type) */
- } /* End of while (temp_p != NULL) */
- /*
- * At this point, the cards have been broken into 4 sorted lists, now
- * we run through the lists in order and register each controller
- */
- {
- int i;
-
- left = found;
- for (i=0; i<NUMBER(sort_list); i++)
- {
- temp_p = sort_list[i];
- while(temp_p != NULL)
- {
- template->name = board_names[temp_p->board_name_index];
- p = aic7xxx_alloc(template, temp_p);
- if (p != NULL)
- {
- p->instance = found - left;
- if (aic7xxx_register(template, p, (--left)) == 0)
- {
- found--;
- aic7xxx_release(p->host);
- scsi_unregister(p->host);
- }
- else if (aic7xxx_dump_card)
- {
- pause_sequencer(p);
- aic7xxx_print_card(p);
- aic7xxx_print_scratch_ram(p);
- unpause_sequencer(p, TRUE);
- }
- }
- current_p = temp_p;
- temp_p = (struct aic7xxx_host *)temp_p->next;
- kfree(current_p);
- }
- }
- }
- }
- return (found);
- }
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- /*+F*************************************************************************
- * Function:
- * aic7xxx_print_scb
- *
- * Description:
- * Dump the byte codes for an about to be sent SCB.
- *-F*************************************************************************/
- static void
- aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
- {
- int i;
- unsigned char *x;
- x = (unsigned char *)&scb->hscb->control;
- for(i=0; i<32; i++)
- {
- printk("%02x ", x[i]);
- }
- printk("n");
- }
- #endif
- /*+F*************************************************************************
- * Function:
- * aic7xxx_buildscb
- *
- * Description:
- * Build a SCB.
- *-F*************************************************************************/
- static void
- aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
- struct aic7xxx_scb *scb)
- {
- unsigned short mask;
- struct aic7xxx_hwscb *hscb;
- unsigned char tindex = TARGET_INDEX(cmd);
- mask = (0x01 << tindex);
- hscb = scb->hscb;
- /*
- * Setup the control byte if we need negotiation and have not
- * already requested it.
- */
- hscb->control = 0;
- scb->tag_action = 0;
- if (p->discenable & mask)
- {
- hscb->control |= DISCENB;
- if ( (p->tagenable & mask) &&
- (cmd->cmnd[0] != TEST_UNIT_READY) )
- {
- p->dev_commands_sent[tindex]++;
- if (p->dev_commands_sent[tindex] < 200)
- {
- hscb->control |= MSG_SIMPLE_Q_TAG;
- scb->tag_action = MSG_SIMPLE_Q_TAG;
- }
- else
- {
- if (p->orderedtag & mask)
- {
- hscb->control |= MSG_ORDERED_Q_TAG;
- scb->tag_action = MSG_ORDERED_Q_TAG;
- }
- else
- {
- hscb->control |= MSG_SIMPLE_Q_TAG;
- scb->tag_action = MSG_SIMPLE_Q_TAG;
- }
- p->dev_commands_sent[tindex] = 0;
- }
- }
- }
- if ( !(p->dtr_pending & mask) &&
- ( (p->needppr & mask) ||
- (p->needwdtr & mask) ||
- (p->needsdtr & mask) ) &&
- (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
- {
- p->dtr_pending |= mask;
- scb->tag_action = 0;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- if(p->needppr & mask)
- {
- scb->flags |= SCB_MSGOUT_PPR;
- }
- else if(p->needwdtr & mask)
- {
- scb->flags |= SCB_MSGOUT_WDTR;
- }
- else if(p->needsdtr & mask)
- {
- scb->flags |= SCB_MSGOUT_SDTR;
- }
- scb->flags |= SCB_DTR_SCB;
- }
- hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
- ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
- /*
- * The interpretation of request_buffer and request_bufflen
- * changes depending on whether or not use_sg is zero; a
- * non-zero use_sg indicates the number of elements in the
- * scatter-gather array.
- */
- /*
- * XXX - this relies on the host data being stored in a
- * little-endian format.
- */
- hscb->SCSI_cmd_length = cmd->cmd_len;
- memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
- hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
- if (cmd->use_sg)
- {
- struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */
- /*
- * We must build an SG list in adapter format, as the kernel's SG list
- * cannot be used directly because of data field size (__alpha__)
- * differences and the kernel SG list uses virtual addresses where
- * we need physical addresses.
- */
- int i, use_sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- scb->sg_length = 0;
- use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
- /*
- * Copy the segments into the SG array. NOTE!!! - We used to
- * have the first entry both in the data_pointer area and the first
- * SG element. That has changed somewhat. We still have the first
- * entry in both places, but now we download the address of
- * scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
- */
- for (i = 0; i < use_sg; i++)
- {
- unsigned int len = sg_dma_len(sg+i);
- scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
- scb->sg_list[i].length = cpu_to_le32(len);
- scb->sg_length += len;
- }
- /* Copy the first SG into the data pointer area. */
- hscb->data_pointer = scb->sg_list[0].address;
- hscb->data_count = scb->sg_list[0].length;
- scb->sg_count = i;
- hscb->SG_segment_count = i;
- hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
- }
- else
- {
- if (cmd->request_bufflen)
- {
- unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
- cmd->request_bufflen,
- scsi_to_pci_dma_dir(cmd->sc_data_direction));
- aic7xxx_mapping(cmd) = address;
- scb->sg_list[0].address = cpu_to_le32(address);
- scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
- scb->sg_count = 1;
- scb->sg_length = cmd->request_bufflen;
- hscb->SG_segment_count = 1;
- hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
- hscb->data_count = scb->sg_list[0].length;
- hscb->data_pointer = scb->sg_list[0].address;
- }
- else
- {
- scb->sg_count = 0;
- scb->sg_length = 0;
- hscb->SG_segment_count = 0;
- hscb->SG_list_pointer = 0;
- hscb->data_count = 0;
- hscb->data_pointer = 0;
- }
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_queue
- *
- * Description:
- * Queue a SCB to the controller.
- *-F*************************************************************************/
- int
- aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
- {
- struct aic7xxx_host *p;
- struct aic7xxx_scb *scb;
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- int tindex = TARGET_INDEX(cmd);
- #endif
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
- unsigned long cpu_flags = 0;
- #endif
- p = (struct aic7xxx_host *) cmd->host->hostdata;
- /*
- * Check to see if channel was scanned.
- */
-
- #ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
- {
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(INFO_LEAD "Scanning channel for devices.n",
- p->host_no, 0, -1, -1);
- p->flags |= AHC_A_SCANNED;
- }
- else
- {
- if (!(p->flags & AHC_B_SCANNED) && (cmd->channel == 1))
- {
- if (aic7xxx_verbose & VERBOSE_PROBE2)
- printk(INFO_LEAD "Scanning channel for devices.n",
- p->host_no, 1, -1, -1);
- p->flags |= AHC_B_SCANNED;
- }
- }
- if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1))
- {
- printk(WARN_LEAD "Commands queued exceeds queue "
- "depth, active=%dn",
- p->host_no, CTL_OF_CMD(cmd),
- p->dev_active_cmds[tindex]);
- if ( p->dev_active_cmds[tindex] > 220 )
- p->dev_active_cmds[tindex] = 0;
- }
- #endif
- scb = scbq_remove_head(&p->scb_data->free_scbs);
- if (scb == NULL)
- {
- DRIVER_LOCK
- aic7xxx_allocate_scb(p);
- DRIVER_UNLOCK
- scb = scbq_remove_head(&p->scb_data->free_scbs);
- if(scb == NULL)
- printk(WARN_LEAD "Couldn't get a free SCB.n", p->host_no,
- CTL_OF_CMD(cmd));
- }
- while (scb == NULL)
- {
- /*
- * Well, all SCBs are currently active on the bus. So, we spin here
- * running the interrupt handler until one completes and becomes free.
- * We can do this safely because we either A) hold the driver lock (in
- * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
- * kernels) and so either way, we won't take any other interrupts and
- * the queue path will block until we release it. Also, we would worry
- * about running the completion queues, but obviously there are plenty
- * of commands outstanding to trigger a later interrupt that will do
- * that for us, so skip it here.
- */
- DRIVER_LOCK
- aic7xxx_isr(p->irq, p, NULL);
- DRIVER_UNLOCK
- scb = scbq_remove_head(&p->scb_data->free_scbs);
- }
- scb->cmd = cmd;
- aic7xxx_position(cmd) = scb->hscb->tag;
- /*
- * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
- * is set up properly, and the parity error flag is reset, then send
- * the SCB to the sequencer and watch the fun begin.
- */
- cmd->scsi_done = fn;
- cmd->result = DID_OK;
- memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- aic7xxx_error(cmd) = DID_OK;
- aic7xxx_status(cmd) = 0;
- cmd->host_scribble = NULL;
- /*
- * Construct the SCB beforehand, so the sequencer is
- * paused a minimal amount of time.
- */
- aic7xxx_buildscb(p, cmd, scb);
- scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- DRIVER_LOCK
- scbq_insert_tail(&p->waiting_scbs, scb);
- if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
- {
- aic7xxx_run_waiting_queues(p);
- }
- DRIVER_UNLOCK
- return (0);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_bus_device_reset
- *
- * Description:
- * Abort or reset the current SCSI command(s). If the scb has not
- * previously been aborted, then we attempt to send a BUS_DEVICE_RESET
- * message to the target. If the scb has previously been unsuccessfully
- * aborted, then we will reset the channel and have all devices renegotiate.
- * Returns an enumerated type that indicates the status of the operation.
- *-F*************************************************************************/
- static int
- aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
- {
- struct aic7xxx_scb *scb;
- struct aic7xxx_hwscb *hscb;
- int result = -1;
- int channel;
- unsigned char saved_scbptr, lastphase;
- unsigned char hscb_index;
- int disconnected;
- scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
- hscb = scb->hscb;
- lastphase = aic_inb(p, LASTPHASE);
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- {
- printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
- p->host_no, CTL_OF_SCB(scb), scb->flags);
- switch (lastphase)
- {
- case P_DATAOUT:
- printk("Data-Out phasen");
- break;
- case P_DATAIN:
- printk("Data-In phasen");
- break;
- case P_COMMAND:
- printk("Command phasen");
- break;
- case P_MESGOUT:
- printk("Message-Out phasen");
- break;
- case P_STATUS:
- printk("Status phasen");
- break;
- case P_MESGIN:
- printk("Message-In phasen");
- break;
- default:
- /*
- * We're not in a valid phase, so assume we're idle.
- */
- printk("while idle, LASTPHASE = 0x%xn", lastphase);
- break;
- }
- printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
- "0x%xn", p->host_no, CTL_OF_SCB(scb),
- aic_inb(p, SCSISIGI),
- aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
- aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
- printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%xn", p->host_no,
- CTL_OF_SCB(scb),
- (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
- aic_inb(p, SSTAT2),
- aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
- aic_inb(p, STCNT));
- }
- channel = cmd->channel;
- /*
- * 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
- * abort message to the timed out target if it is disconnected.
- * Otherwise, if we have an active target we stuff the message buffer
- * with an abort message and assert ATN in the hopes that the target
- * will let go of the bus and go to the mesgout phase. If this
- * fails, we'll get another timeout a few seconds later which will
- * attempt a bus reset.
- */
- saved_scbptr = aic_inb(p, SCBPTR);
- disconnected = FALSE;
- if (lastphase != P_BUSFREE)
- {
- if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
- {
- printk(WARN_LEAD "Invalid SCB ID %d is active, "
- "SCB flags = 0x%x.n", p->host_no,
- CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
- return(SCSI_RESET_ERROR);
- }
- if (scb->hscb->tag == aic_inb(p, SCB_TAG))
- {
- if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
- {
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- printk(INFO_LEAD "Device reset message in "
- "message buffern", p->host_no, CTL_OF_SCB(scb));
- scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
- aic7xxx_error(scb->cmd) = DID_RESET;
- p->dev_flags[TARGET_INDEX(scb->cmd)] |=
- BUS_DEVICE_RESET_PENDING;
- /* Send the abort message to the active SCB. */
- aic_outb(p, HOST_MSG, MSG_OUT);
- aic_outb(p, lastphase | ATNO, SCSISIGO);
- return(SCSI_RESET_PENDING);
- }
- else
- {
- /* 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(WARN_LEAD "Device reset, Message buffer "
- "in usen", p->host_no, CTL_OF_SCB(scb));
- scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
- aic7xxx_error(scb->cmd) = DID_RESET;
- p->dev_flags[TARGET_INDEX(scb->cmd)] |=
- BUS_DEVICE_RESET_PENDING;
- return(SCSI_RESET_ERROR);
- }
- }
- } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
- hscb_index = aic7xxx_find_scb(p, scb);
- if (hscb_index == SCB_LIST_NULL)
- {
- disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
- }
- else
- {
- aic_outb(p, hscb_index, SCBPTR);
- if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
- {
- disconnected = TRUE;
- }
- }
- if (disconnected)
- {
- /*
- * Simply set the MK_MESSAGE flag and the SEQINT handler will do
- * the rest on a reconnect.
- */
- scb->hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
- p->dev_flags[TARGET_INDEX(scb->cmd)] |=
- BUS_DEVICE_RESET_PENDING;
- if (hscb_index != SCB_LIST_NULL)
- {
- unsigned char scb_control;
- aic_outb(p, hscb_index, SCBPTR);
- scb_control = aic_inb(p, SCB_CONTROL);
- aic_outb(p, scb_control | MK_MESSAGE, 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, then this will be the only
- * outstanding command and we can simply shove it on the
- * qoutfifo and be done. If it is tagged, then it goes right
- * in with all the others, no problem :) We need to add it
- * to the qinfifo and let the sequencer know it is there.
- * Now, the only problem left to deal with is, *IF* this
- * command completes, in spite of the MK_MESSAGE bit in the
- * control byte, then we need to pick that up in the interrupt
- * routine and clean things up. This *shouldn't* ever happen.
- */
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- printk(INFO_LEAD "Queueing device reset "
- "command.n", p->host_no, CTL_OF_SCB(scb));
- p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
- if (p->features & AHC_QUEUE_REGS)
- aic_outb(p, p->qinfifonext, HNSCB_QOFF);
- else
- aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
- scb->flags |= SCB_QUEUED_ABORT;
- result = SCSI_RESET_PENDING;
- }
- else if (result == -1)
- {
- result = SCSI_RESET_ERROR;
- }
- aic_outb(p, saved_scbptr, SCBPTR);
- return (result);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_panic_abort
- *
- * Description:
- * Abort the current SCSI command(s).
- *-F*************************************************************************/
- void
- aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
- {
- printk("aic7xxx driver version %s/%sn", AIC7XXX_C_VERSION,
- UTS_RELEASE);
- printk("Controller type:n %sn", board_names[p->board_name_index]);
- printk("p->flags=0x%lx, p->chip=0x%x, p->features=0x%x, "
- "sequencer %s pausedn",
- p->flags, p->chip, p->features,
- (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
- pause_sequencer(p);
- disable_irq(p->irq);
- aic7xxx_print_card(p);
- aic7xxx_print_scratch_ram(p);
- spin_unlock_irq(&io_request_lock);
- for(;;) barrier();
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_abort
- *
- * Description:
- * Abort the current SCSI command(s).
- *-F*************************************************************************/
- int
- aic7xxx_abort(Scsi_Cmnd *cmd)
- {
- struct aic7xxx_scb *scb = NULL;
- struct aic7xxx_host *p;
- int result, found=0;
- unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
- unsigned long cpu_flags = 0;
- #endif
- 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
- * useful 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, cmd);
- DRIVER_LOCK
- /*
- * 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.
- */
- pause_sequencer(p);
- while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
- {
- aic7xxx_isr(p->irq, p, (void *)NULL);
- pause_sequencer(p);
- }
- aic7xxx_done_cmds_complete(p);
- if (scb == NULL)
- {
- if (aic7xxx_verbose & VERBOSE_ABORT_MID)
- printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
- "pointer.n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- 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. */
- if (aic7xxx_verbose & VERBOSE_ABORT_MID)
- printk(INFO_LEAD "Abort called for already completed"
- " command.n", p->host_no, CTL_OF_CMD(cmd));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- 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, but
- * we also need to be aware of the possibility that we could be using
- * a faked negotiation command that is holding this command up, if
- * so we need to take care of that command instead, which means we
- * would then treat this one like it was sitting around disconnected
- * instead.
- * 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) )
- {
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "SCB aborted once already, "
- "escalating.n", p->host_no, CTL_OF_SCB(scb));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_ABORT_SNOOZE);
- }
- if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) ||
- (p->dev_flags[TARGET_INDEX(scb->cmd)] &
- BUS_DEVICE_RESET_PENDING) )
- {
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "Reset/Abort pending for this "
- "device, not wasting our time.n", p->host_no, CTL_OF_SCB(scb));
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_ABORT_PENDING);
- }
- found = 0;
- p->flags |= AHC_IN_ABORT;
- if (aic7xxx_verbose & VERBOSE_ABORT)
- {
- printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
- "0x%xn",
- p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
- aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
- aic_inb(p, LASTPHASE));
- printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%xn",
- p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
- aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
- aic_inb(p, SCSISIGI));
- printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%xn",
- p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
- aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
- }
- /*
- * 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 ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
- {
- /*
- * Check to see if the sequencer is just sitting on this command, or
- * if it's actively being run.
- */
- result = aic_inb(p, LASTPHASE);
- switch (result)
- {
- 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 & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "SCB is currently active. "
- "Waiting on completion.n", p->host_no, CTL_OF_SCB(scb));
- printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
- "0x%xn", p->host_no, CTL_OF_SCB(scb),
- aic_inb(p, SCSISIGI),
- aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
- aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
- printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%xn",
- p->host_no, CTL_OF_SCB(scb),
- (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
- aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
- aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
- unpause_sequencer(p, FALSE);
- p->flags &= ~AHC_IN_ABORT;
- scb->flags |= SCB_RECOVERY_SCB; /* Note the fact that we've been */
- p->flags |= AHC_ABORT_PENDING; /* here so we will know not to */
- DRIVER_UNLOCK /* muck with other SCBs if this */
- return(SCSI_ABORT_PENDING); /* one doesn't complete and clear */
- break; /* out. */
- default:
- break;
- }
- }
- if ((found == 0) && (scb->flags & SCB_WAITINGQ))
- {
- int tindex = TARGET_INDEX(cmd);
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "SCB found on waiting list and "
- "aborted.n", p->host_no, CTL_OF_SCB(scb));
- scbq_remove(&p->waiting_scbs, scb);
- scbq_remove(&p->delayed_scbs[tindex], scb);
- p->dev_active_cmds[tindex]++;
- p->activescbs++;
- scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
- scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
- found = 1;
- }
- /*
- * We just checked the waiting_q, now for the QINFIFO
- */
- if ( found == 0 )
- {
- if ( ((found = aic7xxx_search_qinfifo(p, cmd->target,
- cmd->channel,
- cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
- FALSE, NULL)) != 0) &&
- (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
- printk(INFO_LEAD "SCB found in QINFIFO and "
- "aborted.n", p->host_no, CTL_OF_SCB(scb));
- }
- /*
- * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card
- */
- if ( found == 0 )
- {
- unsigned char scb_next_ptr;
- prev_hscbptr = SCB_LIST_NULL;
- saved_hscbptr = aic_inb(p, SCBPTR);
- next_hscbptr = aic_inb(p, WAITING_SCBH);
- while ( next_hscbptr != SCB_LIST_NULL )
- {
- aic_outb(p, next_hscbptr, SCBPTR );
- if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
- {
- found = 1;
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "SCB found on hardware waiting"
- " list and aborted.n", p->host_no, CTL_OF_SCB(scb));
- if ( prev_hscbptr == SCB_LIST_NULL )
- {
- aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
- /* stop the selection since we just
- * grabbed the scb out from under the
- * card
- */
- aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
- aic_outb(p, CLRSELTIMEO, CLRSINT1);
- }
- else
- {
- scb_next_ptr = aic_inb(p, SCB_NEXT);
- aic_outb(p, prev_hscbptr, SCBPTR);
- aic_outb(p, scb_next_ptr, SCB_NEXT);
- aic_outb(p, next_hscbptr, SCBPTR);
- }
- aic_outb(p, SCB_LIST_NULL, SCB_TAG);
- aic_outb(p, 0, SCB_CONTROL);
- aic7xxx_add_curscb_to_free_list(p);
- scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
- break;
- }
- prev_hscbptr = next_hscbptr;
- next_hscbptr = aic_inb(p, SCB_NEXT);
- }
- aic_outb(p, saved_hscbptr, SCBPTR );
- }
-
- /*
- * 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 )
- {
- p->flags |= AHC_ABORT_PENDING;
- scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
- scb->hscb->control |= MK_MESSAGE;
- result=aic7xxx_find_scb(p, scb);
- if ( result != SCB_LIST_NULL )
- {
- saved_hscbptr = aic_inb(p, SCBPTR);
- aic_outb(p, result, SCBPTR);
- tmp_char = aic_inb(p, SCB_CONTROL);
- aic_outb(p, tmp_char | MK_MESSAGE, SCB_CONTROL);
- aic_outb(p, saved_hscbptr, SCBPTR);
- }
- if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
- printk(INFO_LEAD "SCB disconnected. Queueing Abort"
- " SCB.n", p->host_no, CTL_OF_SCB(scb));
- p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
- if (p->features & AHC_QUEUE_REGS)
- aic_outb(p, p->qinfifonext, HNSCB_QOFF);
- else
- aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
- }
- if (found)
- {
- aic7xxx_run_done_queue(p, TRUE);
- aic7xxx_run_waiting_queues(p);
- }
- p->flags &= ~AHC_IN_ABORT;
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- /*
- * 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);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_reset
- *
- * Description:
- * Resetting the bus always succeeds - is has to, otherwise the
- * kernel will panic! Try a surgical technique - sending a BUS
- * DEVICE RESET message - on the offending target before pulling
- * the SCSI bus reset line.
- *-F*************************************************************************/
- int
- aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
- {
- struct aic7xxx_scb *scb = NULL;
- struct aic7xxx_host *p;
- int tindex;
- int result = -1;
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
- unsigned long cpu_flags = 0;
- #endif
- #define DEVICE_RESET 0x01
- #define BUS_RESET 0x02
- #define HOST_RESET 0x04
- #define RESET_DELAY 0x08
- int action;
- if ( cmd == NULL )
- {
- printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
- "pointer, failing.n");
- return(SCSI_RESET_SNOOZE);
- }
- p = (struct aic7xxx_host *) cmd->host->hostdata;
- 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
- * useful 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, cmd);
- DRIVER_LOCK
- pause_sequencer(p);
- if(flags & SCSI_RESET_SYNCHRONOUS)
- {
- if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
- "cmd->result 0x%x.n", p->host_no, CTL_OF_CMD(cmd), flags,
- cmd->result);
- scb = NULL;
- action = HOST_RESET;
- }
- else if ((scb == NULL) || (scb->cmd != cmd))
- {
- if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
- "->SCB mapping, failing.n", p->host_no, CTL_OF_CMD(cmd));
- aic7xxx_done_cmds_complete(p);
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_NOT_RUNNING);
- }
- else
- {
- if (aic7xxx_verbose & VERBOSE_RESET_MID)
- printk(INFO_LEAD "Reset called, scb %d, flags "
- "0x%xn", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
- if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
- {
- action = HOST_RESET;
- }
- else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
- {
- action = BUS_RESET;
- }
- else
- {
- action = DEVICE_RESET;
- }
- }
- while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
- {
- aic7xxx_isr(p->irq, p, (void *)NULL );
- pause_sequencer(p);
- }
- aic7xxx_done_cmds_complete(p);
- if(scb && (scb->cmd == NULL))
- {
- /*
- * We just completed the command when we ran the isr stuff, so we no
- * longer have it.
- */
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- return(SCSI_RESET_SUCCESS);
- }
-
- if ( (action & DEVICE_RESET) &&
- (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
- {
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- printk(INFO_LEAD "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 & VERBOSE_RESET_PROCESS)
- {
- printk(INFO_LEAD "Have already attempted to reach "
- "device with queuedn", p->host_no, CTL_OF_CMD(cmd));
- printk(INFO_LEAD "message, will escalate to bus "
- "reset.n", p->host_no, CTL_OF_CMD(cmd));
- }
- action = BUS_RESET;
- }
- if ( (action & DEVICE_RESET) &&
- (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
- {
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- printk(INFO_LEAD "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->features & AHC_TWIN) )
- {
- action = HOST_RESET;
- }
- if ( (p->dev_flags[tindex] & DEVICE_RESET_DELAY) &&
- !(action & (HOST_RESET | BUS_RESET)))
- {
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- {
- printk(INFO_LEAD "Reset called too soon after last "
- "reset without requestingn", p->host_no, CTL_OF_CMD(cmd));
- printk(INFO_LEAD "bus or host reset, escalating.n", p->host_no,
- CTL_OF_CMD(cmd));
- }
- action = BUS_RESET;
- }
- if ( (p->flags & AHC_RESET_DELAY) &&
- (action & (HOST_RESET | BUS_RESET)) )
- {
- if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
- printk(INFO_LEAD "Reset called too soon after "
- "last bus reset, delaying.n", p->host_no, CTL_OF_CMD(cmd));
- action = RESET_DELAY;
- }
- /*
- * 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:
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- if(scb == NULL)
- return(SCSI_RESET_PUNT);
- else
- return(SCSI_RESET_PENDING);
- break;
- case DEVICE_RESET:
- p->flags |= AHC_IN_RESET;
- result = aic7xxx_bus_device_reset(p, cmd);
- aic7xxx_run_done_queue(p, TRUE);
- /* We can't rely on run_waiting_queues to unpause the sequencer for
- * PCI based controllers since we use AAP */
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- p->flags &= ~AHC_IN_RESET;
- DRIVER_UNLOCK
- return(result);
- break;
- case BUS_RESET:
- case HOST_RESET:
- default:
- p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
- p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
- p->dev_timer_active |= (0x01 << p->scsi_id);
- if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
- time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
- {
- mod_timer(&p->dev_timer, p->dev_expires[p->scsi_id]);
- p->dev_timer_active |= (0x01 << MAX_TARGETS);
- }
- aic7xxx_reset_channel(p, cmd->channel, TRUE);
- if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
- {
- aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
- restart_sequencer(p);
- }
- if (action != HOST_RESET)
- result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
- else
- {
- result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
- 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;
- p->msg_len = 0;
- }
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
- if(flags & SCSI_RESET_SYNCHRONOUS)
- {
- cmd->result = DID_RESET << 16;
- cmd->done(cmd);
- }
- #endif
- aic7xxx_run_done_queue(p, TRUE);
- p->flags &= ~AHC_IN_RESET;
- /*
- * We can't rely on run_waiting_queues to unpause the sequencer for
- * PCI based controllers since we use AAP. NOTE: this also sets
- * the timer for the one command we might have queued in the case
- * of a synch reset.
- */
- aic7xxx_run_waiting_queues(p);
- unpause_sequencer(p, FALSE);
- DRIVER_UNLOCK
- if(scb == NULL)
- return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
- else
- return(result);
- break;
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_biosparam
- *
- * Description:
- * Return the disk geometry for the given SCSI device.
- *-F*************************************************************************/
- int
- aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
- {
- int heads, sectors, cylinders, ret;
- struct aic7xxx_host *p;
- struct buffer_head *bh;
- p = (struct aic7xxx_host *) disk->device->host->hostdata;
- bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev));
- if ( bh )
- {
- ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
- brelse(bh);
- if ( ret != -1 )
- return(ret);
- }
-
- heads = 64;
- sectors = 32;
- cylinders = disk->capacity / (heads * sectors);
- if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
- {
- heads = 255;
- sectors = 63;
- cylinders = disk->capacity / (heads * sectors);
- }
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
- return (0);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_release
- *
- * Description:
- * Free the passed in Scsi_Host memory structures prior to unloading the
- * module.
- *-F*************************************************************************/
- int
- aic7xxx_release(struct Scsi_Host *host)
- {
- struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
- struct aic7xxx_host *next, *prev;
- if(p->irq)
- free_irq(p->irq, p);
- if(p->base)
- release_region(p->base, MAXREG - MINREG);
- #ifdef MMAPIO
- if(p->maddr)
- {
- iounmap((void *) (((unsigned long) p->maddr) & PAGE_MASK));
- }
- #endif /* MMAPIO */
- prev = NULL;
- next = first_aic7xxx;
- while(next != NULL)
- {
- if(next == p)
- {
- if(prev == NULL)
- first_aic7xxx = next->next;
- else
- prev->next = next->next;
- }
- else
- {
- prev = next;
- }
- next = next->next;
- }
- aic7xxx_free(p);
- return(0);
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_print_card
- *
- * Description:
- * Print out all of the control registers on the card
- *
- * NOTE: This function is not yet safe for use on the VLB and EISA
- * controllers, so it isn't used on those controllers at all.
- *-F*************************************************************************/
- static void
- aic7xxx_print_card(struct aic7xxx_host *p)
- {
- int i, j, k, chip;
- static struct register_ranges {
- int num_ranges;
- int range_val[32];
- } cards_ds[] = {
- { 0, {0,} }, /* none */
- {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/
- 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} },
- { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/
- 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
- { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/
- 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
- {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/
- 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
- {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/
- 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
- {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/
- 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
- 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
- 0xfe, 0xff} },
- {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/
- 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a,
- 0x9f, 0x9f, 0xe0, 0xf1} },
- {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/
- 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
- 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
- 0xfe, 0xff} },
- {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
- 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
- 0xe0, 0xf1, 0xf4, 0xfc} },
- {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
- 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
- 0xe0, 0xf1, 0xf4, 0xfc} },
- };
- chip = p->chip & AHC_CHIPID_MASK;
- printk("%s at ",
- board_names[p->board_name_index]);
- switch(p->chip & ~AHC_CHIPID_MASK)
- {
- case AHC_VL:
- printk("VLB Slot %d.n", p->pci_device_fn);
- break;
- case AHC_EISA:
- printk("EISA Slot %d.n", p->pci_device_fn);
- break;
- case AHC_PCI:
- default:
- printk("PCI %d/%d/%d.n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
- PCI_FUNC(p->pci_device_fn));
- break;
- }
- /*
- * the registers on the card....
- */
- printk("Card Dump:n");
- k = 0;
- for(i=0; i<cards_ds[chip].num_ranges; i++)
- {
- for(j = cards_ds[chip].range_val[ i * 2 ];
- j <= cards_ds[chip].range_val[ i * 2 + 1 ] ;
- j++)
- {
- printk("%02x:%02x ", j, aic_inb(p, j));
- if(++k == 13)
- {
- printk("n");
- k=0;
- }
- }
- }
- if(k != 0)
- printk("n");
- /*
- * If this was an Ultra2 controller, then we just hosed the card in terms
- * of the QUEUE REGS. This function is only called at init time or by
- * the panic_abort function, so it's safe to assume a generic init time
- * setting here
- */
- if(p->features & AHC_QUEUE_REGS)
- {
- aic_outb(p, 0, SDSCB_QOFF);
- aic_outb(p, 0, SNSCB_QOFF);
- aic_outb(p, 0, HNSCB_QOFF);
- }
- }
- /*+F*************************************************************************
- * Function:
- * aic7xxx_print_scratch_ram
- *
- * Description:
- * Print out the scratch RAM values on the card.
- *-F*************************************************************************/
- static void
- aic7xxx_print_scratch_ram(struct aic7xxx_host *p)
- {
- int i, k;
- k = 0;
- printk("Scratch RAM:n");
- for(i = SRAM_BASE; i < SEQCTL; i++)
- {
- printk("%02x:%02x ", i, aic_inb(p, i));
- if(++k == 13)
- {
- printk("n");
- k=0;
- }
- }
- if (p->features & AHC_MORE_SRAM)
- {
- for(i = TARG_OFFSET; i < 0x80; i++)
- {
- printk("%02x:%02x ", i, aic_inb(p, i));
- if(++k == 13)
- {
- printk("n");
- k=0;
- }
- }
- }
- printk("n");
- }
- #include "aic7xxx_old/aic7xxx_proc.c"
- MODULE_LICENSE("Dual BSD/GPL");
- /* Eventually this will go into an include file, but this will be later */
- static Scsi_Host_Template driver_template = AIC7XXX;
- #include "scsi_module.c"
- /*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 2
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -2
- * c-argdecl-indent: 2
- * c-label-offset: -2
- * c-continued-statement-offset: 2
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */