int aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) { u_long l; u_long s; int error; int have_seeprom; u_int hostconf; u_int irq; u_int intdef; error = entry->setup(ahc); have_seeprom = 0; if (error != 0) return (error); error = aic7770_map_registers(ahc, io); if (error != 0) return (error); /* * Before we continue probing the card, ensure that * its interrupts are *disabled*. We don't want * a misstep to hang the machine in an interrupt * storm. */ ahc_intr_enable(ahc, FALSE); ahc->description = entry->name; error = ahc_softc_init(ahc); error = ahc_reset(ahc); if (error != 0) return (error); /* Make sure we have a valid interrupt vector */ intdef = ahc_inb(ahc, INTDEF); irq = intdef & VECTOR; switch (irq) { case 9: case 10: case 11: case 12: case 14: case 15: break; default: printf("aic7770_config: illegal irq setting %d\n", intdef); return (ENXIO); } if ((intdef & EDGE_TRIG) != 0) ahc->flags |= AHC_EDGE_INTERRUPT; switch (ahc->chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: { u_int biosctrl; u_int scsiconf; u_int scsiconf1; biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); scsiconf = ahc_inb(ahc, SCSICONF); scsiconf1 = ahc_inb(ahc, SCSICONF + 1); /* Get the primary channel information */ if ((biosctrl & CHANNEL_B_PRIMARY) != 0) ahc->flags |= 1; if ((biosctrl & BIOSMODE) == BIOSDISABLED) { ahc->flags |= AHC_USEDEFAULTS; } else { if ((ahc->features & AHC_WIDE) != 0) { ahc->our_id = scsiconf1 & HWSCSIID; if (scsiconf & TERM_ENB) ahc->flags |= AHC_TERM_ENB_A; } else { ahc->our_id = scsiconf & HSCSIID; ahc->our_id_b = scsiconf1 & HSCSIID; if (scsiconf & TERM_ENB) ahc->flags |= AHC_TERM_ENB_A; if (scsiconf1 & TERM_ENB) ahc->flags |= AHC_TERM_ENB_B; } } if ((ahc_inb(ahc, HA_274_BIOSGLOBAL) & HA_274_EXTENDED_TRANS)) ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; break; } case AHC_VL: { have_seeprom = aha2840_load_seeprom(ahc); break; } default: break; } if (have_seeprom == 0) { free(ahc->seep_config, M_DEVBUF); ahc->seep_config = NULL; } /* * Ensure autoflush is enabled */ ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); /* Setup the FIFO threshold and the bus off time */ hostconf = ahc_inb(ahc, HOSTCONF); ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); /* * Generic aic7xxx initialization. */ error = ahc_init(ahc); if (error != 0) return (error); error = aic7770_map_int(ahc, irq); if (error != 0) return (error); ahc_list_lock(&l); /* * Link this softc in with all other ahc instances. */ ahc_softc_insert(ahc); /* * Enable the board's BUS drivers */ ahc_outb(ahc, BCTL, ENABLE); /* * Allow interrupts. */ ahc_lock(ahc, &s); ahc_intr_enable(ahc, TRUE); ahc_unlock(ahc, &s); ahc_list_unlock(&l); return (0); }
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); }