/* * Read the 284x SEEPROM. */ static int aha2840_load_seeprom(struct ahc_softc *ahc) { struct seeprom_descriptor sd; struct seeprom_config *sc; int have_seeprom; uint8_t scsi_conf; sd.sd_ahc = ahc; sd.sd_control_offset = SEECTL_2840; sd.sd_status_offset = STATUS_2840; sd.sd_dataout_offset = STATUS_2840; sd.sd_chip = C46; sd.sd_MS = 0; sd.sd_RDY = EEPROM_TF; sd.sd_CS = CS_2840; sd.sd_CK = CK_2840; sd.sd_DO = DO_2840; sd.sd_DI = DI_2840; sc = ahc->seep_config; if (bootverbose) printf("%s: Reading SEEPROM...", ahc_name(ahc)); have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc, /*start_addr*/0, sizeof(sc)/2); if (have_seeprom) { if (ahc_verify_cksum(sc) == 0) { if(bootverbose) printf ("checksum error\n"); have_seeprom = 0; } else if (bootverbose) { printf("done.\n"); } } if (!have_seeprom) { if (bootverbose) printf("%s: No SEEPROM available\n", ahc_name(ahc)); ahc->flags |= AHC_USEDEFAULTS; } else { /* * Put the data we've collected down into SRAM * where ahc_init will find it. */ int i; int max_targ; uint16_t discenable; max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; discenable = 0; for (i = 0; i < max_targ; i++){ uint8_t target_settings; target_settings = (sc->device_flags[i] & CFXFER) << 4; if (sc->device_flags[i] & CFSYNCH) target_settings |= SOFS; if (sc->device_flags[i] & CFWIDEB) target_settings |= WIDEXFER; if (sc->device_flags[i] & CFDISC) discenable |= (0x01 << i); ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); } ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); ahc->our_id = sc->brtime_id & CFSCSIID; scsi_conf = (ahc->our_id & 0x7); if (sc->adapter_control & CFSPARITY) scsi_conf |= ENSPCHK; if (sc->adapter_control & CFRESETB) scsi_conf |= RESET_SCSI; if (sc->bios_control & CF284XEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; /* Set SCSICONF info */ ahc_outb(ahc, SCSICONF, scsi_conf); if (sc->adapter_control & CF284XSTERM) ahc->flags |= AHC_TERM_ENB_A; } return (have_seeprom); }
void ahc_isa_attach(struct device *parent, struct device *self, void *aux) { struct ahc_softc *ahc = (void *)self; struct isa_attach_args *ia = aux; bus_space_tag_t iot = ia->ia_iot; bus_space_handle_t ioh; int irq; char idstring[EISA_IDSTRINGLEN]; const char *model; u_int intdef; ahc_set_name(ahc, ahc->sc_dev.dv_xname); ahc_set_unit(ahc, ahc->sc_dev.dv_unit); /* set dma tags */ ahc->parent_dmat = ia->ia_dmat; ahc->chip = AHC_VL; /* We are a VL Bus Controller */ if (bus_space_map(iot, ia->ia_iobase, ia->ia_iosize, 0, &ioh)) panic("ahc_isa_attach: can't map slot i/o addresses"); if (!ahc_isa_idstring(iot, ioh, idstring)) panic("ahc_isa_attach: could not read ID string"); if ((irq = ahc_isa_irq(iot, ioh)) < 0) panic("ahc_isa_attach: ahc_isa_irq failed!"); if (strcmp(idstring, "ADP7756") == 0) { model = EISA_PRODUCT_ADP7756; } else if (strcmp(idstring, "ADP7757") == 0) { model = EISA_PRODUCT_ADP7757; } else { panic("ahc_isa_attach: Unknown device type %s", idstring); } printf(": %s\n", model); ahc->channel = 'A'; ahc->chip = AHC_AIC7770; ahc->features = AHC_AIC7770_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG; ahc->flags |= AHC_PAGESCBS; /* set tag and handle */ ahc->tag = iot; ahc->bsh = ioh; #ifdef DEBUG /* * Tell the user what type of interrupts we're using. * useful for debugging irq problems */ printf( "%s: Using %s Interrupts\n", ahc_name(ahc), ahc->pause & IRQMS ? "Level Sensitive" : "Edge Triggered"); #endif if (ahc_reset(ahc, /*reinit*/FALSE) != 0) return; /* See if we are edge triggered */ intdef = ahc_inb(ahc, INTDEF); if ((intdef & EDGE_TRIG) != 0) ahc->flags |= AHC_EDGE_INTERRUPT; /* * Now that we know we own the resources we need, do the * card initialization. */ aha2840_load_seeprom(ahc); /* * See if we have a Rev E or higher aic7770. Anything below a * Rev E will have a R/O autoflush disable configuration bit. * It's still not clear exactly what is differenent about the Rev E. * We think it allows 8 bit entries in the QOUTFIFO to support * "paging" SCBs so you can have more than 4 commands active at * once. */ { char *id_string; u_char sblkctl; u_char sblkctl_orig; sblkctl_orig = ahc_inb(ahc, SBLKCTL); sblkctl = sblkctl_orig ^ AUTOFLUSHDIS; ahc_outb(ahc, SBLKCTL, sblkctl); sblkctl = ahc_inb(ahc, SBLKCTL); if(sblkctl != sblkctl_orig) { id_string = "aic7770 >= Rev E, "; /* * Ensure autoflush is enabled */ sblkctl &= ~AUTOFLUSHDIS; ahc_outb(ahc, SBLKCTL, sblkctl); /* Allow paging on this adapter */ ahc->flags |= AHC_PAGESCBS; } else id_string = "aic7770 <= Rev C, "; printf("%s: %s", ahc_name(ahc), id_string); } /* Setup the FIFO threshold and the bus off time */ { u_char hostconf = ahc_inb(ahc, HOSTCONF); ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); } /* * Generic aic7xxx initialization. */ if(ahc_init(ahc)){ ahc_free(ahc); return; } /* * Link this softc in with all other ahc instances. */ ahc_softc_insert(ahc); /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); /* * The IRQMS bit enables level sensitive interrupts only allow * IRQ sharing if its set. */ ahc->ih = isa_intr_establish(ia->ia_ic, irq, ahc->pause & IRQMS ? IST_LEVEL : IST_EDGE, IPL_BIO, ahc_platform_intr, ahc, ahc->sc_dev.dv_xname); if (ahc->ih == NULL) { printf("%s: couldn't establish interrupt\n", ahc->sc_dev.dv_xname); ahc_free(ahc); return; } ahc_intr_enable(ahc, TRUE); /* Attach sub-devices - always succeeds */ ahc_attach(ahc); }
void ahc_cardbus_attach(device_t parent, device_t self, void *aux) { struct cardbus_attach_args *ca = aux; struct ahc_cardbus_softc *csc = device_private(self); struct ahc_softc *ahc = &csc->sc_ahc; cardbus_devfunc_t ct = ca->ca_ct; bus_space_tag_t bst; bus_space_handle_t bsh; pcireg_t reg; u_int sxfrctl1 = 0; u_char sblkctl; ahc->sc_dev = self; csc->sc_ct = ct; csc->sc_tag = ca->ca_tag; printf(": Adaptec ADP-1480 SCSI\n"); /* * Map the device. */ csc->sc_csr = PCI_COMMAND_MASTER_ENABLE; if (Cardbus_mapreg_map(csc->sc_ct, AHC_CARDBUS_MMBA, PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0, &bst, &bsh, NULL, &csc->sc_size) == 0) { csc->sc_bar = AHC_CARDBUS_MMBA; csc->sc_csr |= PCI_COMMAND_MEM_ENABLE; } else if (Cardbus_mapreg_map(csc->sc_ct, AHC_CARDBUS_IOBA, PCI_MAPREG_TYPE_IO, 0, &bst, &bsh, NULL, &csc->sc_size) == 0) { csc->sc_bar = AHC_CARDBUS_IOBA; csc->sc_csr |= PCI_COMMAND_IO_ENABLE; } else { csc->sc_bar = 0; aprint_error("%s: unable to map device registers\n", ahc_name(ahc)); return; } /* Enable the appropriate bits in the PCI CSR. */ reg = Cardbus_conf_read(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG); reg &= ~(PCI_COMMAND_IO_ENABLE|PCI_COMMAND_MEM_ENABLE); reg |= csc->sc_csr; Cardbus_conf_write(ct, ca->ca_tag, PCI_COMMAND_STATUS_REG, reg); /* * Make sure the latency timer is set to some reasonable * value. */ reg = Cardbus_conf_read(ct, ca->ca_tag, PCI_BHLC_REG); if (PCI_LATTIMER(reg) < 0x20) { reg &= ~(PCI_LATTIMER_MASK << PCI_LATTIMER_SHIFT); reg |= (0x20 << PCI_LATTIMER_SHIFT); Cardbus_conf_write(ct, ca->ca_tag, PCI_BHLC_REG, reg); } ahc_set_name(ahc, device_xname(ahc->sc_dev)); ahc->parent_dmat = ca->ca_dmat; ahc->tag = bst; ahc->bsh = bsh; /* * ADP-1480 is always an AIC-7860. */ ahc->chip = AHC_AIC7860 | AHC_PCI; ahc->features = AHC_AIC7860_FE|AHC_REMOVABLE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; if (PCI_REVISION(ca->ca_class) >= 1) ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; if (ahc_softc_init(ahc) != 0) return; /* * On all CardBus adapters, we allow SCB paging. */ ahc->flags = AHC_PAGESCBS; ahc->channel = 'A'; ahc_intr_enable(ahc, FALSE); ahc_reset(ahc); /* * Establish the interrupt. */ ahc->ih = Cardbus_intr_establish(ct, IPL_BIO, ahc_intr, ahc); if (ahc->ih == NULL) { aprint_error("%s: unable to establish interrupt\n", ahc_name(ahc)); return; } ahc->seep_config = malloc(sizeof(*ahc->seep_config), M_DEVBUF, M_NOWAIT); if (ahc->seep_config == NULL) return; ahc_check_extport(ahc, &sxfrctl1); /* * Take the LED out of diagnostic mode. */ sblkctl = ahc_inb(ahc, SBLKCTL); ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); /* * I don't know where this is set in the SEEPROM or by the * BIOS, so we default to 100%. */ ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100); if (ahc->flags & AHC_USEDEFAULTS) { int our_id; /* * Assume only one connector and always turn * on termination. */ our_id = AHC_CARDBUS_DEFAULT_SCSI_ID; sxfrctl1 = STPWEN; ahc_outb(ahc, SCSICONF, our_id | ENSPCHK | RESET_SCSI); ahc->our_id = our_id; } printf("%s: aic7860", ahc_name(ahc)); /* * Record our termination setting for the * generic initialization routine. */ if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; if (ahc_init(ahc)) { ahc_free(ahc); return; } ahc_attach(ahc); }
int ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) { u_int command; u_int our_id; u_int sxfrctl1; u_int scsiseq; u_int dscommand0; uint32_t devconfig; int error; uint8_t sblkctl; our_id = 0; error = entry->setup(ahc); if (error != 0) return (error); ahc->chip |= AHC_PCI; ahc->description = entry->name; pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0); error = ahc_pci_map_registers(ahc); if (error != 0) return (error); ahc_intr_enable(ahc, FALSE); devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { if (bootverbose) printf("%s: Enabling 39Bit Addressing\n", ahc_name(ahc)); devconfig |= DACEN; } devconfig |= PCIERRGENDIS; ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4); command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 2); command |= PCIM_CMD_BUSMASTEREN; ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 2); ahc->flags |= AHC_PAGESCBS; error = ahc_softc_init(ahc); if (error != 0) return (error); if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) ahc->seqctl |= FAILDIS; ahc->bus_intr = ahc_pci_intr; ahc->bus_chip_init = ahc_pci_chip_init; if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { ahc_pause(ahc); if ((ahc->features & AHC_ULTRA2) != 0) our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; else our_id = ahc_inb(ahc, SCSIID) & OID; sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN; scsiseq = ahc_inb(ahc, SCSISEQ); } else { sxfrctl1 = STPWEN; our_id = 7; scsiseq = 0; } error = ahc_reset(ahc, FALSE); if (error != 0) return (ENXIO); if ((ahc->features & AHC_DT) != 0) { u_int sfunct; sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS); ahc_outb(ahc, SFUNCT, sfunct); ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN |TARGCRCENDEN); } dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { dscommand0 &= ~DPARCKEN; } if ((ahc->bugs & AHC_CACHETHEN_DIS_BUG) != 0) dscommand0 |= CACHETHEN; if ((ahc->bugs & AHC_CACHETHEN_BUG) != 0) dscommand0 &= ~CACHETHEN; ahc_outb(ahc, DSCOMMAND0, dscommand0); ahc->pci_cachesize = ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, 1) & CACHESIZE; ahc->pci_cachesize *= 4; if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0 && ahc->pci_cachesize == 4) { ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, 0, 1); ahc->pci_cachesize = 0; } if ((ahc->features & AHC_ULTRA) != 0) { uint32_t devconfig; devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); if ((devconfig & REXTVALID) == 0) ahc->features &= ~AHC_ULTRA; } check_extport(ahc, &sxfrctl1); sblkctl = ahc_inb(ahc, SBLKCTL); ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); if ((ahc->features & AHC_ULTRA2) != 0) { ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_MAX|WR_DFTHRSH_MAX); } else { ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100); } if (ahc->flags & AHC_USEDEFAULTS) { if ((ahc->flags & AHC_NO_BIOS_INIT) == 0 && scsiseq != 0) { printf("%s: Using left over BIOS settings\n", ahc_name(ahc)); ahc->flags &= ~AHC_USEDEFAULTS; ahc->flags |= AHC_BIOS_ENABLED; } else { our_id = 0x07; sxfrctl1 = STPWEN; } ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI); ahc->our_id = our_id; } ahc_probe_ext_scbram(ahc); if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; ahc->bus_softc.pci_softc.devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); ahc->bus_softc.pci_softc.command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 1); ahc->bus_softc.pci_softc.csize_lattime = ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, 1); ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0); ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS); if ((ahc->features & AHC_DT) != 0) { u_int sfunct; sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE); ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT); ahc_outb(ahc, SFUNCT, sfunct); ahc->bus_softc.pci_softc.crccontrol1 = ahc_inb(ahc, CRCCONTROL1); } if ((ahc->features & AHC_MULTI_FUNC) != 0) ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR); if ((ahc->features & AHC_ULTRA2) != 0) ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH); error = ahc_init(ahc); if (error != 0) return (error); ahc->init_level++; return ahc_pci_map_int(ahc); }
static void ahc_probe_ext_scbram(struct ahc_softc *ahc) { int num_scbs; int test_num_scbs; int enable; int pcheck; int fast; int large; enable = FALSE; pcheck = FALSE; fast = FALSE; large = FALSE; num_scbs = 0; if (ahc_ext_scbram_present(ahc) == 0) goto done; ahc_scbram_config(ahc, TRUE, pcheck, fast, large); num_scbs = ahc_probe_scbs(ahc); if (num_scbs == 0) { goto done; } enable = TRUE; ahc_outb(ahc, SEQCTL, 0); ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); ahc_scbram_config(ahc, enable, TRUE, fast, large); num_scbs = ahc_probe_scbs(ahc); if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 || (ahc_inb(ahc, ERROR) & MPARERR) == 0) pcheck = TRUE; ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); ahc_scbram_config(ahc, enable, pcheck, TRUE, large); test_num_scbs = ahc_probe_scbs(ahc); if (test_num_scbs == num_scbs && ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 || (ahc_inb(ahc, ERROR) & MPARERR) == 0)) fast = TRUE; if ((ahc->features & AHC_LARGE_SCBS) != 0) { ahc_scbram_config(ahc, enable, pcheck, fast, TRUE); test_num_scbs = ahc_probe_scbs(ahc); if (test_num_scbs >= num_scbs) { large = TRUE; num_scbs = test_num_scbs; if (num_scbs >= 64) { ahc->flags |= AHC_SCB_BTT; } } } done: ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); if (bootverbose && enable) { printf("%s: External SRAM, %s access%s, %dbytes/SCB\n", ahc_name(ahc), fast ? "fast" : "slow", pcheck ? ", parity checking enabled" : "", large ? 64 : 32); } ahc_scbram_config(ahc, enable, pcheck, fast, large); }
static void ahc_pci_intr(struct ahc_softc *ahc) { u_int error; u_int status1; error = ahc_inb(ahc, ERROR); if ((error & PCIERRSTAT) == 0) return; status1 = ahc_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, 1); printf("%s: PCI error Interrupt at seqaddr = 0x%x\n", ahc_name(ahc), ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); if (status1 & DPE) { ahc->pci_target_perr_count++; printf("%s: Data Parity Error Detected during address " "or write data phase\n", ahc_name(ahc)); } if (status1 & SSE) { printf("%s: Signal System Error Detected\n", ahc_name(ahc)); } if (status1 & RMA) { printf("%s: Received a Master Abort\n", ahc_name(ahc)); } if (status1 & RTA) { printf("%s: Received a Target Abort\n", ahc_name(ahc)); } if (status1 & STA) { printf("%s: Signaled a Target Abort\n", ahc_name(ahc)); } if (status1 & DPR) { printf("%s: Data Parity Error has been reported via PERR#\n", ahc_name(ahc)); } ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, status1, 1); if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) { printf("%s: Latched PCIERR interrupt with " "no status bits set\n", ahc_name(ahc)); } else { ahc_outb(ahc, CLRINT, CLRPARERR); } if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) { printf( "%s: WARNING WARNING WARNING WARNING\n" "%s: Too many PCI parity errors observed as a target.\n" "%s: Some device on this bus is generating bad parity.\n" "%s: This is an error *observed by*, not *generated by*, this controller.\n" "%s: PCI parity error checking has been disabled.\n" "%s: WARNING WARNING WARNING WARNING\n", ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc)); ahc->seqctl |= FAILDIS; ahc_outb(ahc, SEQCTL, ahc->seqctl); } ahc_unpause(ahc); }
static void configure_termination(struct ahc_softc *ahc, struct seeprom_descriptor *sd, u_int adapter_control, u_int *sxfrctl1) { uint8_t brddat; brddat = 0; *sxfrctl1 = 0; SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); if ((adapter_control & CFAUTOTERM) != 0 || (ahc->features & AHC_NEW_TERMCTL) != 0) { int internal50_present; int internal68_present; int externalcable_present; int eeprom_present; int enableSEC_low; int enableSEC_high; int enablePRI_low; int enablePRI_high; int sum; enableSEC_low = 0; enableSEC_high = 0; enablePRI_low = 0; enablePRI_high = 0; if ((ahc->features & AHC_NEW_TERMCTL) != 0) { ahc_new_term_detect(ahc, &enableSEC_low, &enableSEC_high, &enablePRI_low, &enablePRI_high, &eeprom_present); if ((adapter_control & CFSEAUTOTERM) == 0) { if (bootverbose) printf("%s: Manual SE Termination\n", ahc_name(ahc)); enableSEC_low = (adapter_control & CFSELOWTERM); enableSEC_high = (adapter_control & CFSEHIGHTERM); } if ((adapter_control & CFAUTOTERM) == 0) { if (bootverbose) printf("%s: Manual LVD Termination\n", ahc_name(ahc)); enablePRI_low = (adapter_control & CFSTERM); enablePRI_high = (adapter_control & CFWSTERM); } internal50_present = 0; internal68_present = 1; externalcable_present = 1; } else if ((ahc->features & AHC_SPIOCAP) != 0) { aic785X_cable_detect(ahc, &internal50_present, &externalcable_present, &eeprom_present); internal68_present = 0; } else { aic787X_cable_detect(ahc, &internal50_present, &internal68_present, &externalcable_present, &eeprom_present); } if ((ahc->features & AHC_WIDE) == 0) internal68_present = 0; if (bootverbose && (ahc->features & AHC_ULTRA2) == 0) { printf("%s: internal 50 cable %s present", ahc_name(ahc), internal50_present ? "is":"not"); if ((ahc->features & AHC_WIDE) != 0) printf(", internal 68 cable %s present", internal68_present ? "is":"not"); printf("\n%s: external cable %s present\n", ahc_name(ahc), externalcable_present ? "is":"not"); } if (bootverbose) printf("%s: BIOS eeprom %s present\n", ahc_name(ahc), eeprom_present ? "is" : "not"); if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { internal50_present = 0; } if ((ahc->features & AHC_ULTRA2) == 0 && (internal50_present != 0) && (internal68_present != 0) && (externalcable_present != 0)) { printf("%s: Illegal cable configuration!!. " "Only two connectors on the " "adapter may be used at a " "time!\n", ahc_name(ahc)); internal50_present = 0; internal68_present = 0; externalcable_present = 0; } if ((ahc->features & AHC_WIDE) != 0 && ((externalcable_present == 0) || (internal68_present == 0) || (enableSEC_high != 0))) { brddat |= BRDDAT6; if (bootverbose) { if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) printf("%s: 68 pin termination " "Enabled\n", ahc_name(ahc)); else printf("%s: %sHigh byte termination " "Enabled\n", ahc_name(ahc), enableSEC_high ? "Secondary " : ""); } } sum = internal50_present + internal68_present + externalcable_present; if (sum < 2 || (enableSEC_low != 0)) { if ((ahc->features & AHC_ULTRA2) != 0) brddat |= BRDDAT5; else *sxfrctl1 |= STPWEN; if (bootverbose) { if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) printf("%s: 50 pin termination " "Enabled\n", ahc_name(ahc)); else printf("%s: %sLow byte termination " "Enabled\n", ahc_name(ahc), enableSEC_low ? "Secondary " : ""); } } if (enablePRI_low != 0) { *sxfrctl1 |= STPWEN; if (bootverbose) printf("%s: Primary Low Byte termination " "Enabled\n", ahc_name(ahc)); } ahc_outb(ahc, SXFRCTL1, *sxfrctl1); if (enablePRI_high != 0) { brddat |= BRDDAT4; if (bootverbose) printf("%s: Primary High Byte " "termination Enabled\n", ahc_name(ahc)); } write_brdctl(ahc, brddat); } else { if ((adapter_control & CFSTERM) != 0) { *sxfrctl1 |= STPWEN; if (bootverbose) printf("%s: %sLow byte termination Enabled\n", ahc_name(ahc), (ahc->features & AHC_ULTRA2) ? "Primary " : ""); } if ((adapter_control & CFWSTERM) != 0 && (ahc->features & AHC_WIDE) != 0) { brddat |= BRDDAT6; if (bootverbose) printf("%s: %sHigh byte termination Enabled\n", ahc_name(ahc), (ahc->features & AHC_ULTRA2) ? "Secondary " : ""); } ahc_outb(ahc, SXFRCTL1, *sxfrctl1); if ((ahc->features & AHC_WIDE) != 0) write_brdctl(ahc, brddat); } SEEPROM_OUTB(sd, sd->sd_MS); }
static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) { struct seeprom_descriptor sd; struct seeprom_config *sc; int have_seeprom; int have_autoterm; sd.sd_ahc = ahc; sd.sd_control_offset = SEECTL; sd.sd_status_offset = SEECTL; sd.sd_dataout_offset = SEECTL; sc = ahc->seep_config; if (ahc->flags & AHC_LARGE_SEEPROM) sd.sd_chip = C56_66; else sd.sd_chip = C46; sd.sd_MS = SEEMS; sd.sd_RDY = SEERDY; sd.sd_CS = SEECS; sd.sd_CK = SEECK; sd.sd_DO = SEEDO; sd.sd_DI = SEEDI; have_seeprom = ahc_acquire_seeprom(ahc, &sd); if (have_seeprom) { if (bootverbose) printf("%s: Reading SEEPROM...", ahc_name(ahc)); for (;;) { u_int start_addr; start_addr = 32 * (ahc->channel - 'A'); have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc, start_addr, sizeof(*sc)/2); if (have_seeprom) have_seeprom = ahc_verify_cksum(sc); if (have_seeprom != 0 || sd.sd_chip == C56_66) { if (bootverbose) { if (have_seeprom == 0) printf ("checksum error\n"); else printf ("done.\n"); } break; } sd.sd_chip = C56_66; } ahc_release_seeprom(&sd); if (sd.sd_chip == C56_66) ahc->flags |= AHC_LARGE_SEEPROM; } if (!have_seeprom) { ahc_outb(ahc, SCBPTR, 2); if (ahc_inb(ahc, SCB_BASE) == 'A' && ahc_inb(ahc, SCB_BASE + 1) == 'D' && ahc_inb(ahc, SCB_BASE + 2) == 'P' && ahc_inb(ahc, SCB_BASE + 3) == 'T') { uint16_t *sc_data; int i; sc_data = (uint16_t *)sc; for (i = 0; i < 32; i++, sc_data++) { int j; j = i * 2; *sc_data = ahc_inb(ahc, SRAM_BASE + j) | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; } have_seeprom = ahc_verify_cksum(sc); if (have_seeprom) ahc->flags |= AHC_SCB_CONFIG_USED; } ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); } if (!have_seeprom) { if (bootverbose) printf("%s: No SEEPROM available.\n", ahc_name(ahc)); ahc->flags |= AHC_USEDEFAULTS; free(ahc->seep_config, M_DEVBUF); ahc->seep_config = NULL; sc = NULL; } else { ahc_parse_pci_eeprom(ahc, sc); } have_autoterm = have_seeprom; if ((ahc->features & AHC_SPIOCAP) != 0) { if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0) have_autoterm = FALSE; } if (have_autoterm) { ahc->flags |= AHC_HAS_TERM_LOGIC; ahc_acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1); ahc_release_seeprom(&sd); } else if (have_seeprom) { *sxfrctl1 &= ~STPWEN; if ((sc->adapter_control & CFSTERM) != 0) *sxfrctl1 |= STPWEN; if (bootverbose) printf("%s: Low byte termination %sabled\n", ahc_name(ahc), (*sxfrctl1 & STPWEN) ? "en" : "dis"); } }
/* * Check the external port logic for a serial eeprom * and termination/cable detection contrls. */ void ahc_check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) { struct seeprom_descriptor sd; struct seeprom_config *sc; int have_seeprom; int have_autoterm; sd.sd_tag = ahc->tag; sd.sd_bsh = ahc->bsh; sd.sd_regsize = 1; sd.sd_control_offset = SEECTL; sd.sd_status_offset = SEECTL; sd.sd_dataout_offset = SEECTL; sc = ahc->seep_config; /* * For some multi-channel devices, the c46 is simply too * small to work. For the other controller types, we can * get our information from either SEEPROM type. Set the * type to start our probe with accordingly. */ if (ahc->flags & AHC_LARGE_SEEPROM) sd.sd_chip = C56_66; else sd.sd_chip = C46; sd.sd_MS = SEEMS; sd.sd_RDY = SEERDY; sd.sd_CS = SEECS; sd.sd_CK = SEECK; sd.sd_DO = SEEDO; sd.sd_DI = SEEDI; have_seeprom = ahc_acquire_seeprom(ahc, &sd); if (have_seeprom) { if (bootverbose) printf("%s: Reading SEEPROM...", ahc_name(ahc)); for (;;) { u_int start_addr; start_addr = 32 * (ahc->channel - 'A'); have_seeprom = read_seeprom(&sd, (uint16_t *)sc, start_addr, sizeof(*sc)/2); if (have_seeprom) have_seeprom = verify_seeprom_cksum(sc); if (have_seeprom != 0 || sd.sd_chip == C56_66) { if (bootverbose) { if (have_seeprom == 0) printf ("checksum error\n"); else printf ("done.\n"); } break; } sd.sd_chip = C56_66; } ahc_release_seeprom(&sd); } if (!have_seeprom) { /* * Pull scratch ram settings and treat them as * if they are the contents of an seeprom if * the 'ADPT' signature is found in SCB2. * We manually compose the data as 16bit values * to avoid endian issues. */ ahc_outb(ahc, SCBPTR, 2); if (ahc_inb(ahc, SCB_BASE) == 'A' && ahc_inb(ahc, SCB_BASE + 1) == 'D' && ahc_inb(ahc, SCB_BASE + 2) == 'P' && ahc_inb(ahc, SCB_BASE + 3) == 'T') { uint16_t *sc_data; int i; sc_data = (uint16_t *)sc; for (i = 0; i < 32; i++, sc_data++) { int j; j = i * 2; *sc_data = ahc_inb(ahc, SRAM_BASE + j) | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; } have_seeprom = verify_seeprom_cksum(sc); if (have_seeprom) ahc->flags |= AHC_SCB_CONFIG_USED; } /* * Clear any SCB parity errors in case this data and * its associated parity was not initialized by the BIOS */ ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); } if (!have_seeprom) { if (bootverbose) printf("%s: No SEEPROM available.\n", ahc_name(ahc)); ahc->flags |= AHC_USEDEFAULTS; free(ahc->seep_config, M_DEVBUF); ahc->seep_config = NULL; sc = NULL; } else { ahc_parse_pci_eeprom(ahc, sc); } /* * Cards that have the external logic necessary to talk to * a SEEPROM, are almost certain to have the remaining logic * necessary for auto-termination control. This assumption * hasn't failed yet... */ have_autoterm = have_seeprom; /* * Some low-cost chips have SEEPROM and auto-term control built * in, instead of using a GAL. They can tell us directly * if the termination logic is enabled. */ if ((ahc->features & AHC_SPIOCAP) != 0) { if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0) have_autoterm = FALSE; } if (have_autoterm) { ahc_acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1); ahc_release_seeprom(&sd); } else if (have_seeprom) { *sxfrctl1 &= ~STPWEN; if ((sc->adapter_control & CFSTERM) != 0) *sxfrctl1 |= STPWEN; if (bootverbose) printf("%s: Low byte termination %sabled\n", ahc_name(ahc), (*sxfrctl1 & STPWEN) ? "en" : "dis"); } }
static void configure_termination(struct ahc_softc *ahc, struct seeprom_descriptor *sd, u_int adapter_control, u_int *sxfrctl1) { uint8_t brddat; brddat = 0; /* * Update the settings in sxfrctl1 to match the * termination settings */ *sxfrctl1 = 0; /* * SEECS must be on for the GALS to latch * the data properly. Be sure to leave MS * on or we will release the seeprom. */ SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); if ((adapter_control & CFAUTOTERM) != 0 || (ahc->features & AHC_NEW_TERMCTL) != 0) { int internal50_present; int internal68_present; int externalcable_present; int eeprom_present; int enableSEC_low; int enableSEC_high; int enablePRI_low; int enablePRI_high; int sum; enableSEC_low = 0; enableSEC_high = 0; enablePRI_low = 0; enablePRI_high = 0; if ((ahc->features & AHC_NEW_TERMCTL) != 0) { ahc_new_term_detect(ahc, &enableSEC_low, &enableSEC_high, &enablePRI_low, &enablePRI_high, &eeprom_present); if ((adapter_control & CFSEAUTOTERM) == 0) { if (bootverbose) printf("%s: Manual SE Termination\n", ahc_name(ahc)); enableSEC_low = (adapter_control & CFSELOWTERM); enableSEC_high = (adapter_control & CFSEHIGHTERM); } if ((adapter_control & CFAUTOTERM) == 0) { if (bootverbose) printf("%s: Manual LVD Termination\n", ahc_name(ahc)); enablePRI_low = (adapter_control & CFSTERM); enablePRI_high = (adapter_control & CFWSTERM); } /* Make the table calculations below happy */ internal50_present = 0; internal68_present = 1; externalcable_present = 1; } else if ((ahc->features & AHC_SPIOCAP) != 0) { aic785X_cable_detect(ahc, &internal50_present, &externalcable_present, &eeprom_present); /* Can never support a wide connector. */ internal68_present = 0; } else { aic787X_cable_detect(ahc, &internal50_present, &internal68_present, &externalcable_present, &eeprom_present); } if ((ahc->features & AHC_WIDE) == 0) internal68_present = 0; if (bootverbose && (ahc->features & AHC_ULTRA2) == 0) { printf("%s: internal 50 cable %s present", ahc_name(ahc), internal50_present ? "is":"not"); if ((ahc->features & AHC_WIDE) != 0) printf(", internal 68 cable %s present", internal68_present ? "is":"not"); printf("\n%s: external cable %s present\n", ahc_name(ahc), externalcable_present ? "is":"not"); } if (bootverbose) printf("%s: BIOS eeprom %s present\n", ahc_name(ahc), eeprom_present ? "is" : "not"); if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { /* * The 50 pin connector is a separate bus, * so force it to always be terminated. * In the future, perform current sensing * to determine if we are in the middle of * a properly terminated bus. */ internal50_present = 0; } /* * Now set the termination based on what * we found. * Flash Enable = BRDDAT7 * Secondary High Term Enable = BRDDAT6 * Secondary Low Term Enable = BRDDAT5 (7890) * Primary High Term Enable = BRDDAT4 (7890) */ if ((ahc->features & AHC_ULTRA2) == 0 && (internal50_present != 0) && (internal68_present != 0) && (externalcable_present != 0)) { printf("%s: Illegal cable configuration!!. " "Only two connectors on the " "adapter may be used at a " "time!\n", ahc_name(ahc)); /* * Pretend there are no cables in the hope * that having all of the termination on * gives us a more stable bus. */ internal50_present = 0; internal68_present = 0; externalcable_present = 0; } if ((ahc->features & AHC_WIDE) != 0 && ((externalcable_present == 0) || (internal68_present == 0) || (enableSEC_high != 0))) { brddat |= BRDDAT6; if (bootverbose) { if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) printf("%s: 68 pin termination " "Enabled\n", ahc_name(ahc)); else printf("%s: %sHigh byte termination " "Enabled\n", ahc_name(ahc), enableSEC_high ? "Secondary " : ""); } } sum = internal50_present + internal68_present + externalcable_present; if (sum < 2 || (enableSEC_low != 0)) { if ((ahc->features & AHC_ULTRA2) != 0) brddat |= BRDDAT5; else *sxfrctl1 |= STPWEN; if (bootverbose) { if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) printf("%s: 50 pin termination " "Enabled\n", ahc_name(ahc)); else printf("%s: %sLow byte termination " "Enabled\n", ahc_name(ahc), enableSEC_low ? "Secondary " : ""); } } if (enablePRI_low != 0) { *sxfrctl1 |= STPWEN; if (bootverbose) printf("%s: Primary Low Byte termination " "Enabled\n", ahc_name(ahc)); } /* * Setup STPWEN before setting up the rest of * the termination per the tech note on the U160 cards. */ ahc_outb(ahc, SXFRCTL1, *sxfrctl1); if (enablePRI_high != 0) { brddat |= BRDDAT4; if (bootverbose) printf("%s: Primary High Byte " "termination Enabled\n", ahc_name(ahc)); } write_brdctl(ahc, brddat); } else { if ((adapter_control & CFSTERM) != 0) { *sxfrctl1 |= STPWEN; if (bootverbose) printf("%s: %sLow byte termination Enabled\n", ahc_name(ahc), (ahc->features & AHC_ULTRA2) ? "Primary " : ""); } if ((adapter_control & CFWSTERM) != 0 && (ahc->features & AHC_WIDE) != 0) { brddat |= BRDDAT6; if (bootverbose) printf("%s: %sHigh byte termination Enabled\n", ahc_name(ahc), (ahc->features & AHC_ULTRA2) ? "Secondary " : ""); } /* * Setup STPWEN before setting up the rest of * the termination per the tech note on the U160 cards. */ ahc_outb(ahc, SXFRCTL1, *sxfrctl1); if ((ahc->features & AHC_WIDE) != 0) write_brdctl(ahc, brddat); } SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */ }