diff options
Diffstat (limited to 'sys/dev/pci/ahc_pci.c')
-rw-r--r-- | sys/dev/pci/ahc_pci.c | 2387 |
1 files changed, 1198 insertions, 1189 deletions
diff --git a/sys/dev/pci/ahc_pci.c b/sys/dev/pci/ahc_pci.c index 3e17732547c..b15714f84a0 100644 --- a/sys/dev/pci/ahc_pci.c +++ b/sys/dev/pci/ahc_pci.c @@ -1,87 +1,597 @@ -/* $OpenBSD: ahc_pci.c,v 1.41 2003/09/25 07:11:15 deraadt Exp $ */ -/* $NetBSD: ahc_pci.c,v 1.9 1996/10/21 22:56:24 thorpej Exp $ */ - +/* $OpenBSD: ahc_pci.c,v 1.42 2003/12/24 22:45:45 krw Exp $ */ /* * Product specific probe and attach routines for: - * 3940, 2940, aic7880, aic7870, aic7860 and aic7850 SCSI controllers + * 3940, 2940, aic7895, aic7890, aic7880, + * aic7870, aic7860 and aic7850 SCSI controllers * - * Copyright (c) 1995, 1996 Justin T. Gibbs. + * 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 immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 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. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * 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 DAMAGE. + * 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: ahc_pci.c,v 1.42 2003/12/24 22:45:45 krw Exp $ + * + * //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#57 $ + * + * $FreeBSD: /repoman/r/ncvs/src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.22 2003/01/20 20:44:55 gibbs Exp $ + */ +/* + * Ported from FreeBSD by Pascal Renauld, Network Storage Solutions, Inc. - April 2003 */ +#include <sys/cdefs.h> +/* __KERNEL_RCSID(0, "$NetBSD: ahc_pci.c,v 1.43 2003/08/18 09:16:22 taca Exp $"); */ + #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> #include <sys/kernel.h> #include <sys/queue.h> #include <sys/device.h> +#include <sys/reboot.h> + #include <machine/bus.h> #include <machine/intr.h> -#include <scsi/scsi_all.h> -#include <scsi/scsiconf.h> - #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> -#include <dev/pci/pcidevs.h> #define AHC_PCI_IOADDR PCI_MAPREG_START /* I/O Address */ #define AHC_PCI_MEMADDR (PCI_MAPREG_START + 4) /* Mem I/O Address */ -#include <dev/ic/aic7xxxreg.h> #include <dev/ic/aic7xxx_openbsd.h> #include <dev/ic/aic7xxx_inline.h> + #include <dev/ic/smc93cx6var.h> -/* - * XXX memory-mapped is busted on some i386 on-board chips. - * for i386, we don't even try it. Also, suppress the damn - * PCI bus errors messages on i386. They are not fatal, and are - * usually caused by some other device on the PCI bus. But some - * ahc cards won't work without ACKing them. So just ACK and go! - * XXX- smurph - */ -#ifndef i386 -#define AHC_ALLOW_MEMIO -#define AHC_SHOW_PCI_ERRORS -#endif +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 ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull +#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull +#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull +#define ID_9005_SISL_MASK 0x000FFFFF00000000ull +#define ID_9005_SISL_ID 0x0005900500000000ull +#define ID_AIC7850 0x5078900400000000ull +#define ID_AHA_2902_04_10_15_20_30C 0x5078900478509004ull +#define ID_AIC7855 0x5578900400000000ull +#define ID_AIC7859 0x3860900400000000ull +#define ID_AHA_2930CU 0x3860900438699004ull +#define ID_AIC7860 0x6078900400000000ull +#define ID_AIC7860C 0x6078900478609004ull +#define ID_AHA_1480A 0x6075900400000000ull +#define ID_AHA_2940AU_0 0x6178900400000000ull +#define ID_AHA_2940AU_1 0x6178900478619004ull +#define ID_AHA_2940AU_CN 0x2178900478219004ull +#define ID_AHA_2930C_VAR 0x6038900438689004ull + +#define ID_AIC7870 0x7078900400000000ull +#define ID_AHA_2940 0x7178900400000000ull +#define ID_AHA_3940 0x7278900400000000ull +#define ID_AHA_398X 0x7378900400000000ull +#define ID_AHA_2944 0x7478900400000000ull +#define ID_AHA_3944 0x7578900400000000ull +#define ID_AHA_4944 0x7678900400000000ull + +#define ID_AIC7880 0x8078900400000000ull +#define ID_AIC7880_B 0x8078900478809004ull +#define ID_AHA_2940U 0x8178900400000000ull +#define ID_AHA_3940U 0x8278900400000000ull +#define ID_AHA_2944U 0x8478900400000000ull +#define ID_AHA_3944U 0x8578900400000000ull +#define ID_AHA_398XU 0x8378900400000000ull +#define ID_AHA_4944U 0x8678900400000000ull +#define ID_AHA_2940UB 0x8178900478819004ull +#define ID_AHA_2930U 0x8878900478889004ull +#define ID_AHA_2940U_PRO 0x8778900478879004ull +#define ID_AHA_2940U_CN 0x0078900478009004ull + +#define ID_AIC7895 0x7895900478959004ull +#define ID_AIC7895_ARO 0x7890900478939004ull +#define ID_AIC7895_ARO_MASK 0xFFF0FFFFFFFFFFFFull +#define ID_AHA_2940U_DUAL 0x7895900478919004ull +#define ID_AHA_3940AU 0x7895900478929004ull +#define ID_AHA_3944AU 0x7895900478949004ull + +#define ID_AIC7890 0x001F9005000F9005ull +#define ID_AIC7890_ARO 0x00139005000F9005ull +#define ID_AAA_131U2 0x0013900500039005ull +#define ID_AHA_2930U2 0x0011900501819005ull +#define ID_AHA_2940U2B 0x00109005A1009005ull +#define ID_AHA_2940U2_OEM 0x0010900521809005ull +#define ID_AHA_2940U2 0x00109005A1809005ull +#define ID_AHA_2950U2B 0x00109005E1009005ull + +#define ID_AIC7892 0x008F9005FFFF9005ull +#define ID_AIC7892_ARO 0x00839005FFFF9005ull +#define ID_AHA_2915LP 0x0082900502109005ull +#define ID_AHA_29160 0x00809005E2A09005ull +#define ID_AHA_29160_CPQ 0x00809005E2A00E11ull +#define ID_AHA_29160N 0x0080900562A09005ull +#define ID_AHA_29160C 0x0080900562209005ull +#define ID_AHA_29160B 0x00809005E2209005ull +#define ID_AHA_19160B 0x0081900562A19005ull + +#define ID_AIC7896 0x005F9005FFFF9005ull +#define ID_AIC7896_ARO 0x00539005FFFF9005ull +#define ID_AHA_3950U2B_0 0x00509005FFFF9005ull +#define ID_AHA_3950U2B_1 0x00509005F5009005ull +#define ID_AHA_3950U2D_0 0x00519005FFFF9005ull +#define ID_AHA_3950U2D_1 0x00519005B5009005ull + +#define ID_AIC7899 0x00CF9005FFFF9005ull +#define ID_AIC7899_ARO 0x00C39005FFFF9005ull +#define ID_AHA_3960D 0x00C09005F6209005ull +#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull + +#define ID_AIC7810 0x1078900400000000ull +#define ID_AIC7815 0x7815900400000000ull + +#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) /* - * Under normal circumstances, these messages are unnecessary - * and not terribly cosmetic. + * Informational only. Should use chip register to be + * certain, but may be use in identification strings. */ -#ifdef DEBUG -#define bootverbose 1 -#else -#define bootverbose 0 -#endif - -#define PCI_BASEADR0 PCI_MAPREG_START +#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_20_30C, + ID_ALL_MASK, + ahc_aic785X_setup + }, + /* aic7860 based controllers */ + { + ID_AHA_2930CU, + ID_ALL_MASK, + ahc_aic7860_setup + }, + { + ID_AHA_1480A & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_apa1480_setup + }, + { + ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7860_setup + }, + { + ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7860_setup + }, + { + ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7860_setup + }, + /* aic7870 based controllers */ + { + ID_AHA_2940, + ID_ALL_MASK, + ahc_aic7870_setup + }, + { + ID_AHA_3940, + ID_ALL_MASK, + ahc_aha394X_setup + }, + { + ID_AHA_398X, + ID_ALL_MASK, + ahc_aha398X_setup + }, + { + ID_AHA_2944, + ID_ALL_MASK, + ahc_aic7870_setup + }, + { + ID_AHA_3944, + ID_ALL_MASK, + ahc_aha394X_setup + }, + { + ID_AHA_4944, + ID_ALL_MASK, + ahc_aha494X_setup + }, + /* aic7880 based controllers */ + { + ID_AHA_2940U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7880_setup + }, + { + ID_AHA_3940U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aha394XU_setup + }, + { + ID_AHA_2944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7880_setup + }, + { + ID_AHA_3944U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aha394XU_setup + }, + { + ID_AHA_398XU & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + 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, + ahc_aic7880_setup + }, + { + ID_AHA_2930U & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7880_setup + }, + { + ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aha2940Pro_setup + }, + { + ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7880_setup + }, + /* Ignore all SISL (AAC on MB) based controllers. */ + { + ID_9005_SISL_ID, + ID_9005_SISL_MASK, + NULL + }, + /* aic7890 based controllers */ + { + ID_AHA_2930U2, + ID_ALL_MASK, + ahc_aic7890_setup + }, + { + ID_AHA_2940U2B, + ID_ALL_MASK, + ahc_aic7890_setup + }, + { + ID_AHA_2940U2_OEM, + ID_ALL_MASK, + ahc_aic7890_setup + }, + { + ID_AHA_2940U2, + ID_ALL_MASK, + ahc_aic7890_setup + }, + { + ID_AHA_2950U2B, + ID_ALL_MASK, + ahc_aic7890_setup + }, + { + ID_AIC7890_ARO, + ID_ALL_MASK, + ahc_aic7890_setup + }, + { + ID_AAA_131U2, + ID_ALL_MASK, + ahc_aic7890_setup + }, + /* aic7892 based controllers */ + { + ID_AHA_29160, + ID_ALL_MASK, + ahc_aic7892_setup + }, + { + ID_AHA_29160_CPQ, + ID_ALL_MASK, + ahc_aic7892_setup + }, + { + ID_AHA_29160N, + ID_ALL_MASK, + ahc_aic7892_setup + }, + { + ID_AHA_29160C, + ID_ALL_MASK, + ahc_aha29160C_setup + }, + { + ID_AHA_29160B, + ID_ALL_MASK, + ahc_aic7892_setup + }, + { + ID_AHA_19160B, + ID_ALL_MASK, + ahc_aic7892_setup + }, + { + ID_AIC7892_ARO, + ID_ALL_MASK, + ahc_aic7892_setup + }, + { + ID_AHA_2915LP, + ID_ALL_MASK, + ahc_aic7892_setup + }, + /* aic7895 based controllers */ + { + ID_AHA_2940U_DUAL, + ID_ALL_MASK, + ahc_aic7895_setup + }, + { + ID_AHA_3940AU, + ID_ALL_MASK, + ahc_aic7895_setup + }, + { + ID_AHA_3944AU, + ID_ALL_MASK, + ahc_aic7895_setup + }, + { + ID_AIC7895_ARO, + ID_AIC7895_ARO_MASK, + ahc_aic7895_setup + }, + /* aic7896/97 based controllers */ + { + ID_AHA_3950U2B_0, + ID_ALL_MASK, + ahc_aic7896_setup + }, + { + ID_AHA_3950U2B_1, + ID_ALL_MASK, + ahc_aic7896_setup + }, + { + ID_AHA_3950U2D_0, + ID_ALL_MASK, + ahc_aic7896_setup + }, + { + ID_AHA_3950U2D_1, + ID_ALL_MASK, + ahc_aic7896_setup + }, + { + ID_AIC7896_ARO, + ID_ALL_MASK, + ahc_aic7896_setup + }, + /* aic7899 based controllers */ + { + ID_AHA_3960D, + ID_ALL_MASK, + ahc_aic7899_setup + }, + { + ID_AHA_3960D_CPQ, + ID_ALL_MASK, + ahc_aic7899_setup + }, + { + ID_AIC7899_ARO, + ID_ALL_MASK, + ahc_aic7899_setup + }, + /* Generic chip probes for devices we don't know 'exactly' */ + { + ID_AIC7850 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic785X_setup + }, + { + ID_AIC7855 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic785X_setup + }, + { + ID_AIC7859 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7860_setup + }, + { + ID_AIC7860 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7860_setup + }, + { + ID_AIC7870 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7870_setup + }, + { + ID_AIC7880 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7880_setup + }, + { + ID_AIC7890 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + ahc_aic7890_setup + }, + { + ID_AIC7892 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + ahc_aic7892_setup + }, + { + ID_AIC7895 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_aic7895_setup + }, + { + ID_AIC7896 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + ahc_aic7896_setup + }, + { + ID_AIC7899 & ID_9005_GENERIC_MASK, + ID_9005_GENERIC_MASK, + ahc_aic7899_setup + }, + { + ID_AIC7810 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + ahc_raid_setup + }, + { + ID_AIC7815 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + 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 @@ -89,425 +599,201 @@ #define AHC_398X_SLOT_CHANNEL_B 8 #define AHC_398X_SLOT_CHANNEL_C 12 -#define EXROMBADR 0x30 -#define EXROMEN 0x00000001UL /* External Rom Enable */ +#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 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 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 - -static int ahc_ext_scbram_present(struct ahc_softc *ahc); +#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 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, u_int8_t value); -static u_int8_t read_brdctl(struct ahc_softc *ahc); - -int ahc_do_pci_config(struct ahc_softc *ahc); - -void load_seeprom(struct ahc_softc *ahc); -static int acquire_seeprom(struct ahc_softc *ahc, - struct seeprom_descriptor *sd); -static void release_seeprom(struct seeprom_descriptor *sd); -static int verify_cksum(struct seeprom_config *); -int ahc_probe_scbs(struct ahc_softc *ahc); - -static u_char aic3940_count; int ahc_pci_probe(struct device *, void *, void *); void ahc_pci_attach(struct device *, struct device *, void *); + struct cfattach ahc_pci_ca = { sizeof(struct ahc_softc), ahc_pci_probe, ahc_pci_attach }; -const struct pci_matchid ahc_pci_devices[] = { - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7810 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7850 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7855 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7860 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940AU }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7870 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2930CU }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3940 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3985 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2944 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC7880 }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940U }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_3940U }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_398XU }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2944U }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_2940UWPro }, - { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_7895 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AAA131U2 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7890 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_2940U2 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_2930U2 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7892 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_29160 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_19160B }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3950U2B }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3950U2D }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7896 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899B }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899D }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899F }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AIC7899 }, - { PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_3960D }, -}; +const struct ahc_pci_identity * +ahc_find_pci_device(id, subid, func) + pcireg_t id, subid; + u_int func; +{ + u_int64_t full_id; + const struct ahc_pci_identity *entry; + u_int i; + + full_id = ahc_compose_id(PCI_PRODUCT(id), PCI_VENDOR(id), + PCI_PRODUCT(subid), PCI_VENDOR(subid)); + + /* + * 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 (func > 0 + && ahc_9005_subdevinfo_valid(PCI_VENDOR(id), PCI_PRODUCT(id), + PCI_VENDOR(subid), PCI_PRODUCT(subid)) + && SUBID_9005_MFUNCENB(PCI_PRODUCT(subid)) == 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)) + return (entry); + } + return (NULL); +} int ahc_pci_probe(parent, match, aux) -struct device *parent; -void *match, *aux; + struct device *parent; + void *match, *aux; { - return (pci_matchbyid((struct pci_attach_args *)aux, ahc_pci_devices, - sizeof(ahc_pci_devices)/sizeof(ahc_pci_devices[0]))); + struct pci_attach_args *pa = aux; + const struct ahc_pci_identity *entry; + pcireg_t subid; + + subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); + entry = ahc_find_pci_device(pa->pa_id, subid, pa->pa_function); + return (entry != NULL && entry->setup != NULL) ? 1 : 0; } void ahc_pci_attach(parent, self, aux) -struct device *parent, *self; -void *aux; + struct device *parent, *self; + void *aux; { struct pci_attach_args *pa = aux; - struct ahc_softc *ahc = (void *)self; - pcireg_t devconfig; - pcireg_t command; + const struct ahc_pci_identity *entry; + struct ahc_softc *ahc = (void *)self; + pcireg_t command; + u_int our_id = 0; + u_int sxfrctl1; + u_int scsiseq; + u_int sblkctl; + uint8_t dscommand0; + uint32_t devconfig; + int error; + pcireg_t subid; + int ioh_valid, memh_valid; + bus_space_tag_t st, iot; + bus_space_handle_t sh, ioh; +#ifdef AHC_ALLOW_MEMIO + bus_space_tag_t memt; + bus_space_handle_t memh; + pcireg_t memtype; +#endif + pci_intr_handle_t ih; + const char *intrstr; + struct ahc_pci_busdata *bd; - /* setup the PCI stuff */ ahc->dev_softc = pa; - /* - * We really don't allocate our softc, but - * we need to do the initialization. And this - * also allocates the platform_data structure. - */ - ahc_alloc(ahc, NULL); ahc_set_name(ahc, ahc->sc_dev.dv_xname); - ahc_set_unit(ahc, ahc->sc_dev.dv_unit); - - /* set dma tags */ ahc->parent_dmat = pa->pa_dmat; - ahc->buffer_dmat = pa->pa_dmat; - ahc->shared_data_dmat = pa->pa_dmat; - - /* card specific setup */ - switch (PCI_VENDOR(pa->pa_id)) { - case PCI_VENDOR_ADP: - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_ADP_7895: - ahc->channel = pa->pa_function == 1 ? 'B' : 'A'; - /* The 'C' revision of the aic7895 - has a few additional features */ - if (PCI_REVISION(pa->pa_class) >= 4){ - ahc->chip |= AHC_AIC7895C; - } else { - ahc->chip |= AHC_AIC7895; - } - break; - case PCI_PRODUCT_ADP_3940U: - case PCI_PRODUCT_ADP_3940: - if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ADP_3940U) { - ahc->chip |= AHC_AIC7880; - } else { - ahc->chip |= AHC_AIC7870; - } - aic3940_count++; - if (!(aic3940_count & 0x01)) - /* Even count implies second channel */ - ahc->channel = 'B'; - break; - case PCI_PRODUCT_ADP_2940UWPro: - ahc->flags |= AHC_INT50_SPEEDFLEX; - /* fall through */ - case PCI_PRODUCT_ADP_AIC7880: - case PCI_PRODUCT_ADP_398XU: /* XXX */ - case PCI_PRODUCT_ADP_2944U: - case PCI_PRODUCT_ADP_2940U: - ahc->chip |= AHC_AIC7880; - break; - case PCI_PRODUCT_ADP_AIC7870: - case PCI_PRODUCT_ADP_2944: - case PCI_PRODUCT_ADP_2940: - ahc->chip |= AHC_AIC7870; - break; - case PCI_PRODUCT_ADP_AIC7860: - case PCI_PRODUCT_ADP_2940AU: - ahc->chip |= AHC_AIC7860; - break; - case PCI_PRODUCT_ADP_AIC7855: - case PCI_PRODUCT_ADP_AIC7850: - ahc->chip |= AHC_AIC7850; - break; - default: - /* TTT */ - break; - } - break; - case PCI_VENDOR_ADP2: - switch (PCI_PRODUCT(pa->pa_id)) { - case PCI_PRODUCT_ADP2_AIC7890: - case PCI_PRODUCT_ADP2_2940U2: - case PCI_PRODUCT_ADP2_2930U2: - case PCI_PRODUCT_ADP2_AAA131U2: - ahc->chip |= AHC_AIC7890; - break; - case PCI_PRODUCT_ADP2_AIC7892: - case PCI_PRODUCT_ADP2_29160: - case PCI_PRODUCT_ADP2_19160B: - ahc->chip |= AHC_AIC7892; - break; - case PCI_PRODUCT_ADP2_3950U2B: - case PCI_PRODUCT_ADP2_3950U2D: - case PCI_PRODUCT_ADP2_AIC7896: - ahc->chip |= AHC_AIC7896; - ahc->channel = pa->pa_function == 1 ? 'B' : 'A'; - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, 4); - /* turn off 64 bit for now XXX smurph */ - devconfig &= ~PCI64BIT; - ahc_pci_write_config(ahc->dev_softc, - DEVCONFIG, devconfig, 4); - break; - case PCI_PRODUCT_ADP2_AIC7899: - case PCI_PRODUCT_ADP2_3960D: - ahc->chip |= AHC_AIC7899; - ahc->channel = pa->pa_function == 1 ? 'B' : 'A'; - break; - default: - /* TTT */ - break; - } - } - - /* chip specific setup */ - switch(ahc->chip){ - case AHC_AIC7850: - case AHC_AIC7855: - case AHC_AIC7859: - ahc->features = AHC_AIC7850_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - if (PCI_REVISION(pa->pa_class) >= 1) - ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; - break; - case AHC_AIC7860: - ahc->features = AHC_AIC7860_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - if (PCI_REVISION(pa->pa_class) >= 1) - ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; - break; - case AHC_AIC7870: - ahc->features = AHC_AIC7870_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - break; - case AHC_AIC7880: - ahc->features = AHC_AIC7880_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG; - if (PCI_REVISION(pa->pa_class) >= 1) { - ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; - } else { - ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - } - break; - case AHC_AIC7895: - ahc->features = AHC_AIC7895_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - /* - * The BIOS disables the use of MWI transactions - * since it does not have the MWI bug work around - * we have. Disabling MWI reduces performance, so - * turn it on again. - */ - command = pci_conf_read(pa->pa_pc, pa->pa_tag, - PCI_COMMAND_STATUS_REG); - command |= PCI_COMMAND_INVALIDATE_ENABLE; - pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, - command); - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG - | AHC_CACHETHEN_BUG | AHC_PCI_MWI_BUG; - break; - case AHC_AIC7895C: - ahc->features = AHC_AIC7895C_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG - | AHC_CACHETHEN_BUG; - break; - case AHC_AIC7890: - ahc->features = AHC_AIC7890_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - if (PCI_REVISION(pa->pa_class) == 0) - ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; - break; - case AHC_AIC7892: - ahc->features = AHC_AIC7892_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; - break; - case AHC_AIC7896: - ahc->features = AHC_AIC7896_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_CACHETHEN_DIS_BUG; - break; - case AHC_AIC7899: - ahc->features = AHC_AIC7899_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; - break; - default: - break; - } - /* setup the PCI interrupt */ - ahc->bus_intr = ahc_pci_intr; - ahc->unsolicited_ints = 0; + command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); + subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); + entry = ahc_find_pci_device(pa->pa_id, subid, pa->pa_function); + if (entry == NULL) + return; - if(ahc_do_pci_config(ahc)){ - ahc_free(ahc); + /* Keep information about the PCI bus */ + bd = malloc(sizeof (struct ahc_pci_busdata), M_DEVBUF, M_NOWAIT); + if (bd == NULL) { + printf("%s: unable to allocate bus-specific data\n", ahc_name(ahc)); return; } - - ahc_attach(ahc); -} + memset(bd, 0, sizeof(struct ahc_pci_busdata)); + + bd->pc = pa->pa_pc; + bd->tag = pa->pa_tag; + bd->func = pa->pa_function; + bd->dev = pa->pa_device; + bd->class = pa->pa_class; + + ahc->bd = bd; + + error = entry->setup(ahc); + if (error != 0) + return; + + ioh_valid = memh_valid = 0; -int -ahc_pci_map_registers(ahc) - struct ahc_softc *ahc; -{ - pcireg_t command; - int ioh_valid; - bus_space_tag_t iot; - bus_space_handle_t ioh; - struct pci_attach_args *pa = ahc->dev_softc; - - command = ahc_pci_read_config(ahc->dev_softc, - PCI_COMMAND_STATUS_REG, 4); #ifdef AHC_ALLOW_MEMIO - /* - * attempt to use memory mapping on hardware that supports it. - * e.g powerpc XXX - smurph - * - * Note: If this fails, IO mapping is used. - */ - if ((command & PCI_COMMAND_MEM_ENABLE) != 0) { - pcireg_t memtype; - memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AHC_PCI_MEMADDR); - switch (memtype) { - case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: - case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: - ioh_valid = (pci_mapreg_map(pa, AHC_PCI_MEMADDR, - memtype, 0, &iot, &ioh, NULL, NULL, 0) == 0); - break; - default: - ioh_valid = 0; - } - if (ioh_valid) { - /* - * Do a quick test to see if memory mapped - * I/O is functioning correctly. - */ - ahc->tag = iot; - ahc->bsh = ioh; - if (ahc_inb(ahc, HCNTRL) == 0xFF) { - /* nope, use I/O mapping */ - ioh_valid = 0; - } else { - /* Using memory mapping, disable I/O mapping */ - command &= ~PCI_COMMAND_IO_ENABLE; - ahc_pci_write_config(ahc->dev_softc, - PCI_COMMAND_STATUS_REG, - command, 4); - } - } + memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AHC_PCI_MEMADDR); + switch (memtype) { + case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: + case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: + memh_valid = (pci_mapreg_map(pa, AHC_PCI_MEMADDR, + memtype, 0, &memt, &memh, NULL, NULL, 0) == 0); + break; + default: + memh_valid = 0; } - - if (!ioh_valid) /* try to drop back to IO mapping */ #endif - { - ioh_valid = (pci_mapreg_map(pa, AHC_PCI_IOADDR, - PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, NULL, NULL, 0) == 0); - - /* Using I/O mapping, disable memory mapping */ - command &= ~PCI_COMMAND_MEM_ENABLE; - ahc_pci_write_config(ahc->dev_softc, - PCI_COMMAND_STATUS_REG, - command, 4); - } + ioh_valid = (pci_mapreg_map(pa, AHC_PCI_IOADDR, + PCI_MAPREG_TYPE_IO, 0, &iot, + &ioh, NULL, NULL, 0) == 0); +#if 0 + printf("%s: mem mapping: memt 0x%x, memh 0x%x, iot 0x%x, ioh 0x%lx\n", + ahc_name(ahc), memt, (u_int32_t)memh, (u_int32_t)iot, ioh); +#endif - if (!ioh_valid) { - /* Game Over. Insert coin... */ + if (ioh_valid) { + st = iot; + sh = ioh; +#ifdef AHC_ALLOW_MEMIO + } else if (memh_valid) { + st = memt; + sh = memh; +#endif + } else { printf(": unable to map registers\n"); - return (1); + return; } - ahc->tag = iot; - ahc->bsh = ioh; - return (0); -} - -int -ahc_do_pci_config(ahc) - struct ahc_softc *ahc; -{ - pcireg_t command; - u_int our_id = 0; - u_int sxfrctl1; - u_int scsiseq; - u_int dscommand0; - int error; - int opri; - uint8_t sblkctl; - + ahc->tag = st; + ahc->bsh = sh; ahc->chip |= AHC_PCI; -#if 0 - ahc_power_state_change(ahc, AHC_POWER_STATE_D0); -#endif - error = ahc_pci_map_registers(ahc); - if (error != 0) - return (error); - /* - * Registers are mapped. Now it is safe to use - * the ahc_inb and ahc_outb macros. - */ - - /* + /* * 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 @@ -516,34 +802,53 @@ ahc_do_pci_config(ahc) ahc_intr_enable(ahc, FALSE); /* + * XXX somehow reading this once fails on some sparc64 systems. + * This may be a problem in the sparc64 PCI code. Doing it + * twice works around it. + */ + devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG); + devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG); + + /* * 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) { - pcireg_t devconfig; - if (bootverbose) + if (1/*bootverbose*/) printf("%s: Enabling 39Bit Addressing\n", ahc_name(ahc)); - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); devconfig |= DACEN; - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4); } + /* Ensure that pci error generation, a test feature, is disabled. */ + devconfig |= PCIERRGENDIS; + + pci_conf_write(pa->pa_pc, pa->pa_tag, DEVCONFIG, devconfig); + /* Ensure busmastering is enabled */ - command = ahc_pci_read_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, 4); - command |= PCI_COMMAND_MASTER_ENABLE; + command |= PCI_COMMAND_MASTER_ENABLE;; + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); + + /* + * Disable PCI parity error reporting. Users typically + * do this to work around broken PCI chipsets that get + * the parity timing wrong and thus generate lots of spurious + * errors. + */ + if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) + command &= ~PCI_COMMAND_PARITY_ENABLE; + pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); - ahc_pci_write_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, command, 4); - /* On all PCI adapters, we allow SCB paging */ ahc->flags |= AHC_PAGESCBS; - error = ahc_softc_init(ahc); if (error != 0) - return (error); + goto error_out; + + ahc->bus_intr = ahc_pci_intr; /* Remember how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { @@ -562,7 +867,7 @@ ahc_do_pci_config(ahc) error = ahc_reset(ahc); if (error != 0) - return (ENXIO); + goto error_out; if ((ahc->features & AHC_DT) != 0) { u_int sfunct; @@ -579,12 +884,27 @@ ahc_do_pci_config(ahc) |TARGCRCENDEN); } - /* - * Protect ourself from spurrious interrupts during - * initialization. - */ - opri = splbio(); - + if (pci_intr_map(pa, &ih)) { + printf("%s: couldn't map interrupt\n", ahc_name(ahc)); + ahc_free(ahc); + return; + } + intrstr = pci_intr_string(pa->pa_pc, ih); + ahc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, + ahc_platform_intr, ahc, ahc->sc_dev.dv_xname); + if (ahc->ih == NULL) { + printf("%s: couldn't establish interrupt", + ahc->sc_dev.dv_xname); + if (intrstr != NULL) + printf(" at %s", intrstr); + printf("\n"); + ahc_free(ahc); + return; + } + printf("\n"); + if (intrstr != NULL) + printf("%s: interrupting at %s\n", ahc_name(ahc), intrstr); + dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -607,34 +927,38 @@ ahc_do_pci_config(ahc) dscommand0 &= ~CACHETHEN; ahc_outb(ahc, DSCOMMAND0, dscommand0); - - ahc->pci_cachesize = ahc_pci_read_config(ahc->dev_softc, - CSIZE_LATTIME, 4) & CACHESIZE; + + ahc->pci_cachesize = + pci_conf_read(pa->pa_pc, pa->pa_tag, CSIZE_LATTIME) & CACHESIZE; ahc->pci_cachesize *= 4; if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0 - && ahc->pci_cachesize == 4) { - u_int csl = ahc_pci_read_config(ahc->dev_softc, - CSIZE_LATTIME, 4); - csl &= ~CACHESIZE; - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, csl, 4); + && ahc->pci_cachesize == 4) { + pci_conf_write(pa->pa_pc, pa->pa_tag, CSIZE_LATTIME, 0); ahc->pci_cachesize = 0; } /* - * We cannot perform ULTRA speeds without the presense + * We cannot perform ULTRA speeds without the presence * of the external precision resistor. */ if ((ahc->features & AHC_ULTRA) != 0) { uint32_t devconfig; - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); + devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG); if ((devconfig & REXTVALID) == 0) ahc->features &= ~AHC_ULTRA; } + ahc->seep_config = malloc(sizeof(*ahc->seep_config), + M_DEVBUF, M_NOWAIT); + if (ahc->seep_config == NULL) + goto error_out; + + memset(ahc->seep_config, 0, sizeof(*ahc->seep_config)); + /* See if we have a SEEPROM and perform auto-term */ - check_extport(ahc, &sxfrctl1); + ahc_check_extport(ahc, &sxfrctl1); /* * Take the LED out of diagnostic mode @@ -655,7 +979,8 @@ ahc_do_pci_config(ahc) * a SEEPROM. */ /* See if someone else set us up already */ - if (scsiseq != 0) { + 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; @@ -687,63 +1012,53 @@ ahc_do_pci_config(ahc) if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; - /* Core initialization */ - error = ahc_init(ahc); - if (error != 0) - return (error); - - /* Special func to force negotiation */ - ahc_force_neg(ahc); - - /* - * Link this softc in with all other ahc instances. - */ - ahc_softc_insert(ahc); + if (ahc_init(ahc)) + goto error_out; - /* - * Allow interrupts now that we are completely setup. - */ - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); + ahc_attach(ahc); - ahc_intr_enable(ahc, TRUE); - splx(opri); + return; - return (0); + error_out: + ahc_free(ahc); + return; } -int -ahc_pci_map_int(ahc) - struct ahc_softc *ahc; +static int +ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor, + uint16_t subdevice, uint16_t subvendor) { - const char *intrstr = NULL; - pci_intr_handle_t ih; - struct pci_attach_args *pa = ahc->dev_softc; - - if (pci_intr_map(pa, &ih)) { - printf(": couldn't map interrupt\n"); - return 1; - } - intrstr = pci_intr_string(pa->pa_pc, ih); - - ahc->platform_data->ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, - ahc_platform_intr, ahc, - ahc->sc_dev.dv_xname); - - if (ahc->platform_data->ih == NULL) { - printf(": couldn't establish interrupt"); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - return 1; + 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; + } } - - if (intrstr != NULL) - printf(": %s\n", intrstr); - return 0; + return (result); } + /* * Test for the presense of external sram in an * "unshared" configuration. @@ -755,15 +1070,21 @@ ahc_ext_scbram_present(struct ahc_softc *ahc) int ramps; int single_user; uint32_t devconfig; - - chip = ahc->chip & AHC_CHIPID_MASK; - - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); + chip = ahc->chip & AHC_CHIPID_MASK; + devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG); 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 @@ -778,24 +1099,23 @@ ahc_ext_scbram_present(struct ahc_softc *ahc) * Enable external scbram. */ static void -ahc_scbram_config(ahc, enable, pcheck, fast, large) - struct ahc_softc *ahc; - int enable; - int pcheck; - int fast; - int large; +ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, + int fast, int large) { - pcireg_t devconfig; + 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_outb(ahc, SCBBADDR, ahc->bd->func); } - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, 4); + ahc->flags &= ~AHC_LSCBS_ENABLED; + if (large) + ahc->flags |= AHC_LSCBS_ENABLED; + devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG); if ((ahc->features & AHC_ULTRA2) != 0) { u_int dscommand0; @@ -828,7 +1148,7 @@ ahc_scbram_config(ahc, enable, pcheck, fast, large) else devconfig &= ~EXTSCBPEN; - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, 4); + pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig); } /* @@ -837,8 +1157,7 @@ ahc_scbram_config(ahc, enable, pcheck, fast, large) * shared among multiple controllers. */ static void -ahc_probe_ext_scbram(ahc) - struct ahc_softc *ahc; +ahc_probe_ext_scbram(struct ahc_softc *ahc) { int num_scbs; int test_num_scbs; @@ -925,7 +1244,7 @@ done: /* Clear any latched parity error */ ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); - if (bootverbose && enable) { + if (1/*bootverbose*/ && enable) { printf("%s: External SRAM, %s access%s, %dbytes/SCB\n", ahc_name(ahc), fast ? "fast" : "slow", pcheck ? ", parity checking enabled" : "", @@ -934,759 +1253,449 @@ done: ahc_scbram_config(ahc, enable, pcheck, fast, large); } +#if 0 /* - * Check the external port logic for a serial eeprom - * and termination/cable detection contrls. + * Perform some simple tests that should catch situations where + * our registers are invalidly mapped. */ -static void -check_extport(ahc, sxfrctl1) - struct ahc_softc *ahc; - u_int *sxfrctl1; +int +ahc_pci_test_register_access(struct ahc_softc *ahc) { - struct seeprom_descriptor sd; - struct seeprom_config sc; - u_int scsi_conf; - u_int adapter_control; - int have_seeprom; - int have_autoterm; - - sd.sd_tag = ahc->tag; - sd.sd_bsh = ahc->bsh; - sd.sd_regsize = 1; - sd.sd_control_offset = SEECTL; - sd.sd_status_offset = SEECTL; - sd.sd_dataout_offset = SEECTL; + int error; + u_int status1; + uint32_t cmd; + uint8_t hcntrl; + + error = EIO; /* - * For some multi-channel devices, the c46 is simply too - * small to work. For the other controller types, we can - * get our information from either SEEPROM type. Set the - * type to start our probe with accordingly. + * Enable PCI error interrupt status, but suppress NMIs + * generated by SERR raised due to target aborts. */ - if (ahc->flags & AHC_LARGE_SEEPROM) - sd.sd_chip = C56_66; - else - sd.sd_chip = C46; - - sd.sd_MS = SEEMS; - sd.sd_RDY = SEERDY; - sd.sd_CS = SEECS; - sd.sd_CK = SEECK; - sd.sd_DO = SEEDO; - sd.sd_DI = SEEDI; + cmd = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCIR_COMMAND); + pci_conf_write(ahc->bd->pc, ahc->bd->tag, PCIR_COMMAND, + cmd & ~PCIM_CMD_SERRESPEN); - have_seeprom = acquire_seeprom(ahc, &sd); - if (have_seeprom) { + /* + * 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; - if (bootverbose) - printf("%s: Reading SEEPROM...", ahc_name(ahc)); + /* + * 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. + */ + ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); + while (ahc_is_paused(ahc) == 0) + ; + 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 = pci_conf_read(ahc->bd->pc, ahc->bd->tag, + PCI_COMMAND_STATUS_REG + 1); + if ((status1 & STA) != 0) + goto fail; + + error = 0; + +fail: + /* Silently clear any latched errors. */ + status1 = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG + 1); + ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, + status1, /*bytes*/1); + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); + return (error); +} +#endif - for (;;) { - u_int start_addr; +void +ahc_pci_intr(struct ahc_softc *ahc) +{ + u_int error; + u_int status1; - start_addr = 32 * (ahc->channel - 'A'); + error = ahc_inb(ahc, ERROR); + if ((error & PCIERRSTAT) == 0) + return; - have_seeprom = read_seeprom(&sd, (uint16_t *)&sc, - start_addr, sizeof(sc)/2); + status1 = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG); - if (have_seeprom) - have_seeprom = verify_cksum(&sc); + printf("%s: PCI error Interrupt at seqaddr = 0x%x\n", + ahc_name(ahc), + ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - if (have_seeprom != 0 || sd.sd_chip == C56_66) { - if (bootverbose) { - if (have_seeprom == 0) - printf ("checksum error\n"); - else - printf ("done.\n"); - } - break; - } - sd.sd_chip = C56_66; - } - release_seeprom(&sd); + if (status1 & DPE) { + printf("%s: Data Parity Error Detected during address " + "or write data phase\n", ahc_name(ahc)); } - - if (!have_seeprom) { - /* - * Pull scratch ram settings and treat them as - * if they are the contents of an seeprom if - * the 'ADPT' signature is found in SCB2. - * We manually compose the data as 16bit values - * to avoid endian issues. - */ - ahc_outb(ahc, SCBPTR, 2); - if (ahc_inb(ahc, SCB_BASE) == 'A' - && ahc_inb(ahc, SCB_BASE + 1) == 'D' - && ahc_inb(ahc, SCB_BASE + 2) == 'P' - && ahc_inb(ahc, SCB_BASE + 3) == 'T') { - uint16_t *sc_data; - int i; - - sc_data = (uint16_t *)≻ - for (i = 0; i < 32; i++) { - uint16_t val; - int j; - - j = i * 2; - val = ahc_inb(ahc, SRAM_BASE + j) - | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; - } - have_seeprom = verify_cksum(&sc); - } - /* - * Clear any SCB parity errors in case this data and - * its associated parity was not initialized by the BIOS - */ - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, CLRINT, CLRBRKADRINT); + if (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)); } - if (!have_seeprom) { - if (bootverbose) - printf("%s: No SEEPROM available.\n", ahc_name(ahc)); - ahc->flags |= AHC_USEDEFAULTS; - } else { - /* - * Put the data we've collected down into SRAM - * where ahc_init will find it. - */ - int i; - int max_targ = sc.max_targets & CFMAXTARG; - uint16_t discenable; - uint16_t ultraenb; - - discenable = 0; - ultraenb = 0; - if ((sc.adapter_control & CFULTRAEN) != 0) { - /* - * Determine if this adapter has a "newstyle" - * SEEPROM format. - */ - 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) { - /* Treat 10MHz as a non-ultra speed */ - 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); - - /* - * The ultra enable bits contain the - * high bit of the ultra2 sync rate - * field. - */ - 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; + /* Clear latched errors. */ + pci_conf_write(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG, status1); - scsi_conf = (ahc->our_id & 0x7); - if (sc.adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - if (sc.adapter_control & CFRESETB) - scsi_conf |= RESET_SCSI; + 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); + } - ahc->flags |= - (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; + ahc_unpause(ahc); +} - if (sc.bios_control & CFEXTEND) - ahc->flags |= AHC_EXTENDED_TRANS_A; +static int +ahc_aic785X_setup(struct ahc_softc *ahc) +{ + uint8_t rev; + + ahc->channel = 'A'; + ahc->chip = AHC_AIC7850; + ahc->features = AHC_AIC7850_FE; + ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; + rev = PCI_REVISION(ahc->bd->class); + if (rev >= 1) + ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; + return (0); +} - if (sc.bios_control & CFBIOSEN) - ahc->flags |= AHC_BIOS_ENABLED; - if (ahc->features & AHC_ULTRA - && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) { - /* Should we enable Ultra mode? */ - if (!(sc.adapter_control & CFULTRAEN)) - /* Treat us as a non-ultra card */ - ultraenb = 0; - } +static int +ahc_aic7860_setup(struct ahc_softc *ahc) +{ + uint8_t rev; + + 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 = PCI_REVISION(ahc->bd->class); + if (rev >= 1) + ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; + return (0); +} - if (sc.signature == CFSIGNATURE - || sc.signature == CFSIGNATURE2) { - pcireg_t devconfig; - - /* Honor the STPWLEVEL settings */ - 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); - } - /* Set SCSICONF info */ - 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); - } +static int +ahc_apa1480_setup(struct ahc_softc *ahc) +{ + int error; - /* - * Cards that have the external logic necessary to talk to - * a SEEPROM, are almost certain to have the remaining logic - * necessary for auto-termination control. This assumption - * hasn't failed yet... - */ - have_autoterm = have_seeprom; - if (have_seeprom) - adapter_control = sc.adapter_control; - else - adapter_control = CFAUTOTERM; + error = ahc_aic7860_setup(ahc); + if (error != 0) + return (error); + ahc->features |= AHC_REMOVABLE; + return (0); +} - /* - * Some low-cost chips have SEEPROM and auto-term control built - * in, instead of using a GAL. They can tell us directly - * if the termination logic is enabled. - */ - if ((ahc->features & AHC_SPIOCAP) != 0) { - if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) != 0) - have_autoterm = TRUE; - else - have_autoterm = FALSE; - } +static int +ahc_aic7870_setup(struct ahc_softc *ahc) +{ - if (have_autoterm) { - acquire_seeprom(ahc, &sd); - configure_termination(ahc, &sd, adapter_control, sxfrctl1); - release_seeprom(&sd); - } + ahc->channel = 'A'; + ahc->chip = AHC_AIC7870; + ahc->features = AHC_AIC7870_FE; + ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; + return (0); } -static void -configure_termination(struct ahc_softc *ahc, - struct seeprom_descriptor *sd, - u_int adapter_control, - u_int *sxfrctl1) +static int +ahc_aha394X_setup(struct ahc_softc *ahc) { - uint8_t brddat; - - brddat = 0; + int error; - /* - * Update the settings in sxfrctl1 to match the - * termination settings - */ - *sxfrctl1 = 0; - - /* - * SEECS must be on for the GALS to latch - * the data properly. Be sure to leave MS - * on or we will release the seeprom. - */ - SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); - if ((adapter_control & CFAUTOTERM) != 0 - || (ahc->features & AHC_NEW_TERMCTL) != 0) { - int internal50_present; - int internal68_present; - int externalcable_present; - int eeprom_present; - int enableSEC_low; - int enableSEC_high; - int enablePRI_low; - int enablePRI_high; - int sum; - - enableSEC_low = 0; - enableSEC_high = 0; - enablePRI_low = 0; - enablePRI_high = 0; - if ((ahc->features & AHC_NEW_TERMCTL) != 0) { - ahc_new_term_detect(ahc, &enableSEC_low, - &enableSEC_high, - &enablePRI_low, - &enablePRI_high, - &eeprom_present); - if ((adapter_control & CFSEAUTOTERM) == 0) { - if (bootverbose) - printf("%s: Manual SE Termination\n", - ahc_name(ahc)); - enableSEC_low = (adapter_control & CFSELOWTERM); - enableSEC_high = - (adapter_control & CFSEHIGHTERM); - } - if ((adapter_control & CFAUTOTERM) == 0) { - if (bootverbose) - printf("%s: Manual LVD Termination\n", - ahc_name(ahc)); - enablePRI_low = (adapter_control & CFSTERM); - enablePRI_high = (adapter_control & CFWSTERM); - } - /* Make the table calculations below happy */ - internal50_present = 0; - internal68_present = 1; - externalcable_present = 1; - } else if ((ahc->features & AHC_SPIOCAP) != 0) { - aic785X_cable_detect(ahc, &internal50_present, - &externalcable_present, - &eeprom_present); - } else { - aic787X_cable_detect(ahc, &internal50_present, - &internal68_present, - &externalcable_present, - &eeprom_present); - } + error = ahc_aic7870_setup(ahc); + if (error == 0) + error = ahc_aha394XX_setup(ahc); + return (error); +} - if ((ahc->features & AHC_WIDE) == 0) - internal68_present = 0; - - if (bootverbose - && (ahc->features & AHC_ULTRA2) == 0) { - printf("%s: internal 50 cable %s present", - ahc_name(ahc), - internal50_present ? "is":"not"); - - if ((ahc->features & AHC_WIDE) != 0) - printf(", internal 68 cable %s present", - internal68_present ? "is":"not"); - printf("\n%s: external cable %s present\n", - ahc_name(ahc), - externalcable_present ? "is":"not"); - } - if (bootverbose) - printf("%s: BIOS eeprom %s present\n", - ahc_name(ahc), eeprom_present ? "is" : "not"); +static int +ahc_aha398X_setup(struct ahc_softc *ahc) +{ + int error; - if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { - /* - * The 50 pin connector is a separate bus, - * so force it to always be terminated. - * In the future, perform current sensing - * to determine if we are in the middle of - * a properly terminated bus. - */ - internal50_present = 0; - } + error = ahc_aic7870_setup(ahc); + if (error == 0) + error = ahc_aha398XX_setup(ahc); + return (error); +} - /* - * Now set the termination based on what - * we found. - * Flash Enable = BRDDAT7 - * Secondary High Term Enable = BRDDAT6 - * Secondary Low Term Enable = BRDDAT5 (7890) - * Primary High Term Enable = BRDDAT4 (7890) - */ - if ((ahc->features & AHC_ULTRA2) == 0 - && (internal50_present != 0) - && (internal68_present != 0) - && (externalcable_present != 0)) { - printf("%s: Illegal cable configuration!!. " - "Only two connectors on the " - "adapter may be used at a " - "time!\n", ahc_name(ahc)); +static int +ahc_aha494X_setup(struct ahc_softc *ahc) +{ + int error; - /* - * Pretend there are no cables in the hope - * that having all of the termination on - * gives us a more stable bus. - */ - internal50_present = 0; - internal68_present = 0; - externalcable_present = 0; - } + error = ahc_aic7870_setup(ahc); + if (error == 0) + error = ahc_aha494XX_setup(ahc); + return (error); +} - if ((ahc->features & AHC_WIDE) != 0 - && ((externalcable_present == 0) - || (internal68_present == 0) - || (enableSEC_high != 0))) { - brddat |= BRDDAT6; - if (bootverbose) { - if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) - printf("%s: 68 pin termination " - "Enabled\n", ahc_name(ahc)); - else - printf("%s: %sHigh byte termination " - "Enabled\n", ahc_name(ahc), - enableSEC_high ? "Secondary " - : ""); - } - } +static int +ahc_aic7880_setup(struct ahc_softc *ahc) +{ + uint8_t rev; + + ahc->channel = 'A'; + ahc->chip = AHC_AIC7880; + ahc->features = AHC_AIC7880_FE; + ahc->bugs |= AHC_TMODE_WIDEODD_BUG; + rev = PCI_REVISION(ahc->bd->class); + if (rev >= 1) { + ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; + } else { + ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; + } + return (0); +} - sum = internal50_present + internal68_present - + externalcable_present; - if (sum < 2 || (enableSEC_low != 0)) { - if ((ahc->features & AHC_ULTRA2) != 0) - brddat |= BRDDAT5; - else - *sxfrctl1 |= STPWEN; - if (bootverbose) { - if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) - printf("%s: 50 pin termination " - "Enabled\n", ahc_name(ahc)); - else - printf("%s: %sLow byte termination " - "Enabled\n", ahc_name(ahc), - enableSEC_low ? "Secondary " - : ""); - } - } +static int +ahc_aha2940Pro_setup(struct ahc_softc *ahc) +{ - if (enablePRI_low != 0) { - *sxfrctl1 |= STPWEN; - if (bootverbose) - printf("%s: Primary Low Byte termination " - "Enabled\n", ahc_name(ahc)); - } + ahc->flags |= AHC_INT50_SPEEDFLEX; + return (ahc_aic7880_setup(ahc)); +} - /* - * Setup STPWEN before setting up the rest of - * the termination per the tech note on the U160 cards. - */ - ahc_outb(ahc, SXFRCTL1, *sxfrctl1); - - if (enablePRI_high != 0) { - brddat |= BRDDAT4; - if (bootverbose) - printf("%s: Primary High Byte " - "termination Enabled\n", - ahc_name(ahc)); - } - - write_brdctl(ahc, brddat); +static int +ahc_aha394XU_setup(struct ahc_softc *ahc) +{ + int error; - } else { - if ((adapter_control & CFSTERM) != 0) { - *sxfrctl1 |= STPWEN; - - if (bootverbose) - printf("%s: %sLow byte termination Enabled\n", - ahc_name(ahc), - (ahc->features & AHC_ULTRA2) ? "Primary " - : ""); - } + error = ahc_aic7880_setup(ahc); + if (error == 0) + error = ahc_aha394XX_setup(ahc); + return (error); +} - if ((adapter_control & CFWSTERM) != 0 - && (ahc->features & AHC_WIDE) != 0) { - brddat |= BRDDAT6; - if (bootverbose) - printf("%s: %sHigh byte termination Enabled\n", - ahc_name(ahc), - (ahc->features & AHC_ULTRA2) - ? "Secondary " : ""); - } +static int +ahc_aha398XU_setup(struct ahc_softc *ahc) +{ + int error; - /* - * Setup STPWEN before setting up the rest of - * the termination per the tech note on the U160 cards. - */ - ahc_outb(ahc, SXFRCTL1, *sxfrctl1); + error = ahc_aic7880_setup(ahc); + if (error == 0) + error = ahc_aha398XX_setup(ahc); + return (error); +} - if ((ahc->features & AHC_WIDE) != 0) - write_brdctl(ahc, brddat); - } - SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */ +static int +ahc_aic7890_setup(struct ahc_softc *ahc) +{ + uint8_t rev; + + ahc->channel = 'A'; + ahc->chip = AHC_AIC7890; + ahc->features = AHC_AIC7890_FE; + ahc->flags |= AHC_NEWEEPROM_FMT; + rev = PCI_REVISION(ahc->bd->class); + if (rev == 0) + ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; + return (0); } -static void -ahc_new_term_detect(ahc, enableSEC_low, enableSEC_high, enablePRI_low, - enablePRI_high, eeprom_present) - struct ahc_softc *ahc; - int *enableSEC_low; - int *enableSEC_high; - int *enablePRI_low; - int *enablePRI_high; - int *eeprom_present; +static int +ahc_aic7892_setup(struct ahc_softc *ahc) { - u_int8_t brdctl; - /* - * BRDDAT7 = Eeprom - * BRDDAT6 = Enable Secondary High Byte termination - * BRDDAT5 = Enable Secondary Low Byte termination - * BRDDAT4 = Enable Primary high byte termination - * BRDDAT3 = Enable Primary low byte termination - */ - brdctl = read_brdctl(ahc); - *eeprom_present = brdctl & BRDDAT7; - *enableSEC_high = (brdctl & BRDDAT6); - *enableSEC_low = (brdctl & BRDDAT5); - *enablePRI_high = (brdctl & BRDDAT4); - *enablePRI_low = (brdctl & BRDDAT3); + ahc->channel = 'A'; + ahc->chip = AHC_AIC7892; + ahc->features = AHC_AIC7892_FE; + ahc->flags |= AHC_NEWEEPROM_FMT; + ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; + return (0); } -static void -aic787X_cable_detect(ahc, internal50_present, internal68_present, - externalcable_present, eeprom_present) - struct ahc_softc *ahc; - int *internal50_present; - int *internal68_present; - int *externalcable_present; - int *eeprom_present; +static int +ahc_aic7895_setup(struct ahc_softc *ahc) { - u_int8_t brdctl; + uint8_t rev; + ahc->channel = (ahc->bd->func == 1) ? 'B' : 'A'; /* - * First read the status of our cables. - * Set the rom bank to 0 since the - * bank setting serves as a multiplexor - * for the cable detection logic. - * BRDDAT5 controls the bank switch. + * The 'C' revision of the aic7895 has a few additional features. */ - write_brdctl(ahc, 0); + rev = PCI_REVISION(ahc->bd->class); + if (rev >= 4) { + ahc->chip = AHC_AIC7895C; + ahc->features = AHC_AIC7895C_FE; + } else { + u_int command; - /* - * Now read the state of the internal - * connectors. BRDDAT6 is INT50 and - * BRDDAT7 is INT68. - */ - brdctl = read_brdctl(ahc); - *internal50_present = (brdctl & BRDDAT6) ? 0 : 1; - *internal68_present = (brdctl & BRDDAT7) ? 0 : 1; + ahc->chip = AHC_AIC7895; + ahc->features = AHC_AIC7895_FE; + /* + * The BIOS disables the use of MWI transactions + * since it does not have the MWI bug work around + * we have. Disabling MWI reduces performance, so + * turn it on again. + */ + command = pci_conf_read(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG); + command |= PCI_COMMAND_INVALIDATE_ENABLE; + pci_conf_write(ahc->bd->pc, ahc->bd->tag, PCI_COMMAND_STATUS_REG, command); + ahc->bugs |= AHC_PCI_MWI_BUG; + } /* - * Set the rom bank to 1 and determine - * the other signals. + * XXX Does CACHETHEN really not work??? What about PCI retry? + * on C level chips. Need to test, but for now, play it safe. */ - write_brdctl(ahc, BRDDAT5); + ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG + | AHC_CACHETHEN_BUG; + +#if 0 + uint32_t devconfig; /* - * Now read the state of the external - * connectors. BRDDAT6 is EXT68 and - * BRDDAT7 is EPROMPS. + * Cachesize must also be zero due to stray DAC + * problem when sitting behind some bridges. */ - brdctl = read_brdctl(ahc); - *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; - *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0; -} - -static void -aic785X_cable_detect(ahc, internal50_present, externalcable_present, - eeprom_present) - struct ahc_softc *ahc; - int *internal50_present; - int *externalcable_present; - int *eeprom_present; -{ - u_int8_t brdctl; - - ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); - ahc_outb(ahc, BRDCTL, 0); - brdctl = ahc_inb(ahc, BRDCTL); - *internal50_present = (brdctl & BRDDAT5) ? 0 : 1; - *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; - - *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; + pci_conf_write(ahc->bd->pc, ahc->bd->tag, CSIZE_LATTIME, 0); + devconfig = pci_conf_read(ahc->bd->pc, ahc->bd->tag, DEVCONFIG); + devconfig |= MRDCEN; + pci_conf_write(ahc->bd->pc, ahc->bd->tag, DEVCONFIG, devconfig); +#endif + ahc->flags |= AHC_NEWEEPROM_FMT; + return (0); } -static void -write_brdctl(ahc, value) - struct ahc_softc *ahc; - u_int8_t value; +static int +ahc_aic7896_setup(struct ahc_softc *ahc) { - u_int8_t brdctl; - - if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - brdctl = BRDSTB; - if (ahc->channel == 'B') - brdctl |= BRDCS; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - brdctl = 0; - } else { - brdctl = BRDSTB|BRDCS; - } - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - brdctl |= value; - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - if ((ahc->features & AHC_ULTRA2) != 0) - brdctl |= BRDSTB_ULTRA2; - else - brdctl &= ~BRDSTB; - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - if ((ahc->features & AHC_ULTRA2) != 0) - brdctl = 0; - else - brdctl &= ~BRDCS; - ahc_outb(ahc, BRDCTL, brdctl); + ahc->channel = (ahc->bd->func == 1) ? 'B' : 'A'; + ahc->chip = AHC_AIC7896; + ahc->features = AHC_AIC7896_FE; + ahc->flags |= AHC_NEWEEPROM_FMT; + ahc->bugs |= AHC_CACHETHEN_DIS_BUG; + return (0); } -static u_int8_t -read_brdctl(ahc) - struct ahc_softc *ahc; +static int +ahc_aic7899_setup(struct ahc_softc *ahc) { - u_int8_t brdctl; - u_int8_t value; - - if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - brdctl = BRDRW; - if (ahc->channel == 'B') - brdctl |= BRDCS; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - brdctl = BRDRW_ULTRA2; - } else { - brdctl = BRDRW|BRDCS; - } - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - value = ahc_inb(ahc, BRDCTL); - ahc_outb(ahc, BRDCTL, 0); - return (value); + ahc->channel = (ahc->bd->func == 1) ? 'B' : 'A'; + ahc->chip = AHC_AIC7899; + ahc->features = AHC_AIC7899_FE; + ahc->flags |= AHC_NEWEEPROM_FMT; + ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; + return (0); } static int -acquire_seeprom(ahc, sd) - struct ahc_softc *ahc; - struct seeprom_descriptor *sd; +ahc_aha29160C_setup(struct ahc_softc *ahc) { - int wait; - - if ((ahc->features & AHC_SPIOCAP) != 0 - && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0) - return (0); + int error; - /* - * Request access of the memory port. When access is - * granted, SEERDY will go high. We use a 1 second - * timeout which should be near 1 second more than - * is needed. Reason: after the chip reset, there - * should be no contention. - */ - SEEPROM_OUTB(sd, sd->sd_MS); - wait = 1000; /* 1 second timeout in msec */ - while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) { - DELAY(1000); /* delay 1 msec */ - } - if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) { - SEEPROM_OUTB(sd, 0); - return (0); - } - return (1); + error = ahc_aic7899_setup(ahc); + if (error != 0) + return (error); + ahc->features |= AHC_REMOVABLE; + return (0); } -static void -release_seeprom(sd) - struct seeprom_descriptor *sd; +static int +ahc_raid_setup(struct ahc_softc *ahc) { - /* Release access to the memory port and the serial EEPROM. */ - SEEPROM_OUTB(sd, 0); + printf("RAID functionality unsupported\n"); + return (ENXIO); } -#define DPE PCI_STATUS_PARITY_DETECT -#define SSE PCI_STATUS_SPECIAL_ERROR -#define RMA PCI_STATUS_MASTER_ABORT -#define RTA PCI_STATUS_MASTER_TARGET_ABORT -#define STA PCI_STATUS_TARGET_TARGET_ABORT -#define DPR PCI_STATUS_PARITY_ERROR - -#define PCIDEBUG -#ifdef PCIDEBUG -#define PCI_PRINT(Printstuff) printf Printstuff -#else -#define PCI_PRINT(Printstuff) -#endif - -void -ahc_pci_intr(ahc) - struct ahc_softc *ahc; +static int +ahc_aha394XX_setup(struct ahc_softc *ahc) { - pcireg_t status1; - if ((ahc_inb(ahc, ERROR) & PCIERRSTAT) == 0) - return; - PCI_PRINT(("%s: PCI error Interrupt at seqaddr = 0x%x\n", - ahc_name(ahc), - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8))); - - status1 = ahc_pci_read_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, 4); - -/* define AHC_SHOW_PCI_ERRORS to get painful errors on your i386 console */ -#ifdef AHC_SHOW_PCI_ERRORS - if (status1 & DPE) { - PCI_PRINT(("%s: Data Parity Error Detected during address " - "or write data phase\n", ahc_name(ahc))); - } -#endif - if (status1 & SSE) { - PCI_PRINT(("%s: Signal System Error Detected\n", ahc_name(ahc))); - } - if (status1 & RMA) { - PCI_PRINT(("%s: Received a Master Abort\n", ahc_name(ahc))); - } - if (status1 & RTA) { - PCI_PRINT(("%s: Received a Target Abort\n", ahc_name(ahc))); - } - if (status1 & STA) { - PCI_PRINT(("%s: Signaled a Target Abort\n", ahc_name(ahc))); - } - if (status1 & DPR) { - PCI_PRINT(("%s: Data Parity Error has been reported via PERR#\n", - ahc_name(ahc))); + switch (ahc->bd->dev) { + case AHC_394X_SLOT_CHANNEL_A: + ahc->channel = 'A'; + break; + case AHC_394X_SLOT_CHANNEL_B: + ahc->channel = 'B'; + break; + default: + printf("adapter at unexpected slot %d\n" + "unable to map to a channel\n", + ahc->bd->dev); + ahc->channel = 'A'; } - - ahc_pci_write_config(ahc->dev_softc, PCI_COMMAND_STATUS_REG, status1, 4); + return (0); +} - 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); - } - - ahc_unpause(ahc); +static int +ahc_aha398XX_setup(struct ahc_softc *ahc) +{ - return; + switch (ahc->bd->dev) { + case AHC_398X_SLOT_CHANNEL_A: + ahc->channel = 'A'; + break; + case AHC_398X_SLOT_CHANNEL_B: + ahc->channel = 'B'; + break; + case AHC_398X_SLOT_CHANNEL_C: + ahc->channel = 'C'; + break; + default: + printf("adapter at unexpected slot %d\n" + "unable to map to a channel\n", + ahc->bd->dev); + ahc->channel = 'A'; + break; + } + ahc->flags |= AHC_LARGE_SEEPROM; + return (0); } static int -verify_cksum(struct seeprom_config *sc) +ahc_aha494XX_setup(struct ahc_softc *ahc) { - int i; - int maxaddr; - u_int32_t checksum; - u_int16_t *scarray; - - maxaddr = (sizeof(*sc)/2) - 1; - checksum = 0; - scarray = (uint16_t *)sc; - - for (i = 0; i < maxaddr; i++) - checksum = checksum + scarray[i]; - if (checksum == 0 || - (checksum & 0xFFFF) != sc->checksum) { - return (0); - } else { - return (1); + + switch (ahc->bd->dev) { + case AHC_494X_SLOT_CHANNEL_A: + ahc->channel = 'A'; + break; + case AHC_494X_SLOT_CHANNEL_B: + ahc->channel = 'B'; + break; + case AHC_494X_SLOT_CHANNEL_C: + ahc->channel = 'C'; + break; + case AHC_494X_SLOT_CHANNEL_D: + ahc->channel = 'D'; + break; + default: + printf("adapter at unexpected slot %d\n" + "unable to map to a channel\n", + ahc->bd->dev); + ahc->channel = 'A'; } + ahc->flags |= AHC_LARGE_SEEPROM; + return (0); } |