aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/aic7xxx/aic7xxx_pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7xxx_pci.c')
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c2407
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