diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7xxx_pci.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7xxx_pci.c | 2407 |
1 files changed, 2407 insertions, 0 deletions
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c new file mode 100644 index 00000000000..7ddcc97fb24 --- /dev/null +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -0,0 +1,2407 @@ +/* + * Product specific probe and attach routines for: + * 3940, 2940, aic7895, aic7890, aic7880, + * aic7870, aic7860 and aic7850 SCSI controllers + * + * Copyright (c) 1994-2001 Justin T. Gibbs. + * Copyright (c) 2000-2001 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#69 $ + * + * $FreeBSD$ + */ + +#ifdef __linux__ +#include "aic7xxx_osm.h" +#include "aic7xxx_inline.h" +#include "aic7xxx_93cx6.h" +#else +#include <dev/aic7xxx/aic7xxx_osm.h> +#include <dev/aic7xxx/aic7xxx_inline.h> +#include <dev/aic7xxx/aic7xxx_93cx6.h> +#endif + +#include "aic7xxx_pci.h" + +static __inline uint64_t +ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) +{ + uint64_t id; + + id = subvendor + | (subdevice << 16) + | ((uint64_t)vendor << 32) + | ((uint64_t)device << 48); + + return (id); +} + +#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ +#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ + +#define DEVID_9005_TYPE(id) ((id) & 0xF) +#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */ +#define DEVID_9005_TYPE_AAA 0x3 /* RAID Card */ +#define DEVID_9005_TYPE_SISL 0x5 /* Container ROMB */ +#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */ + +#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4) +#define DEVID_9005_MAXRATE_U160 0x0 +#define DEVID_9005_MAXRATE_ULTRA2 0x1 +#define DEVID_9005_MAXRATE_ULTRA 0x2 +#define DEVID_9005_MAXRATE_FAST 0x3 + +#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6) + +#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8) +#define DEVID_9005_CLASS_SPI 0x0 /* Parallel SCSI */ + +#define SUBID_9005_TYPE(id) ((id) & 0xF) +#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */ +#define SUBID_9005_TYPE_CARD 0x0 /* Standard Card */ +#define SUBID_9005_TYPE_LCCARD 0x1 /* Low Cost Card */ +#define SUBID_9005_TYPE_RAID 0x3 /* Combined with Raid */ + +#define SUBID_9005_TYPE_KNOWN(id) \ + ((((id) & 0xF) == SUBID_9005_TYPE_MB) \ + || (((id) & 0xF) == SUBID_9005_TYPE_CARD) \ + || (((id) & 0xF) == SUBID_9005_TYPE_LCCARD) \ + || (((id) & 0xF) == SUBID_9005_TYPE_RAID)) + +#define SUBID_9005_MAXRATE(id) (((id) & 0x30) >> 4) +#define SUBID_9005_MAXRATE_ULTRA2 0x0 +#define SUBID_9005_MAXRATE_ULTRA 0x1 +#define SUBID_9005_MAXRATE_U160 0x2 +#define SUBID_9005_MAXRATE_RESERVED 0x3 + +#define SUBID_9005_SEEPTYPE(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? ((id) & 0xC0) >> 6 \ + : ((id) & 0x300) >> 8) +#define SUBID_9005_SEEPTYPE_NONE 0x0 +#define SUBID_9005_SEEPTYPE_1K 0x1 +#define SUBID_9005_SEEPTYPE_2K_4K 0x2 +#define SUBID_9005_SEEPTYPE_RESERVED 0x3 +#define SUBID_9005_AUTOTERM(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? (((id) & 0x400) >> 10) == 0 \ + : (((id) & 0x40) >> 6) == 0) + +#define SUBID_9005_NUMCHAN(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? ((id) & 0x300) >> 8 \ + : ((id) & 0xC00) >> 10) + +#define SUBID_9005_LEGACYCONN(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? 0 \ + : ((id) & 0x80) >> 7) + +#define SUBID_9005_MFUNCENB(id) \ + ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ + ? ((id) & 0x800) >> 11 \ + : ((id) & 0x1000) >> 12) +/* + * Informational only. Should use chip register to be + * certain, but may be use in identification strings. + */ +#define SUBID_9005_CARD_SCSIWIDTH_MASK 0x2000 +#define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000 +#define SUBID_9005_CARD_SEDIFF_MASK 0x8000 + +static ahc_device_setup_t ahc_aic785X_setup; +static ahc_device_setup_t ahc_aic7860_setup; +static ahc_device_setup_t ahc_apa1480_setup; +static ahc_device_setup_t ahc_aic7870_setup; +static ahc_device_setup_t ahc_aha394X_setup; +static ahc_device_setup_t ahc_aha494X_setup; +static ahc_device_setup_t ahc_aha398X_setup; +static ahc_device_setup_t ahc_aic7880_setup; +static ahc_device_setup_t ahc_aha2940Pro_setup; +static ahc_device_setup_t ahc_aha394XU_setup; +static ahc_device_setup_t ahc_aha398XU_setup; +static ahc_device_setup_t ahc_aic7890_setup; +static ahc_device_setup_t ahc_aic7892_setup; +static ahc_device_setup_t ahc_aic7895_setup; +static ahc_device_setup_t ahc_aic7896_setup; +static ahc_device_setup_t ahc_aic7899_setup; +static ahc_device_setup_t ahc_aha29160C_setup; +static ahc_device_setup_t ahc_raid_setup; +static ahc_device_setup_t ahc_aha394XX_setup; +static ahc_device_setup_t ahc_aha494XX_setup; +static ahc_device_setup_t ahc_aha398XX_setup; + +struct ahc_pci_identity ahc_pci_ident_table [] = +{ + /* aic7850 based controllers */ + { + ID_AHA_2902_04_10_15_20C_30C, + ID_ALL_MASK, + "Adaptec 2902/04/10/15/20C/30C SCSI adapter", + ahc_aic785X_setup + }, + /* aic7860 based controllers */ + { + ID_AHA_2930CU, + ID_ALL_MASK, + "Adaptec 2930CU SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AHA_1480A & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 1480A Ultra SCSI adapter", + ahc_apa1480_setup + }, + { + ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940A Ultra SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940A/CN Ultra SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2930C Ultra SCSI adapter (VAR)", + ahc_aic7860_setup + }, + /* aic7870 based controllers */ + { + ID_AHA_2940, + ID_ALL_MASK, + "Adaptec 2940 SCSI adapter", + ahc_aic7870_setup + }, + { + ID_AHA_3940, + ID_ALL_MASK, + "Adaptec 3940 SCSI adapter", + ahc_aha394X_setup + }, + { + ID_AHA_398X, + ID_ALL_MASK, + "Adaptec 398X SCSI RAID adapter", + ahc_aha398X_setup + }, + { + ID_AHA_2944, + ID_ALL_MASK, + "Adaptec 2944 SCSI adapter", + ahc_aic7870_setup + }, + { + ID_AHA_3944, + ID_ALL_MASK, + "Adaptec 3944 SCSI adapter", + ahc_aha394X_setup + }, + { + ID_AHA_4944, + ID_ALL_MASK, + "Adaptec 4944 SCSI adapter", + ahc_aha494X_setup + }, + /* aic7880 based controllers */ + { + ID_AHA_2940U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_3940U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 3940 Ultra SCSI adapter", + ahc_aha394XU_setup + }, + { + ID_AHA_2944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2944 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_3944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 3944 Ultra SCSI adapter", + ahc_aha394XU_setup + }, + { + ID_AHA_398XU & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 398X Ultra SCSI RAID adapter", + ahc_aha398XU_setup + }, + { + /* + * XXX Don't know the slot numbers + * so we can't identify channels + */ + ID_AHA_4944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 4944 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_2930U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2930 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940 Pro Ultra SCSI adapter", + ahc_aha2940Pro_setup + }, + { + ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec 2940/CN Ultra SCSI adapter", + ahc_aic7880_setup + }, + /* Ignore all SISL (AAC on MB) based controllers. */ + { + ID_9005_SISL_ID, + ID_9005_SISL_MASK, + NULL, + NULL + }, + /* aic7890 based controllers */ + { + ID_AHA_2930U2, + ID_ALL_MASK, + "Adaptec 2930 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AHA_2940U2B, + ID_ALL_MASK, + "Adaptec 2940B Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AHA_2940U2_OEM, + ID_ALL_MASK, + "Adaptec 2940 Ultra2 SCSI adapter (OEM)", + ahc_aic7890_setup + }, + { + ID_AHA_2940U2, + ID_ALL_MASK, + "Adaptec 2940 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AHA_2950U2B, + ID_ALL_MASK, + "Adaptec 2950 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AIC7890_ARO, + ID_ALL_MASK, + "Adaptec aic7890/91 Ultra2 SCSI adapter (ARO)", + ahc_aic7890_setup + }, + { + ID_AAA_131U2, + ID_ALL_MASK, + "Adaptec AAA-131 Ultra2 RAID adapter", + ahc_aic7890_setup + }, + /* aic7892 based controllers */ + { + ID_AHA_29160, + ID_ALL_MASK, + "Adaptec 29160 Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_29160_CPQ, + ID_ALL_MASK, + "Adaptec (Compaq OEM) 29160 Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_29160N, + ID_ALL_MASK, + "Adaptec 29160N Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_29160C, + ID_ALL_MASK, + "Adaptec 29160C Ultra160 SCSI adapter", + ahc_aha29160C_setup + }, + { + ID_AHA_29160B, + ID_ALL_MASK, + "Adaptec 29160B Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AHA_19160B, + ID_ALL_MASK, + "Adaptec 19160B Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AIC7892_ARO, + ID_ALL_MASK, + "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", + ahc_aic7892_setup + }, + /* aic7895 based controllers */ + { + ID_AHA_2940U_DUAL, + ID_ALL_MASK, + "Adaptec 2940/DUAL Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AHA_3940AU, + ID_ALL_MASK, + "Adaptec 3940A Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AHA_3944AU, + ID_ALL_MASK, + "Adaptec 3944A Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AIC7895_ARO, + ID_AIC7895_ARO_MASK, + "Adaptec aic7895 Ultra SCSI adapter (ARO)", + ahc_aic7895_setup + }, + /* aic7896/97 based controllers */ + { + ID_AHA_3950U2B_0, + ID_ALL_MASK, + "Adaptec 3950B Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AHA_3950U2B_1, + ID_ALL_MASK, + "Adaptec 3950B Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AHA_3950U2D_0, + ID_ALL_MASK, + "Adaptec 3950D Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AHA_3950U2D_1, + ID_ALL_MASK, + "Adaptec 3950D Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AIC7896_ARO, + ID_ALL_MASK, + "Adaptec aic7896/97 Ultra2 SCSI adapter (ARO)", + ahc_aic7896_setup + }, + /* aic7899 based controllers */ + { + ID_AHA_3960D, + ID_ALL_MASK, + "Adaptec 3960D Ultra160 SCSI adapter", + ahc_aic7899_setup + }, + { + ID_AHA_3960D_CPQ, + ID_ALL_MASK, + "Adaptec (Compaq OEM) 3960D Ultra160 SCSI adapter", + ahc_aic7899_setup + }, + { + ID_AIC7899_ARO, + ID_ALL_MASK, + "Adaptec aic7899 Ultra160 SCSI adapter (ARO)", + ahc_aic7899_setup + }, + /* Generic chip probes for devices we don't know 'exactly' */ + { + ID_AIC7850 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7850 SCSI adapter", + ahc_aic785X_setup + }, + { + ID_AIC7855 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7855 SCSI adapter", + ahc_aic785X_setup + }, + { + ID_AIC7859 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7859 SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AIC7860 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7860 Ultra SCSI adapter", + ahc_aic7860_setup + }, + { + ID_AIC7870 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7870 SCSI adapter", + ahc_aic7870_setup + }, + { + ID_AIC7880 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7880 Ultra SCSI adapter", + ahc_aic7880_setup + }, + { + ID_AIC7890 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7890/91 Ultra2 SCSI adapter", + ahc_aic7890_setup + }, + { + ID_AIC7892 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7892 Ultra160 SCSI adapter", + ahc_aic7892_setup + }, + { + ID_AIC7895 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7895 Ultra SCSI adapter", + ahc_aic7895_setup + }, + { + ID_AIC7896 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7896/97 Ultra2 SCSI adapter", + ahc_aic7896_setup + }, + { + ID_AIC7899 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + "Adaptec aic7899 Ultra160 SCSI adapter", + ahc_aic7899_setup + }, + { + ID_AIC7810 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7810 RAID memory controller", + ahc_raid_setup + }, + { + ID_AIC7815 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec aic7815 RAID memory controller", + ahc_raid_setup + } +}; + +const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table); + +#define AHC_394X_SLOT_CHANNEL_A 4 +#define AHC_394X_SLOT_CHANNEL_B 5 + +#define AHC_398X_SLOT_CHANNEL_A 4 +#define AHC_398X_SLOT_CHANNEL_B 8 +#define AHC_398X_SLOT_CHANNEL_C 12 + +#define AHC_494X_SLOT_CHANNEL_A 4 +#define AHC_494X_SLOT_CHANNEL_B 5 +#define AHC_494X_SLOT_CHANNEL_C 6 +#define AHC_494X_SLOT_CHANNEL_D 7 + +#define DEVCONFIG 0x40 +#define PCIERRGENDIS 0x80000000ul +#define SCBSIZE32 0x00010000ul /* aic789X only */ +#define REXTVALID 0x00001000ul /* ultra cards only */ +#define MPORTMODE 0x00000400ul /* aic7870+ only */ +#define RAMPSM 0x00000200ul /* aic7870+ only */ +#define VOLSENSE 0x00000100ul +#define PCI64BIT 0x00000080ul /* 64Bit PCI bus (Ultra2 Only)*/ +#define SCBRAMSEL 0x00000080ul +#define MRDCEN 0x00000040ul +#define EXTSCBTIME 0x00000020ul /* aic7870 only */ +#define EXTSCBPEN 0x00000010ul /* aic7870 only */ +#define BERREN 0x00000008ul +#define DACEN 0x00000004ul +#define STPWLEVEL 0x00000002ul +#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ + +#define CSIZE_LATTIME 0x0c +#define CACHESIZE 0x0000003ful /* only 5 bits */ +#define LATTIME 0x0000ff00ul + +/* PCI STATUS definitions */ +#define DPE 0x80 +#define SSE 0x40 +#define RMA 0x20 +#define RTA 0x10 +#define STA 0x08 +#define DPR 0x01 + +static int ahc_9005_subdevinfo_valid(uint16_t vendor, uint16_t device, + uint16_t subvendor, uint16_t subdevice); +static int ahc_ext_scbram_present(struct ahc_softc *ahc); +static void ahc_scbram_config(struct ahc_softc *ahc, int enable, + int pcheck, int fast, int large); +static void ahc_probe_ext_scbram(struct ahc_softc *ahc); +static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1); +static void ahc_parse_pci_eeprom(struct ahc_softc *ahc, + struct seeprom_config *sc); +static void configure_termination(struct ahc_softc *ahc, + struct seeprom_descriptor *sd, + u_int adapter_control, + u_int *sxfrctl1); + +static void ahc_new_term_detect(struct ahc_softc *ahc, + int *enableSEC_low, + int *enableSEC_high, + int *enablePRI_low, + int *enablePRI_high, + int *eeprom_present); +static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, + int *internal68_present, + int *externalcable_present, + int *eeprom_present); +static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, + int *externalcable_present, + int *eeprom_present); +static void write_brdctl(struct ahc_softc *ahc, uint8_t value); +static uint8_t read_brdctl(struct ahc_softc *ahc); +static void ahc_pci_intr(struct ahc_softc *ahc); +static int ahc_pci_chip_init(struct ahc_softc *ahc); +static int ahc_pci_suspend(struct ahc_softc *ahc); +static int ahc_pci_resume(struct ahc_softc *ahc); + +static int +ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor, + uint16_t subdevice, uint16_t subvendor) +{ + int result; + + /* Default to invalid. */ + result = 0; + if (vendor == 0x9005 + && subvendor == 0x9005 + && subdevice != device + && SUBID_9005_TYPE_KNOWN(subdevice) != 0) { + + switch (SUBID_9005_TYPE(subdevice)) { + case SUBID_9005_TYPE_MB: + break; + case SUBID_9005_TYPE_CARD: + case SUBID_9005_TYPE_LCCARD: + /* + * Currently only trust Adaptec cards to + * get the sub device info correct. + */ + if (DEVID_9005_TYPE(device) == DEVID_9005_TYPE_HBA) + result = 1; + break; + case SUBID_9005_TYPE_RAID: + break; + default: + break; + } + } + return (result); +} + +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; + struct ahc_pci_identity *entry; + u_int i; + + vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); + device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); + subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); + subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); + full_id = ahc_compose_id(device, vendor, subdevice, subvendor); + + /* + * If the second function is not hooked up, ignore it. + * Unfortunately, not all MB vendors implement the + * subdevice ID as per the Adaptec spec, so do our best + * to sanity check it prior to accepting the subdevice + * ID as valid. + */ + 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)) { + /* Honor exclusion entries. */ + if (entry->name == NULL) + return (NULL); + return (entry); + } + } + return (NULL); +} + +int +ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) +{ + u_long l; + 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); + + /* + * 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); + + devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); + + /* + * If we need to support high memory, enable dual + * address cycles. This bit must be set to enable + * high address bit generation even if we are on a + * 64bit bus (PCI64BIT set in devconfig). + */ + if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { + + if (bootverbose) + printf("%s: Enabling 39Bit Addressing\n", + ahc_name(ahc)); + devconfig |= DACEN; + } + + /* Ensure that pci error generation, a test feature, is disabled. */ + devconfig |= PCIERRGENDIS; + + ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); + + /* Ensure busmastering is enabled */ + command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); + command |= PCIM_CMD_BUSMASTEREN; + + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2); + + /* On all PCI adapters, we allow SCB paging */ + ahc->flags |= AHC_PAGESCBS; + + error = ahc_softc_init(ahc); + if (error != 0) + return (error); + + /* + * Disable PCI parity error checking. Users typically + * do this to work around broken PCI chipsets that get + * the parity timing wrong and thus generate lots of spurious + * errors. The chip only allows us to disable *all* parity + * error reporting when doing this, so CIO bus, scb ram, and + * scratch ram parity errors will be ignored too. + */ + 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; + ahc->bus_suspend = ahc_pci_suspend; + ahc->bus_resume = ahc_pci_resume; + + /* Remeber how the card was setup in case there is no SEEPROM */ + 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, /*reinit*/FALSE); + if (error != 0) + return (ENXIO); + + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + /* Perform ALT-Mode Setup */ + 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); + + /* Normal mode setup */ + ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN + |TARGCRCENDEN); + } + + dscommand0 = ahc_inb(ahc, DSCOMMAND0); + dscommand0 |= MPARCKEN|CACHETHEN; + if ((ahc->features & AHC_ULTRA2) != 0) { + + /* + * DPARCKEN doesn't work correctly on + * some MBs so don't use it. + */ + dscommand0 &= ~DPARCKEN; + } + + /* + * Handle chips that must have cache line + * streaming (dis/en)abled. + */ + 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, + /*bytes*/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, /*bytes*/1); + ahc->pci_cachesize = 0; + } + + /* + * We cannot perform ULTRA speeds without the presense + * of the external precision resistor. + */ + if ((ahc->features & AHC_ULTRA) != 0) { + uint32_t devconfig; + + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + if ((devconfig & REXTVALID) == 0) + ahc->features &= ~AHC_ULTRA; + } + + /* See if we have a SEEPROM and perform auto-term */ + check_extport(ahc, &sxfrctl1); + + /* + * Take the LED out of diagnostic mode + */ + 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) { + /* + * PCI Adapter default setup + * Should only be used if the adapter does not have + * a SEEPROM. + */ + /* See if someone else set us up already */ + 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 { + /* + * Assume only one connector and always turn + * on termination. + */ + our_id = 0x07; + sxfrctl1 = STPWEN; + } + ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI); + + ahc->our_id = our_id; + } + + /* + * Take a look to see if we have external SRAM. + * We currently do not attempt to use SRAM that is + * shared among multiple controllers. + */ + ahc_probe_ext_scbram(ahc); + + /* + * Record our termination setting for the + * generic initialization routine. + */ + if ((sxfrctl1 & STPWEN) != 0) + ahc->flags |= AHC_TERM_ENB_A; + + /* + * Save chip register configuration data for chip resets + * that occur during runtime and resume events. + */ + ahc->bus_softc.pci_softc.devconfig = + ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); + ahc->bus_softc.pci_softc.command = + ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); + ahc->bus_softc.pci_softc.csize_lattime = + ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/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); + + /* Core initialization */ + error = ahc_init(ahc); + if (error != 0) + return (error); + + /* + * Allow interrupts now that we are completely setup. + */ + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + + ahc_list_lock(&l); + /* + * Link this softc in with all other ahc instances. + */ + ahc_softc_insert(ahc); + ahc_list_unlock(&l); + return (0); +} + +/* + * Test for the presense of external sram in an + * "unshared" configuration. + */ +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, /*bytes*/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) + /* + * External SCBRAM arbitration is flakey + * on these chips. Unfortunately this means + * we don't use the extra SCB ram space on the + * 3940AUW. + */ + ramps = 0; + else if (chip >= AHC_AIC7870) + ramps = (devconfig & RAMPSM) != 0; + else + ramps = 0; + + if (ramps && single_user) + return (1); + return (0); +} + +/* + * Enable external scbram. + */ +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) { + /* + * Set the SCB Base addr (highest address bit) + * depending on which channel we are. + */ + 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, /*bytes*/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, /*bytes*/4); +} + +/* + * Take a look to see if we have external SRAM. + * We currently do not attempt to use SRAM that is + * shared among multiple controllers. + */ +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; + + /* + * Probe for the best parameters to use. + */ + ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large); + num_scbs = ahc_probe_scbs(ahc); + if (num_scbs == 0) { + /* The SRAM wasn't really present. */ + goto done; + } + enable = TRUE; + + /* + * Clear any outstanding parity error + * and ensure that parity error reporting + * is enabled. + */ + ahc_outb(ahc, SEQCTL, 0); + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); + + /* Now see if we can do parity */ + ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large); + num_scbs = ahc_probe_scbs(ahc); + if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 + || (ahc_inb(ahc, ERROR) & MPARERR) == 0) + pcheck = TRUE; + + /* Clear any resulting parity error */ + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, CLRINT, CLRBRKADRINT); + + /* Now see if we can do fast timing */ + ahc_scbram_config(ahc, enable, pcheck, /*fast*/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; + + /* + * See if we can use large SCBs and still maintain + * the same overall count of SCBs. + */ + if ((ahc->features & AHC_LARGE_SCBS) != 0) { + ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/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) { + /* + * We have enough space to move the + * "busy targets table" into SCB space + * and make it qualify all the way to the + * lun level. + */ + ahc->flags |= AHC_SCB_BTT; + } + } + } +done: + /* + * Disable parity error reporting until we + * can load instruction ram. + */ + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); + /* Clear any latched parity error */ + 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); +} + +/* + * Perform some simple tests that should catch situations where + * our registers are invalidly mapped. + */ +int +ahc_pci_test_register_access(struct ahc_softc *ahc) +{ + int error; + u_int status1; + uint32_t cmd; + uint8_t hcntrl; + + error = EIO; + + /* + * Enable PCI error interrupt status, but suppress NMIs + * generated by SERR raised due to target aborts. + */ + cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); + + /* + * First a simple test to see if any + * registers can be read. Reading + * HCNTRL has no side effects and has + * at least one bit that is guaranteed to + * be zero so it is a good register to + * use for this test. + */ + hcntrl = ahc_inb(ahc, HCNTRL); + if (hcntrl == 0xFF) + goto fail; + + /* + * Next create a situation where write combining + * or read prefetching could be initiated by the + * CPU or host bridge. Our device does not support + * either, so look for data corruption and/or flagged + * PCI errors. First pause without causing another + * c |