const struct ahc_pci_identity * ahc_find_pci_device(ahc_dev_softc_t pci) { uint64_t full_id; uint16_t device; uint16_t vendor; uint16_t subdevice; uint16_t subvendor; const struct ahc_pci_identity *entry; u_int i; vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, 2); device = ahc_pci_read_config(pci, PCIR_DEVICE, 2); subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, 2); subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, 2); full_id = ahc_compose_id(device, vendor, subdevice, subvendor); if (ahc_get_pci_function(pci) > 0 && ahc_9005_subdevinfo_valid(vendor, device, subvendor, subdevice) && SUBID_9005_MFUNCENB(subdevice) == 0) return (NULL); for (i = 0; i < ahc_num_pci_devs; i++) { entry = &ahc_pci_ident_table[i]; if (entry->full_id == (full_id & entry->id_mask)) { if (entry->name == NULL) return (NULL); return (entry); } } return (NULL); }
static int ahc_ext_scbram_present(struct ahc_softc *ahc) { u_int chip; int ramps; int single_user; uint32_t devconfig; chip = ahc->chip & AHC_CHIPID_MASK; devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); single_user = (devconfig & MPORTMODE) != 0; if ((ahc->features & AHC_ULTRA2) != 0) ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0; else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C) ramps = 0; else if (chip >= AHC_AIC7870) ramps = (devconfig & RAMPSM) != 0; else ramps = 0; if (ramps && single_user) return (1); return (0); }
static int ahc_aic7895_setup(struct ahc_softc *ahc) { ahc_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; rev = ahc_pci_read_config(pci, PCIR_REVID, 1); if (rev >= 4) { ahc->chip = AHC_AIC7895C; ahc->features = AHC_AIC7895C_FE; } else { u_int command; ahc->chip = AHC_AIC7895; ahc->features = AHC_AIC7895_FE; command = ahc_pci_read_config(pci, PCIR_COMMAND, 1); command |= PCIM_CMD_MWRICEN; ahc_pci_write_config(pci, PCIR_COMMAND, command, 1); ahc->bugs |= AHC_PCI_MWI_BUG; } ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG | AHC_CACHETHEN_BUG; #if 0 uint32_t devconfig; ahc_pci_write_config(pci, CSIZE_LATTIME, 0, 1); devconfig = ahc_pci_read_config(pci, DEVCONFIG, 1); devconfig |= MRDCEN; ahc_pci_write_config(pci, DEVCONFIG, devconfig, 1); #endif ahc->flags |= AHC_NEWEEPROM_FMT; ahc->instruction_ram_size = 512; return (0); }
static void ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, int fast, int large) { uint32_t devconfig; if (ahc->features & AHC_MULTI_FUNC) { ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc)); } ahc->flags &= ~AHC_LSCBS_ENABLED; if (large) ahc->flags |= AHC_LSCBS_ENABLED; devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); if ((ahc->features & AHC_ULTRA2) != 0) { u_int dscommand0; dscommand0 = ahc_inb(ahc, DSCOMMAND0); if (enable) dscommand0 &= ~INTSCBRAMSEL; else dscommand0 |= INTSCBRAMSEL; if (large) dscommand0 &= ~USCBSIZE32; else dscommand0 |= USCBSIZE32; ahc_outb(ahc, DSCOMMAND0, dscommand0); } else { if (fast) devconfig &= ~EXTSCBTIME; else devconfig |= EXTSCBTIME; if (enable) devconfig &= ~SCBRAMSEL; else devconfig |= SCBRAMSEL; if (large) devconfig &= ~SCBSIZE32; else devconfig |= SCBSIZE32; } if (pcheck) devconfig |= EXTSCBPEN; else devconfig &= ~EXTSCBPEN; ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4); }
static int ahc_aic7890_setup(struct ahc_softc *ahc) { ahc_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; ahc->channel = 'A'; ahc->chip = AHC_AIC7890; ahc->features = AHC_AIC7890_FE; ahc->flags |= AHC_NEWEEPROM_FMT; rev = ahc_pci_read_config(pci, PCIR_REVID, 1); if (rev == 0) ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; ahc->instruction_ram_size = 768; return (0); }
static int ahc_aic7860_setup(struct ahc_softc *ahc) { ahc_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; ahc->channel = 'A'; ahc->chip = AHC_AIC7860; ahc->features = AHC_AIC7860_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; rev = ahc_pci_read_config(pci, PCIR_REVID, 1); if (rev >= 1) ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; ahc->instruction_ram_size = 512; return (0); }
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_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 ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc) { int i; int max_targ = sc->max_targets & CFMAXTARG; u_int scsi_conf; uint16_t discenable; uint16_t ultraenb; discenable = 0; ultraenb = 0; if ((sc->adapter_control & CFULTRAEN) != 0) { for (i = 0; i < max_targ; i++) { if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) { ahc->flags |= AHC_NEWEEPROM_FMT; break; } } } for (i = 0; i < max_targ; i++) { u_int scsirate; uint16_t target_mask; target_mask = 0x01 << i; if (sc->device_flags[i] & CFDISC) discenable |= target_mask; if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) { if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) ultraenb |= target_mask; } else if ((sc->adapter_control & CFULTRAEN) != 0) { ultraenb |= target_mask; } if ((sc->device_flags[i] & CFXFER) == 0x04 && (ultraenb & target_mask) != 0) { sc->device_flags[i] &= ~CFXFER; ultraenb &= ~target_mask; } if ((ahc->features & AHC_ULTRA2) != 0) { u_int offset; if (sc->device_flags[i] & CFSYNCH) offset = MAX_OFFSET_ULTRA2; else offset = 0; ahc_outb(ahc, TARG_OFFSET + i, offset); scsirate = (sc->device_flags[i] & CFXFER) | ((ultraenb & target_mask) ? 0x8 : 0x0); if (sc->device_flags[i] & CFWIDEB) scsirate |= WIDEXFER; } else { scsirate = (sc->device_flags[i] & CFXFER) << 4; if (sc->device_flags[i] & CFSYNCH) scsirate |= SOFS; if (sc->device_flags[i] & CFWIDEB) scsirate |= WIDEXFER; } ahc_outb(ahc, TARG_SCSIRATE + i, scsirate); } 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; ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; if (sc->bios_control & CFEXTEND) ahc->flags |= AHC_EXTENDED_TRANS_A; if (sc->bios_control & CFBIOSEN) ahc->flags |= AHC_BIOS_ENABLED; if (ahc->features & AHC_ULTRA && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) { if (!(sc->adapter_control & CFULTRAEN)) ultraenb = 0; } if (sc->signature == CFSIGNATURE || sc->signature == CFSIGNATURE2) { uint32_t devconfig; devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); devconfig &= ~STPWLEVEL; if ((sc->bios_control & CFSTPWLEVEL) != 0) devconfig |= STPWLEVEL; ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4); } ahc_outb(ahc, SCSICONF, scsi_conf); ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff); ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff); }
int ahc_pci_test_register_access(struct ahc_softc *ahc) { int error; u_int status1; uint32_t cmd; uint8_t hcntrl; error = EIO; cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 2); ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd & ~PCIM_CMD_SERRESPEN, 2); hcntrl = ahc_inb(ahc, HCNTRL); if (hcntrl == 0xFF) goto fail; if ((hcntrl & CHIPRST) != 0) { ahc->flags |= AHC_NO_BIOS_INIT; } hcntrl &= ~CHIPRST; ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); while (ahc_is_paused(ahc) == 0) ; status1 = ahc_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, 1); ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, status1, 1); ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, SEQCTL, PERRORDIS); ahc_outb(ahc, SCBPTR, 0); ahc_outl(ahc, SCB_BASE, 0x5aa555aa); if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa) goto fail; status1 = ahc_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, 1); if ((status1 & STA) != 0) goto fail; error = 0; fail: status1 = ahc_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, 1); ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, status1, 1); ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, 2); return (error); }
int ahc_pci_map_registers(struct ahc_softc *ahc) { uint32_t command; u_long base; uint8_t __iomem *maddr; int error; /* * If its allowed, we prefer memory mapped access. */ command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); base = 0; maddr = NULL; error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr); if (error == 0) { ahc->platform_data->mem_busaddr = base; ahc->tag = BUS_SPACE_MEMIO; ahc->bsh.maddr = maddr; ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command | PCIM_CMD_MEMEN, 4); /* * Do a quick test to see if memory mapped * I/O is functioning correctly. */ if (ahc_pci_test_register_access(ahc) != 0) { printf("aic7xxx: PCI Device %d:%d:%d " "failed memory mapped test. Using PIO.\n", ahc_get_pci_bus(ahc->dev_softc), ahc_get_pci_slot(ahc->dev_softc), ahc_get_pci_function(ahc->dev_softc)); iounmap(maddr); release_mem_region(ahc->platform_data->mem_busaddr, 0x1000); ahc->bsh.maddr = NULL; maddr = NULL; } else command |= PCIM_CMD_MEMEN; } else { printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx " "unavailable. Cannot memory map device.\n", ahc_get_pci_bus(ahc->dev_softc), ahc_get_pci_slot(ahc->dev_softc), ahc_get_pci_function(ahc->dev_softc), base); } /* * We always prefer memory mapped access. */ if (maddr == NULL) { error = ahc_linux_pci_reserve_io_region(ahc, &base); if (error == 0) { ahc->tag = BUS_SPACE_PIO; ahc->bsh.ioport = base; command |= PCIM_CMD_PORTEN; } else { printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] " "unavailable. Cannot map device.\n", ahc_get_pci_bus(ahc->dev_softc), ahc_get_pci_slot(ahc->dev_softc), ahc_get_pci_function(ahc->dev_softc), base); } } ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); return (error); }