117d24755SJustin T. Gibbs /* 217d24755SJustin T. Gibbs * Product specific probe and attach routines for: 317d24755SJustin T. Gibbs * aic7901 and aic7902 SCSI controllers 417d24755SJustin T. Gibbs * 517d24755SJustin T. Gibbs * Copyright (c) 1994-2001 Justin T. Gibbs. 61a1fbd0bSJustin T. Gibbs * Copyright (c) 2000-2002 Adaptec Inc. 717d24755SJustin T. Gibbs * All rights reserved. 817d24755SJustin T. Gibbs * 917d24755SJustin T. Gibbs * Redistribution and use in source and binary forms, with or without 1017d24755SJustin T. Gibbs * modification, are permitted provided that the following conditions 1117d24755SJustin T. Gibbs * are met: 1217d24755SJustin T. Gibbs * 1. Redistributions of source code must retain the above copyright 1317d24755SJustin T. Gibbs * notice, this list of conditions, and the following disclaimer, 1417d24755SJustin T. Gibbs * without modification. 1517d24755SJustin T. Gibbs * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1617d24755SJustin T. Gibbs * substantially similar to the "NO WARRANTY" disclaimer below 1717d24755SJustin T. Gibbs * ("Disclaimer") and any redistribution must be conditioned upon 1817d24755SJustin T. Gibbs * including a substantially similar Disclaimer requirement for further 1917d24755SJustin T. Gibbs * binary redistribution. 2017d24755SJustin T. Gibbs * 3. Neither the names of the above-listed copyright holders nor the names 2117d24755SJustin T. Gibbs * of any contributors may be used to endorse or promote products derived 2217d24755SJustin T. Gibbs * from this software without specific prior written permission. 2317d24755SJustin T. Gibbs * 2417d24755SJustin T. Gibbs * Alternatively, this software may be distributed under the terms of the 2517d24755SJustin T. Gibbs * GNU General Public License ("GPL") version 2 as published by the Free 2617d24755SJustin T. Gibbs * Software Foundation. 2717d24755SJustin T. Gibbs * 2817d24755SJustin T. Gibbs * NO WARRANTY 2917d24755SJustin T. Gibbs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3017d24755SJustin T. Gibbs * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3117d24755SJustin T. Gibbs * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3217d24755SJustin T. Gibbs * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3317d24755SJustin T. Gibbs * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3417d24755SJustin T. Gibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3517d24755SJustin T. Gibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3617d24755SJustin T. Gibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3717d24755SJustin T. Gibbs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 3817d24755SJustin T. Gibbs * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3917d24755SJustin T. Gibbs * POSSIBILITY OF SUCH DAMAGES. 4017d24755SJustin T. Gibbs * 41454bf169SScott Long * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#54 $ 4217d24755SJustin T. Gibbs * 4317d24755SJustin T. Gibbs * $FreeBSD$ 4417d24755SJustin T. Gibbs */ 4517d24755SJustin T. Gibbs 4617d24755SJustin T. Gibbs #ifdef __linux__ 4717d24755SJustin T. Gibbs #include "aic79xx_osm.h" 4817d24755SJustin T. Gibbs #include "aic79xx_inline.h" 4917d24755SJustin T. Gibbs #else 5017d24755SJustin T. Gibbs #include <dev/aic7xxx/aic79xx_osm.h> 5117d24755SJustin T. Gibbs #include <dev/aic7xxx/aic79xx_inline.h> 5217d24755SJustin T. Gibbs #endif 5317d24755SJustin T. Gibbs 5417d24755SJustin T. Gibbs static __inline uint64_t 5517d24755SJustin T. Gibbs ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) 5617d24755SJustin T. Gibbs { 5717d24755SJustin T. Gibbs uint64_t id; 5817d24755SJustin T. Gibbs 5917d24755SJustin T. Gibbs id = subvendor 6017d24755SJustin T. Gibbs | (subdevice << 16) 6117d24755SJustin T. Gibbs | ((uint64_t)vendor << 32) 6217d24755SJustin T. Gibbs | ((uint64_t)device << 48); 6317d24755SJustin T. Gibbs 6417d24755SJustin T. Gibbs return (id); 6517d24755SJustin T. Gibbs } 6617d24755SJustin T. Gibbs 6717d24755SJustin T. Gibbs #define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull 6817d24755SJustin T. Gibbs #define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull 6917d24755SJustin T. Gibbs #define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull 7017d24755SJustin T. Gibbs 7117d24755SJustin T. Gibbs #define ID_AIC7901 0x800F9005FFFF9005ull 721a1fbd0bSJustin T. Gibbs #define ID_AIC7901A 0x801E9005FFFF9005ull 73454bf169SScott Long #define ID_AIC7901A_IROC 0x809E9005FFFF9005ull 741a1fbd0bSJustin T. Gibbs #define ID_AHA_29320A 0x8000900500609005ull 75454bf169SScott Long #define ID_AHA_29320LP 0x8014900500449005ull 76454bf169SScott Long #define ID_AHA_29320LP_IROC 0x8094900500449005ull 7717d24755SJustin T. Gibbs 7817d24755SJustin T. Gibbs #define ID_AIC7902 0x801F9005FFFF9005ull 79454bf169SScott Long #define ID_AIC7902_IROC 0x809F9005FFFF9005ull 80454bf169SScott Long #define ID_AIC7902_B 0x801D9005FFFF9005ull 81454bf169SScott Long #define ID_AIC7902_B_IROC 0x809D9005FFFF9005ull 8217d24755SJustin T. Gibbs #define ID_AHA_39320 0x8010900500409005ull 8317d24755SJustin T. Gibbs #define ID_AHA_39320D 0x8011900500419005ull 84454bf169SScott Long #define ID_AHA_39320D_B 0x801C900500419005ull 85454bf169SScott Long #define ID_AHA_39320D_HP 0x8011900500AC0E11ull 86454bf169SScott Long #define ID_AHA_39320D_B_HP 0x801C900500AC0E11ull 871a1fbd0bSJustin T. Gibbs #define ID_AHA_29320 0x8012900500429005ull 881a1fbd0bSJustin T. Gibbs #define ID_AHA_29320B 0x8013900500439005ull 8917d24755SJustin T. Gibbs #define ID_AIC7902_PCI_REV_A4 0x3 901a1fbd0bSJustin T. Gibbs #define ID_AIC7902_PCI_REV_B0 0x10 91454bf169SScott Long #define SUBID_HP 0x0E11 9217d24755SJustin T. Gibbs 9317d24755SJustin T. Gibbs #define DEVID_9005_TYPE(id) ((id) & 0xF) 9417d24755SJustin T. Gibbs #define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */ 9517d24755SJustin T. Gibbs #define DEVID_9005_TYPE_HBA_2EXT 0x1 /* 2 External Ports */ 9617d24755SJustin T. Gibbs #define DEVID_9005_TYPE_IROC 0x8 /* Raid(0,1,10) Card */ 9717d24755SJustin T. Gibbs #define DEVID_9005_TYPE_MB 0xF /* On Motherboard */ 9817d24755SJustin T. Gibbs 9917d24755SJustin T. Gibbs #define DEVID_9005_MFUNC(id) ((id) & 0x10) 10017d24755SJustin T. Gibbs 10117d24755SJustin T. Gibbs #define DEVID_9005_PACKETIZED(id) ((id) & 0x8000) 10217d24755SJustin T. Gibbs 10317d24755SJustin T. Gibbs #define SUBID_9005_TYPE(id) ((id) & 0xF) 10417d24755SJustin T. Gibbs #define SUBID_9005_TYPE_HBA 0x0 /* Standard Card */ 10517d24755SJustin T. Gibbs #define SUBID_9005_TYPE_MB 0xF /* On Motherboard */ 10617d24755SJustin T. Gibbs 10717d24755SJustin T. Gibbs #define SUBID_9005_AUTOTERM(id) (((id) & 0x10) == 0) 10817d24755SJustin T. Gibbs 10917d24755SJustin T. Gibbs #define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20) 11017d24755SJustin T. Gibbs 11117d24755SJustin T. Gibbs #define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6) 11217d24755SJustin T. Gibbs #define SUBID_9005_SEEPTYPE_NONE 0x0 11317d24755SJustin T. Gibbs #define SUBID_9005_SEEPTYPE_4K 0x1 11417d24755SJustin T. Gibbs 1151a1fbd0bSJustin T. Gibbs static ahd_device_setup_t ahd_aic7901A_setup; 116454bf169SScott Long static ahd_device_setup_t ahd_aic7902_setup; 11717d24755SJustin T. Gibbs 11817d24755SJustin T. Gibbs struct ahd_pci_identity ahd_pci_ident_table [] = 11917d24755SJustin T. Gibbs { 120454bf169SScott Long /* aic7901A based controllers */ 121454bf169SScott Long { 122454bf169SScott Long ID_AHA_29320LP, 123454bf169SScott Long ID_ALL_MASK, 124454bf169SScott Long "Adaptec 29320LP Ultra320 SCSI adapter", 125454bf169SScott Long ahd_aic7901A_setup 126454bf169SScott Long }, 12717d24755SJustin T. Gibbs { 1281a1fbd0bSJustin T. Gibbs ID_AHA_29320A, 12917d24755SJustin T. Gibbs ID_ALL_MASK, 1301a1fbd0bSJustin T. Gibbs "Adaptec 29320A Ultra320 SCSI adapter", 131454bf169SScott Long ahd_aic7901A_setup 13217d24755SJustin T. Gibbs }, 13317d24755SJustin T. Gibbs /* aic7902 based controllers */ 13417d24755SJustin T. Gibbs { 13517d24755SJustin T. Gibbs ID_AHA_39320, 13617d24755SJustin T. Gibbs ID_ALL_MASK, 13717d24755SJustin T. Gibbs "Adaptec 39320 Ultra320 SCSI adapter", 13817d24755SJustin T. Gibbs ahd_aic7902_setup 13917d24755SJustin T. Gibbs }, 14017d24755SJustin T. Gibbs { 14117d24755SJustin T. Gibbs ID_AHA_39320D, 14217d24755SJustin T. Gibbs ID_ALL_MASK, 14317d24755SJustin T. Gibbs "Adaptec 39320D Ultra320 SCSI adapter", 14417d24755SJustin T. Gibbs ahd_aic7902_setup 14517d24755SJustin T. Gibbs }, 14617d24755SJustin T. Gibbs { 147454bf169SScott Long ID_AHA_39320D_HP, 14817d24755SJustin T. Gibbs ID_ALL_MASK, 149454bf169SScott Long "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter", 150454bf169SScott Long ahd_aic7902_setup 151454bf169SScott Long }, 152454bf169SScott Long { 153454bf169SScott Long ID_AHA_39320D_B, 154454bf169SScott Long ID_ALL_MASK, 155454bf169SScott Long "Adaptec 39320D Ultra320 SCSI adapter", 156454bf169SScott Long ahd_aic7902_setup 157454bf169SScott Long }, 158454bf169SScott Long { 159454bf169SScott Long ID_AHA_39320D_B_HP, 160454bf169SScott Long ID_ALL_MASK, 161454bf169SScott Long "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter", 16217d24755SJustin T. Gibbs ahd_aic7902_setup 16317d24755SJustin T. Gibbs }, 1641a1fbd0bSJustin T. Gibbs { 1651a1fbd0bSJustin T. Gibbs ID_AHA_29320, 1661a1fbd0bSJustin T. Gibbs ID_ALL_MASK, 1671a1fbd0bSJustin T. Gibbs "Adaptec 29320 Ultra320 SCSI adapter", 1681a1fbd0bSJustin T. Gibbs ahd_aic7902_setup 1691a1fbd0bSJustin T. Gibbs }, 1701a1fbd0bSJustin T. Gibbs { 1711a1fbd0bSJustin T. Gibbs ID_AHA_29320B, 1721a1fbd0bSJustin T. Gibbs ID_ALL_MASK, 1731a1fbd0bSJustin T. Gibbs "Adaptec 29320B Ultra320 SCSI adapter", 1741a1fbd0bSJustin T. Gibbs ahd_aic7902_setup 1751a1fbd0bSJustin T. Gibbs }, 17617d24755SJustin T. Gibbs /* Generic chip probes for devices we don't know 'exactly' */ 17717d24755SJustin T. Gibbs { 178454bf169SScott Long ID_AIC7901A & ID_ALL_MASK, 179454bf169SScott Long ID_ALL_MASK, 180454bf169SScott Long "Adaptec AIC7901A Ultra320 SCSI adapter", 181454bf169SScott Long ahd_aic7901A_setup 18217d24755SJustin T. Gibbs }, 18317d24755SJustin T. Gibbs { 18417d24755SJustin T. Gibbs ID_AIC7902 & ID_9005_GENERIC_MASK, 18517d24755SJustin T. Gibbs ID_9005_GENERIC_MASK, 186454bf169SScott Long "Adaptec AIC7902 Ultra320 SCSI adapter", 18717d24755SJustin T. Gibbs ahd_aic7902_setup 18817d24755SJustin T. Gibbs } 18917d24755SJustin T. Gibbs }; 19017d24755SJustin T. Gibbs 19117d24755SJustin T. Gibbs const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table); 19217d24755SJustin T. Gibbs 19317d24755SJustin T. Gibbs #define DEVCONFIG 0x40 19417d24755SJustin T. Gibbs #define PCIXINITPAT 0x0000E000ul 19517d24755SJustin T. Gibbs #define PCIXINIT_PCI33_66 0x0000E000ul 19617d24755SJustin T. Gibbs #define PCIXINIT_PCIX50_66 0x0000C000ul 19717d24755SJustin T. Gibbs #define PCIXINIT_PCIX66_100 0x0000A000ul 19817d24755SJustin T. Gibbs #define PCIXINIT_PCIX100_133 0x00008000ul 19917d24755SJustin T. Gibbs #define PCI_BUS_MODES_INDEX(devconfig) \ 20017d24755SJustin T. Gibbs (((devconfig) & PCIXINITPAT) >> 13) 20117d24755SJustin T. Gibbs static const char *pci_bus_modes[] = 20217d24755SJustin T. Gibbs { 20317d24755SJustin T. Gibbs "PCI bus mode unknown", 20417d24755SJustin T. Gibbs "PCI bus mode unknown", 20517d24755SJustin T. Gibbs "PCI bus mode unknown", 20617d24755SJustin T. Gibbs "PCI bus mode unknown", 20717d24755SJustin T. Gibbs "PCI-X 101-133Mhz", 20817d24755SJustin T. Gibbs "PCI-X 67-100Mhz", 20917d24755SJustin T. Gibbs "PCI-X 50-66Mhz", 21017d24755SJustin T. Gibbs "PCI 33 or 66Mhz" 21117d24755SJustin T. Gibbs }; 21217d24755SJustin T. Gibbs 21317d24755SJustin T. Gibbs #define TESTMODE 0x00000800ul 21417d24755SJustin T. Gibbs #define IRDY_RST 0x00000200ul 21517d24755SJustin T. Gibbs #define FRAME_RST 0x00000100ul 21617d24755SJustin T. Gibbs #define PCI64BIT 0x00000080ul 21717d24755SJustin T. Gibbs #define MRDCEN 0x00000040ul 21817d24755SJustin T. Gibbs #define ENDIANSEL 0x00000020ul 21917d24755SJustin T. Gibbs #define MIXQWENDIANEN 0x00000008ul 22017d24755SJustin T. Gibbs #define DACEN 0x00000004ul 22117d24755SJustin T. Gibbs #define STPWLEVEL 0x00000002ul 22217d24755SJustin T. Gibbs #define QWENDIANSEL 0x00000001ul 22317d24755SJustin T. Gibbs 22417d24755SJustin T. Gibbs #define DEVCONFIG1 0x44 22517d24755SJustin T. Gibbs #define PREQDIS 0x01 22617d24755SJustin T. Gibbs 22717d24755SJustin T. Gibbs #define CSIZE_LATTIME 0x0c 22817d24755SJustin T. Gibbs #define CACHESIZE 0x000000fful 22917d24755SJustin T. Gibbs #define LATTIME 0x0000ff00ul 23017d24755SJustin T. Gibbs 23117d24755SJustin T. Gibbs static int ahd_check_extport(struct ahd_softc *ahd); 23217d24755SJustin T. Gibbs static void ahd_configure_termination(struct ahd_softc *ahd, 23317d24755SJustin T. Gibbs u_int adapter_control); 23417d24755SJustin T. Gibbs static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat); 23517d24755SJustin T. Gibbs 23617d24755SJustin T. Gibbs struct ahd_pci_identity * 23717d24755SJustin T. Gibbs ahd_find_pci_device(ahd_dev_softc_t pci) 23817d24755SJustin T. Gibbs { 23917d24755SJustin T. Gibbs uint64_t full_id; 24017d24755SJustin T. Gibbs uint16_t device; 24117d24755SJustin T. Gibbs uint16_t vendor; 24217d24755SJustin T. Gibbs uint16_t subdevice; 24317d24755SJustin T. Gibbs uint16_t subvendor; 24417d24755SJustin T. Gibbs struct ahd_pci_identity *entry; 24517d24755SJustin T. Gibbs u_int i; 24617d24755SJustin T. Gibbs 24717d24755SJustin T. Gibbs vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); 24817d24755SJustin T. Gibbs device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); 24917d24755SJustin T. Gibbs subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); 25017d24755SJustin T. Gibbs subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); 25117d24755SJustin T. Gibbs full_id = ahd_compose_id(device, 25217d24755SJustin T. Gibbs vendor, 25317d24755SJustin T. Gibbs subdevice, 25417d24755SJustin T. Gibbs subvendor); 25517d24755SJustin T. Gibbs 25617d24755SJustin T. Gibbs for (i = 0; i < ahd_num_pci_devs; i++) { 25717d24755SJustin T. Gibbs entry = &ahd_pci_ident_table[i]; 25817d24755SJustin T. Gibbs if (entry->full_id == (full_id & entry->id_mask)) { 25917d24755SJustin T. Gibbs /* Honor exclusion entries. */ 26017d24755SJustin T. Gibbs if (entry->name == NULL) 26117d24755SJustin T. Gibbs return (NULL); 26217d24755SJustin T. Gibbs return (entry); 26317d24755SJustin T. Gibbs } 26417d24755SJustin T. Gibbs } 26517d24755SJustin T. Gibbs return (NULL); 26617d24755SJustin T. Gibbs } 26717d24755SJustin T. Gibbs 26817d24755SJustin T. Gibbs int 26917d24755SJustin T. Gibbs ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) 27017d24755SJustin T. Gibbs { 27117d24755SJustin T. Gibbs struct scb_data *shared_scb_data; 27217d24755SJustin T. Gibbs u_long l; 27317d24755SJustin T. Gibbs u_int command; 27417d24755SJustin T. Gibbs uint32_t devconfig; 27517d24755SJustin T. Gibbs uint16_t subvendor; 27617d24755SJustin T. Gibbs int error; 27717d24755SJustin T. Gibbs 27817d24755SJustin T. Gibbs shared_scb_data = NULL; 279454bf169SScott Long ahd->description = entry->name; 280454bf169SScott Long /* 281454bf169SScott Long * Record if this is an HP board. 282454bf169SScott Long */ 283454bf169SScott Long subvendor = ahd_pci_read_config(ahd->dev_softc, 284454bf169SScott Long PCIR_SUBVEND_0, /*bytes*/2); 285454bf169SScott Long if (subvendor == SUBID_HP) 286454bf169SScott Long ahd->flags |= AHD_HP_BOARD; 287454bf169SScott Long 28817d24755SJustin T. Gibbs error = entry->setup(ahd); 28917d24755SJustin T. Gibbs if (error != 0) 29017d24755SJustin T. Gibbs return (error); 29117d24755SJustin T. Gibbs 29217d24755SJustin T. Gibbs devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); 29317d24755SJustin T. Gibbs if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) { 29417d24755SJustin T. Gibbs ahd->chip |= AHD_PCI; 29517d24755SJustin T. Gibbs /* Disable PCIX workarounds when running in PCI mode. */ 29617d24755SJustin T. Gibbs ahd->bugs &= ~AHD_PCIX_BUG_MASK; 29717d24755SJustin T. Gibbs } else { 29817d24755SJustin T. Gibbs ahd->chip |= AHD_PCIX; 29917d24755SJustin T. Gibbs } 30017d24755SJustin T. Gibbs ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)]; 30117d24755SJustin T. Gibbs 30217d24755SJustin T. Gibbs ahd_power_state_change(ahd, AHD_POWER_STATE_D0); 30317d24755SJustin T. Gibbs 30417d24755SJustin T. Gibbs error = ahd_pci_map_registers(ahd); 30517d24755SJustin T. Gibbs if (error != 0) 30617d24755SJustin T. Gibbs return (error); 30717d24755SJustin T. Gibbs 30817d24755SJustin T. Gibbs /* 30917d24755SJustin T. Gibbs * If we need to support high memory, enable dual 31017d24755SJustin T. Gibbs * address cycles. This bit must be set to enable 31117d24755SJustin T. Gibbs * high address bit generation even if we are on a 31217d24755SJustin T. Gibbs * 64bit bus (PCI64BIT set in devconfig). 31317d24755SJustin T. Gibbs */ 31417d24755SJustin T. Gibbs if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) { 31517d24755SJustin T. Gibbs uint32_t devconfig; 31617d24755SJustin T. Gibbs 31717d24755SJustin T. Gibbs if (bootverbose) 31817d24755SJustin T. Gibbs printf("%s: Enabling 39Bit Addressing\n", 31917d24755SJustin T. Gibbs ahd_name(ahd)); 32017d24755SJustin T. Gibbs devconfig = ahd_pci_read_config(ahd->dev_softc, 32117d24755SJustin T. Gibbs DEVCONFIG, /*bytes*/4); 32217d24755SJustin T. Gibbs devconfig |= DACEN; 32317d24755SJustin T. Gibbs ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, 32417d24755SJustin T. Gibbs devconfig, /*bytes*/4); 32517d24755SJustin T. Gibbs } 32617d24755SJustin T. Gibbs 32717d24755SJustin T. Gibbs /* Ensure busmastering is enabled */ 32817d24755SJustin T. Gibbs command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1); 32917d24755SJustin T. Gibbs command |= PCIM_CMD_BUSMASTEREN; 33017d24755SJustin T. Gibbs ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/1); 33117d24755SJustin T. Gibbs 33217d24755SJustin T. Gibbs error = ahd_softc_init(ahd); 33317d24755SJustin T. Gibbs if (error != 0) 33417d24755SJustin T. Gibbs return (error); 33517d24755SJustin T. Gibbs 33617d24755SJustin T. Gibbs ahd->bus_intr = ahd_pci_intr; 33717d24755SJustin T. Gibbs 33817d24755SJustin T. Gibbs error = ahd_reset(ahd); 33917d24755SJustin T. Gibbs if (error != 0) 34017d24755SJustin T. Gibbs return (ENXIO); 34117d24755SJustin T. Gibbs 34217d24755SJustin T. Gibbs ahd->pci_cachesize = 34317d24755SJustin T. Gibbs ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, 34417d24755SJustin T. Gibbs /*bytes*/1) & CACHESIZE; 34517d24755SJustin T. Gibbs ahd->pci_cachesize *= 4; 34617d24755SJustin T. Gibbs 34717d24755SJustin T. Gibbs ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); 34817d24755SJustin T. Gibbs /* See if we have a SEEPROM and perform auto-term */ 34917d24755SJustin T. Gibbs error = ahd_check_extport(ahd); 35017d24755SJustin T. Gibbs if (error != 0) 35117d24755SJustin T. Gibbs return (error); 35217d24755SJustin T. Gibbs 35317d24755SJustin T. Gibbs /* Core initialization */ 35417d24755SJustin T. Gibbs error = ahd_init(ahd); 35517d24755SJustin T. Gibbs if (error != 0) 35617d24755SJustin T. Gibbs return (error); 35717d24755SJustin T. Gibbs 35817d24755SJustin T. Gibbs /* 35917d24755SJustin T. Gibbs * Allow interrupts now that we are completely setup. 36017d24755SJustin T. Gibbs */ 36117d24755SJustin T. Gibbs error = ahd_pci_map_int(ahd); 36217d24755SJustin T. Gibbs if (error != 0) 36317d24755SJustin T. Gibbs return (error); 36417d24755SJustin T. Gibbs 36517d24755SJustin T. Gibbs ahd_list_lock(&l); 36617d24755SJustin T. Gibbs /* 36717d24755SJustin T. Gibbs * Link this softc in with all other ahd instances. 36817d24755SJustin T. Gibbs */ 36917d24755SJustin T. Gibbs ahd_softc_insert(ahd); 37017d24755SJustin T. Gibbs ahd_list_unlock(&l); 37117d24755SJustin T. Gibbs return (0); 37217d24755SJustin T. Gibbs } 37317d24755SJustin T. Gibbs 37417d24755SJustin T. Gibbs /* 375454bf169SScott Long * Perform some simple tests that should catch situations where 376454bf169SScott Long * our registers are invalidly mapped. 377454bf169SScott Long */ 378454bf169SScott Long int 379454bf169SScott Long ahd_pci_test_register_access(struct ahd_softc *ahd) 380454bf169SScott Long { 381454bf169SScott Long int i; 382454bf169SScott Long 383454bf169SScott Long /* 384454bf169SScott Long * First a simple test to see if any 385454bf169SScott Long * registers can be read. Reading 386454bf169SScott Long * HCNTRL has no side effects and has 387454bf169SScott Long * at least one bit that is guaranteed to 388454bf169SScott Long * be zero so it is a good register to 389454bf169SScott Long * use for this test. 390454bf169SScott Long */ 391454bf169SScott Long if (ahd_inb(ahd, HCNTRL) == 0xFF) 392454bf169SScott Long return (EIO); 393454bf169SScott Long 394454bf169SScott Long /* 395454bf169SScott Long * Next create a situation where write combining 396454bf169SScott Long * or read prefetching could be initiated by the 397454bf169SScott Long * CPU or host bridge. Our device does not support 398454bf169SScott Long * either, so look for data corruption and/or flaged 399454bf169SScott Long * PCI errors. 400454bf169SScott Long */ 401454bf169SScott Long for (i = 0; i < 16; i++) 402454bf169SScott Long ahd_outb(ahd, SRAM_BASE + i, i); 403454bf169SScott Long 404454bf169SScott Long for (i = 0; i < 16; i++) 405454bf169SScott Long if (ahd_inb(ahd, SRAM_BASE + i) != i) 406454bf169SScott Long return (EIO); 407454bf169SScott Long 408454bf169SScott Long if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { 409454bf169SScott Long ahd_mode_state saved_modes; 410454bf169SScott Long u_int targpcistat; 411454bf169SScott Long u_int pci_status1; 412454bf169SScott Long 413454bf169SScott Long saved_modes = ahd_save_modes(ahd); 414454bf169SScott Long ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 415454bf169SScott Long targpcistat = ahd_inb(ahd, TARGPCISTAT); 416454bf169SScott Long 417454bf169SScott Long /* Silently clear any latched errors. */ 418454bf169SScott Long ahd_outb(ahd, TARGPCISTAT, targpcistat); 419454bf169SScott Long pci_status1 = ahd_pci_read_config(ahd->dev_softc, 420454bf169SScott Long PCIR_STATUS + 1, /*bytes*/1); 421454bf169SScott Long ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, 422454bf169SScott Long pci_status1, /*bytes*/1); 423454bf169SScott Long ahd_restore_modes(ahd, saved_modes); 424454bf169SScott Long 425454bf169SScott Long if ((targpcistat & STA) != 0) 426454bf169SScott Long return (EIO); 427454bf169SScott Long } 428454bf169SScott Long 429454bf169SScott Long return (0); 430454bf169SScott Long } 431454bf169SScott Long 432454bf169SScott Long /* 43317d24755SJustin T. Gibbs * Check the external port logic for a serial eeprom 43417d24755SJustin T. Gibbs * and termination/cable detection contrls. 43517d24755SJustin T. Gibbs */ 43617d24755SJustin T. Gibbs static int 43717d24755SJustin T. Gibbs ahd_check_extport(struct ahd_softc *ahd) 43817d24755SJustin T. Gibbs { 43917d24755SJustin T. Gibbs struct seeprom_config *sc; 44017d24755SJustin T. Gibbs u_int adapter_control; 44117d24755SJustin T. Gibbs int have_seeprom; 44217d24755SJustin T. Gibbs int error; 44317d24755SJustin T. Gibbs 44417d24755SJustin T. Gibbs sc = ahd->seep_config; 44517d24755SJustin T. Gibbs have_seeprom = ahd_acquire_seeprom(ahd); 44617d24755SJustin T. Gibbs if (have_seeprom) { 44717d24755SJustin T. Gibbs u_int start_addr; 44817d24755SJustin T. Gibbs 44917d24755SJustin T. Gibbs if (bootverbose) 45017d24755SJustin T. Gibbs printf("%s: Reading SEEPROM...", ahd_name(ahd)); 45117d24755SJustin T. Gibbs 45217d24755SJustin T. Gibbs /* Address is always in units of 16bit words */ 45317d24755SJustin T. Gibbs start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A'); 45417d24755SJustin T. Gibbs 45517d24755SJustin T. Gibbs error = ahd_read_seeprom(ahd, (uint16_t *)sc, 45617d24755SJustin T. Gibbs start_addr, sizeof(*sc)/2); 45717d24755SJustin T. Gibbs 45817d24755SJustin T. Gibbs if (error != 0) { 45917d24755SJustin T. Gibbs printf("Unable to read SEEPROM\n"); 46017d24755SJustin T. Gibbs have_seeprom = 0; 46117d24755SJustin T. Gibbs } else { 46217d24755SJustin T. Gibbs have_seeprom = ahd_verify_cksum(sc); 46317d24755SJustin T. Gibbs 46417d24755SJustin T. Gibbs if (bootverbose) { 46517d24755SJustin T. Gibbs if (have_seeprom == 0) 46617d24755SJustin T. Gibbs printf ("checksum error\n"); 46717d24755SJustin T. Gibbs else 46817d24755SJustin T. Gibbs printf ("done.\n"); 46917d24755SJustin T. Gibbs } 47017d24755SJustin T. Gibbs } 47117d24755SJustin T. Gibbs ahd_release_seeprom(ahd); 47217d24755SJustin T. Gibbs } 47317d24755SJustin T. Gibbs 47417d24755SJustin T. Gibbs if (!have_seeprom) { 47517d24755SJustin T. Gibbs u_int nvram_scb; 47617d24755SJustin T. Gibbs 47717d24755SJustin T. Gibbs /* 47817d24755SJustin T. Gibbs * Pull scratch ram settings and treat them as 47917d24755SJustin T. Gibbs * if they are the contents of an seeprom if 48017d24755SJustin T. Gibbs * the 'ADPT', 'BIOS', or 'ASPI' signature is found 48117d24755SJustin T. Gibbs * in SCB 0xFF. We manually compose the data as 16bit 48217d24755SJustin T. Gibbs * values to avoid endian issues. 48317d24755SJustin T. Gibbs */ 48417d24755SJustin T. Gibbs ahd_set_scbptr(ahd, 0xFF); 48517d24755SJustin T. Gibbs nvram_scb = ahd_inb_scbram(ahd, SCB_BASE + NVRAM_SCB_OFFSET); 48617d24755SJustin T. Gibbs if (nvram_scb != 0xFF 48717d24755SJustin T. Gibbs && ((ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A' 48817d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'D' 48917d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P' 49017d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'T') 49117d24755SJustin T. Gibbs || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'B' 49217d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'I' 49317d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'O' 49417d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'S') 49517d24755SJustin T. Gibbs || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A' 49617d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'S' 49717d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P' 49817d24755SJustin T. Gibbs && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'I'))) { 49917d24755SJustin T. Gibbs uint16_t *sc_data; 50017d24755SJustin T. Gibbs int i; 50117d24755SJustin T. Gibbs 50217d24755SJustin T. Gibbs ahd_set_scbptr(ahd, nvram_scb); 50317d24755SJustin T. Gibbs sc_data = (uint16_t *)sc; 50417d24755SJustin T. Gibbs for (i = 0; i < 64; i += 2) 50517d24755SJustin T. Gibbs *sc_data++ = ahd_inw_scbram(ahd, SCB_BASE+i); 50617d24755SJustin T. Gibbs have_seeprom = ahd_verify_cksum(sc); 50717d24755SJustin T. Gibbs if (have_seeprom) 50817d24755SJustin T. Gibbs ahd->flags |= AHD_SCB_CONFIG_USED; 50917d24755SJustin T. Gibbs } 51017d24755SJustin T. Gibbs } 51117d24755SJustin T. Gibbs 51217d24755SJustin T. Gibbs #if AHD_DEBUG 51317d24755SJustin T. Gibbs if (have_seeprom != 0 51417d24755SJustin T. Gibbs && (ahd_debug & AHD_DUMP_SEEPROM) != 0) { 51517d24755SJustin T. Gibbs uint8_t *sc_data; 51617d24755SJustin T. Gibbs int i; 51717d24755SJustin T. Gibbs 51817d24755SJustin T. Gibbs printf("%s: Seeprom Contents:", ahd_name(ahd)); 51917d24755SJustin T. Gibbs sc_data = (uint8_t *)sc; 52017d24755SJustin T. Gibbs for (i = 0; i < (sizeof(*sc)); i += 2) 52117d24755SJustin T. Gibbs printf("\n\t0x%.4x", 52217d24755SJustin T. Gibbs sc_data[i] | (sc_data[i+1] << 8)); 52317d24755SJustin T. Gibbs printf("\n"); 52417d24755SJustin T. Gibbs } 52517d24755SJustin T. Gibbs #endif 52617d24755SJustin T. Gibbs 52717d24755SJustin T. Gibbs if (!have_seeprom) { 52817d24755SJustin T. Gibbs if (bootverbose) 52917d24755SJustin T. Gibbs printf("%s: No SEEPROM available.\n", ahd_name(ahd)); 53017d24755SJustin T. Gibbs ahd->flags |= AHD_USEDEFAULTS; 53117d24755SJustin T. Gibbs error = ahd_default_config(ahd); 53217d24755SJustin T. Gibbs adapter_control = CFAUTOTERM|CFSEAUTOTERM; 53317d24755SJustin T. Gibbs free(ahd->seep_config, M_DEVBUF); 53417d24755SJustin T. Gibbs ahd->seep_config = NULL; 53517d24755SJustin T. Gibbs } else { 53617d24755SJustin T. Gibbs error = ahd_parse_cfgdata(ahd, sc); 53717d24755SJustin T. Gibbs adapter_control = sc->adapter_control; 53817d24755SJustin T. Gibbs } 53917d24755SJustin T. Gibbs if (error != 0) 54017d24755SJustin T. Gibbs return (error); 54117d24755SJustin T. Gibbs 54217d24755SJustin T. Gibbs ahd_configure_termination(ahd, adapter_control); 54317d24755SJustin T. Gibbs 54417d24755SJustin T. Gibbs return (0); 54517d24755SJustin T. Gibbs } 54617d24755SJustin T. Gibbs 54717d24755SJustin T. Gibbs static void 54817d24755SJustin T. Gibbs ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) 54917d24755SJustin T. Gibbs { 55017d24755SJustin T. Gibbs int error; 55117d24755SJustin T. Gibbs u_int sxfrctl1; 55217d24755SJustin T. Gibbs uint8_t termctl; 55317d24755SJustin T. Gibbs uint32_t devconfig; 55417d24755SJustin T. Gibbs 55517d24755SJustin T. Gibbs devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); 55617d24755SJustin T. Gibbs devconfig &= ~STPWLEVEL; 5571a1fbd0bSJustin T. Gibbs if ((ahd->flags & AHD_STPWLEVEL_A) != 0) 55817d24755SJustin T. Gibbs devconfig |= STPWLEVEL; 5591a1fbd0bSJustin T. Gibbs if (bootverbose) 5601a1fbd0bSJustin T. Gibbs printf("%s: STPWLEVEL is %s\n", 5611a1fbd0bSJustin T. Gibbs ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off"); 56217d24755SJustin T. Gibbs ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); 56317d24755SJustin T. Gibbs 56417d24755SJustin T. Gibbs /* Make sure current sensing is off. */ 56517d24755SJustin T. Gibbs if ((ahd->flags & AHD_CURRENT_SENSING) != 0) { 56617d24755SJustin T. Gibbs (void)ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0); 56717d24755SJustin T. Gibbs } 56817d24755SJustin T. Gibbs 56917d24755SJustin T. Gibbs /* 57017d24755SJustin T. Gibbs * Read to sense. Write to set. 57117d24755SJustin T. Gibbs */ 57217d24755SJustin T. Gibbs error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl); 57317d24755SJustin T. Gibbs if ((adapter_control & CFAUTOTERM) == 0) { 57417d24755SJustin T. Gibbs if (bootverbose) 57517d24755SJustin T. Gibbs printf("%s: Manual Primary Termination\n", 57617d24755SJustin T. Gibbs ahd_name(ahd)); 57717d24755SJustin T. Gibbs termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH); 57817d24755SJustin T. Gibbs if ((adapter_control & CFSTERM) != 0) 57917d24755SJustin T. Gibbs termctl |= FLX_TERMCTL_ENPRILOW; 58017d24755SJustin T. Gibbs if ((adapter_control & CFWSTERM) != 0) 58117d24755SJustin T. Gibbs termctl |= FLX_TERMCTL_ENPRIHIGH; 58217d24755SJustin T. Gibbs } else if (error != 0) { 58317d24755SJustin T. Gibbs printf("%s: Primary Auto-Term Sensing failed! " 58417d24755SJustin T. Gibbs "Using Defaults.\n", ahd_name(ahd)); 58517d24755SJustin T. Gibbs termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH; 58617d24755SJustin T. Gibbs } 58717d24755SJustin T. Gibbs 58817d24755SJustin T. Gibbs if ((adapter_control & CFSEAUTOTERM) == 0) { 58917d24755SJustin T. Gibbs if (bootverbose) 59017d24755SJustin T. Gibbs printf("%s: Manual Secondary Termination\n", 59117d24755SJustin T. Gibbs ahd_name(ahd)); 59217d24755SJustin T. Gibbs termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH); 59317d24755SJustin T. Gibbs if ((adapter_control & CFSELOWTERM) != 0) 59417d24755SJustin T. Gibbs termctl |= FLX_TERMCTL_ENSECLOW; 59517d24755SJustin T. Gibbs if ((adapter_control & CFSEHIGHTERM) != 0) 59617d24755SJustin T. Gibbs termctl |= FLX_TERMCTL_ENSECHIGH; 59717d24755SJustin T. Gibbs } else if (error != 0) { 59817d24755SJustin T. Gibbs printf("%s: Secondary Auto-Term Sensing failed! " 59917d24755SJustin T. Gibbs "Using Defaults.\n", ahd_name(ahd)); 60017d24755SJustin T. Gibbs termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH; 60117d24755SJustin T. Gibbs } 60217d24755SJustin T. Gibbs 60317d24755SJustin T. Gibbs /* 60417d24755SJustin T. Gibbs * Now set the termination based on what we found. 60517d24755SJustin T. Gibbs */ 60617d24755SJustin T. Gibbs sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN; 60717d24755SJustin T. Gibbs if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) { 60817d24755SJustin T. Gibbs ahd->flags |= AHD_TERM_ENB_A; 60917d24755SJustin T. Gibbs sxfrctl1 |= STPWEN; 61017d24755SJustin T. Gibbs } 61117d24755SJustin T. Gibbs /* Must set the latch once in order to be effective. */ 61217d24755SJustin T. Gibbs ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); 61317d24755SJustin T. Gibbs ahd_outb(ahd, SXFRCTL1, sxfrctl1); 61417d24755SJustin T. Gibbs 61517d24755SJustin T. Gibbs error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl); 61617d24755SJustin T. Gibbs if (error != 0) { 61717d24755SJustin T. Gibbs printf("%s: Unable to set termination settings!\n", 61817d24755SJustin T. Gibbs ahd_name(ahd)); 61917d24755SJustin T. Gibbs } else if (bootverbose) { 62017d24755SJustin T. Gibbs printf("%s: Primary High byte termination %sabled\n", 62117d24755SJustin T. Gibbs ahd_name(ahd), 62217d24755SJustin T. Gibbs (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis"); 62317d24755SJustin T. Gibbs 62417d24755SJustin T. Gibbs printf("%s: Primary Low byte termination %sabled\n", 62517d24755SJustin T. Gibbs ahd_name(ahd), 62617d24755SJustin T. Gibbs (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis"); 62717d24755SJustin T. Gibbs 62817d24755SJustin T. Gibbs printf("%s: Secondary High byte termination %sabled\n", 62917d24755SJustin T. Gibbs ahd_name(ahd), 63017d24755SJustin T. Gibbs (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis"); 63117d24755SJustin T. Gibbs 63217d24755SJustin T. Gibbs printf("%s: Secondary Low byte termination %sabled\n", 63317d24755SJustin T. Gibbs ahd_name(ahd), 63417d24755SJustin T. Gibbs (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis"); 63517d24755SJustin T. Gibbs } 63617d24755SJustin T. Gibbs return; 63717d24755SJustin T. Gibbs } 63817d24755SJustin T. Gibbs 63917d24755SJustin T. Gibbs #define DPE 0x80 64017d24755SJustin T. Gibbs #define SSE 0x40 64117d24755SJustin T. Gibbs #define RMA 0x20 64217d24755SJustin T. Gibbs #define RTA 0x10 64317d24755SJustin T. Gibbs #define STA 0x08 64417d24755SJustin T. Gibbs #define DPR 0x01 64517d24755SJustin T. Gibbs 64617d24755SJustin T. Gibbs static const char *split_status_source[] = 64717d24755SJustin T. Gibbs { 64817d24755SJustin T. Gibbs "DFF0", 64917d24755SJustin T. Gibbs "DFF1", 65017d24755SJustin T. Gibbs "OVLY", 65117d24755SJustin T. Gibbs "CMC", 65217d24755SJustin T. Gibbs }; 65317d24755SJustin T. Gibbs 65417d24755SJustin T. Gibbs static const char *pci_status_source[] = 65517d24755SJustin T. Gibbs { 65617d24755SJustin T. Gibbs "DFF0", 65717d24755SJustin T. Gibbs "DFF1", 65817d24755SJustin T. Gibbs "SG", 65917d24755SJustin T. Gibbs "CMC", 66017d24755SJustin T. Gibbs "OVLY", 66117d24755SJustin T. Gibbs "NONE", 66217d24755SJustin T. Gibbs "MSI", 66317d24755SJustin T. Gibbs "TARG" 66417d24755SJustin T. Gibbs }; 66517d24755SJustin T. Gibbs 66617d24755SJustin T. Gibbs static const char *split_status_strings[] = 66717d24755SJustin T. Gibbs { 66817d24755SJustin T. Gibbs "%s: Received split response in %s.\n" 66917d24755SJustin T. Gibbs "%s: Received split completion error message in %s\n", 67017d24755SJustin T. Gibbs "%s: Receive overrun in %s\n", 67117d24755SJustin T. Gibbs "%s: Count not complete in %s\n", 67217d24755SJustin T. Gibbs "%s: Split completion data bucket in %s\n", 67317d24755SJustin T. Gibbs "%s: Split completion address error in %s\n", 67417d24755SJustin T. Gibbs "%s: Split completion byte count error in %s\n", 67517d24755SJustin T. Gibbs "%s: Signaled Target-abort to early terminate a split in %s\n", 67617d24755SJustin T. Gibbs }; 67717d24755SJustin T. Gibbs 67817d24755SJustin T. Gibbs static const char *pci_status_strings[] = 67917d24755SJustin T. Gibbs { 68017d24755SJustin T. Gibbs "%s: Data Parity Error has been reported via PERR# in %s\n", 68117d24755SJustin T. Gibbs "%s: Target initial wait state error in %s\n", 68217d24755SJustin T. Gibbs "%s: Split completion read data parity error in %s\n", 68317d24755SJustin T. Gibbs "%s: Split completion address attribute parity error in %s\n", 68417d24755SJustin T. Gibbs "%s: Received a Target Abort in %s\n", 68517d24755SJustin T. Gibbs "%s: Received a Master Abort in %s\n", 68617d24755SJustin T. Gibbs "%s: Signal System Error Detected in %s\n", 68717d24755SJustin T. Gibbs "%s: Address or Write Phase Parity Error Detected in %s.\n" 68817d24755SJustin T. Gibbs }; 68917d24755SJustin T. Gibbs 69017d24755SJustin T. Gibbs void 69117d24755SJustin T. Gibbs ahd_pci_intr(struct ahd_softc *ahd) 69217d24755SJustin T. Gibbs { 69317d24755SJustin T. Gibbs uint8_t pci_status[8]; 69417d24755SJustin T. Gibbs ahd_mode_state saved_modes; 69517d24755SJustin T. Gibbs u_int pci_status1; 69617d24755SJustin T. Gibbs u_int intstat; 69717d24755SJustin T. Gibbs u_int i; 69817d24755SJustin T. Gibbs u_int reg; 69917d24755SJustin T. Gibbs 70017d24755SJustin T. Gibbs intstat = ahd_inb(ahd, INTSTAT); 70117d24755SJustin T. Gibbs 70217d24755SJustin T. Gibbs if ((intstat & SPLTINT) != 0) 70317d24755SJustin T. Gibbs ahd_pci_split_intr(ahd, intstat); 70417d24755SJustin T. Gibbs 70517d24755SJustin T. Gibbs if ((intstat & PCIINT) == 0) 70617d24755SJustin T. Gibbs return; 70717d24755SJustin T. Gibbs 70817d24755SJustin T. Gibbs printf("%s: PCI error Interrupt\n", ahd_name(ahd)); 70917d24755SJustin T. Gibbs saved_modes = ahd_save_modes(ahd); 71017d24755SJustin T. Gibbs ahd_dump_card_state(ahd); 71117d24755SJustin T. Gibbs ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); 71217d24755SJustin T. Gibbs for (i = 0, reg = DF0PCISTAT; i < 8; i++, reg++) { 71317d24755SJustin T. Gibbs 71417d24755SJustin T. Gibbs if (i == 5) 71517d24755SJustin T. Gibbs continue; 71617d24755SJustin T. Gibbs pci_status[i] = ahd_inb(ahd, reg); 71717d24755SJustin T. Gibbs /* Clear latched errors. So our interupt deasserts. */ 71817d24755SJustin T. Gibbs ahd_outb(ahd, reg, pci_status[i]); 71917d24755SJustin T. Gibbs } 72017d24755SJustin T. Gibbs 72117d24755SJustin T. Gibbs for (i = 0; i < 8; i++) { 72217d24755SJustin T. Gibbs u_int bit; 72317d24755SJustin T. Gibbs 72417d24755SJustin T. Gibbs if (i == 5) 72517d24755SJustin T. Gibbs continue; 72617d24755SJustin T. Gibbs 72717d24755SJustin T. Gibbs for (bit = 0; bit < 8; bit++) { 72817d24755SJustin T. Gibbs 72917d24755SJustin T. Gibbs if ((pci_status[i] & (0x1 << bit)) != 0) { 73017d24755SJustin T. Gibbs static const char *s; 73117d24755SJustin T. Gibbs 73217d24755SJustin T. Gibbs s = pci_status_strings[bit]; 73317d24755SJustin T. Gibbs if (i == 7/*TARG*/ && bit == 3) 73417d24755SJustin T. Gibbs s = "%s: Signal Target Abort\n"; 73517d24755SJustin T. Gibbs printf(s, ahd_name(ahd), pci_status_source[i]); 73617d24755SJustin T. Gibbs } 73717d24755SJustin T. Gibbs } 73817d24755SJustin T. Gibbs } 73917d24755SJustin T. Gibbs pci_status1 = ahd_pci_read_config(ahd->dev_softc, 74017d24755SJustin T. Gibbs PCIR_STATUS + 1, /*bytes*/1); 74117d24755SJustin T. Gibbs ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, 74217d24755SJustin T. Gibbs pci_status1, /*bytes*/1); 74317d24755SJustin T. Gibbs ahd_restore_modes(ahd, saved_modes); 74417d24755SJustin T. Gibbs ahd_unpause(ahd); 74517d24755SJustin T. Gibbs } 74617d24755SJustin T. Gibbs 74717d24755SJustin T. Gibbs static void 74817d24755SJustin T. Gibbs ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) 74917d24755SJustin T. Gibbs { 75017d24755SJustin T. Gibbs uint8_t split_status[4]; 75117d24755SJustin T. Gibbs uint8_t split_status1[4]; 75217d24755SJustin T. Gibbs uint8_t sg_split_status[2]; 75317d24755SJustin T. Gibbs uint8_t sg_split_status1[2]; 75417d24755SJustin T. Gibbs ahd_mode_state saved_modes; 75517d24755SJustin T. Gibbs u_int i; 75617d24755SJustin T. Gibbs uint16_t pcix_status; 75717d24755SJustin T. Gibbs 75817d24755SJustin T. Gibbs /* 75917d24755SJustin T. Gibbs * Check for splits in all modes. Modes 0 and 1 76017d24755SJustin T. Gibbs * additionally have SG engine splits to look at. 76117d24755SJustin T. Gibbs */ 76217d24755SJustin T. Gibbs pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS, 76317d24755SJustin T. Gibbs /*bytes*/2); 76417d24755SJustin T. Gibbs printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n", 76517d24755SJustin T. Gibbs ahd_name(ahd), pcix_status); 76617d24755SJustin T. Gibbs saved_modes = ahd_save_modes(ahd); 76717d24755SJustin T. Gibbs for (i = 0; i < 4; i++) { 76817d24755SJustin T. Gibbs ahd_set_modes(ahd, i, i); 76917d24755SJustin T. Gibbs 77017d24755SJustin T. Gibbs split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0); 77117d24755SJustin T. Gibbs split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1); 77217d24755SJustin T. Gibbs /* Clear latched errors. So our interupt deasserts. */ 77317d24755SJustin T. Gibbs ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]); 77417d24755SJustin T. Gibbs ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]); 77517d24755SJustin T. Gibbs if (i != 0) 77617d24755SJustin T. Gibbs continue; 77717d24755SJustin T. Gibbs sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0); 77817d24755SJustin T. Gibbs sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1); 77917d24755SJustin T. Gibbs /* Clear latched errors. So our interupt deasserts. */ 78017d24755SJustin T. Gibbs ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]); 78117d24755SJustin T. Gibbs ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]); 78217d24755SJustin T. Gibbs } 78317d24755SJustin T. Gibbs 78417d24755SJustin T. Gibbs for (i = 0; i < 4; i++) { 78517d24755SJustin T. Gibbs u_int bit; 78617d24755SJustin T. Gibbs 78717d24755SJustin T. Gibbs for (bit = 0; bit < 8; bit++) { 78817d24755SJustin T. Gibbs 78917d24755SJustin T. Gibbs if ((split_status[i] & (0x1 << bit)) != 0) { 79017d24755SJustin T. Gibbs static const char *s; 79117d24755SJustin T. Gibbs 79217d24755SJustin T. Gibbs s = split_status_strings[bit]; 79317d24755SJustin T. Gibbs printf(s, ahd_name(ahd), 79417d24755SJustin T. Gibbs split_status_source[i]); 79517d24755SJustin T. Gibbs } 79617d24755SJustin T. Gibbs 79717d24755SJustin T. Gibbs if (i != 0) 79817d24755SJustin T. Gibbs continue; 79917d24755SJustin T. Gibbs 80017d24755SJustin T. Gibbs if ((sg_split_status[i] & (0x1 << bit)) != 0) { 80117d24755SJustin T. Gibbs static const char *s; 80217d24755SJustin T. Gibbs 80317d24755SJustin T. Gibbs s = split_status_strings[bit]; 80417d24755SJustin T. Gibbs printf(s, ahd_name(ahd), "SG"); 80517d24755SJustin T. Gibbs } 80617d24755SJustin T. Gibbs } 80717d24755SJustin T. Gibbs } 80817d24755SJustin T. Gibbs /* 80917d24755SJustin T. Gibbs * Clear PCI-X status bits. 81017d24755SJustin T. Gibbs */ 81117d24755SJustin T. Gibbs ahd_pci_write_config(ahd->dev_softc, PCIXR_STATUS, 81217d24755SJustin T. Gibbs pcix_status, /*bytes*/2); 81317d24755SJustin T. Gibbs ahd_restore_modes(ahd, saved_modes); 81417d24755SJustin T. Gibbs } 81517d24755SJustin T. Gibbs 81617d24755SJustin T. Gibbs static int 8171a1fbd0bSJustin T. Gibbs ahd_aic7901A_setup(struct ahd_softc *ahd) 8181a1fbd0bSJustin T. Gibbs { 8191a1fbd0bSJustin T. Gibbs int error; 8201a1fbd0bSJustin T. Gibbs 8211a1fbd0bSJustin T. Gibbs error = ahd_aic7902_setup(ahd); 8221a1fbd0bSJustin T. Gibbs if (error != 0) 8231a1fbd0bSJustin T. Gibbs return (error); 8241a1fbd0bSJustin T. Gibbs ahd->chip = AHD_AIC7901A; 8251a1fbd0bSJustin T. Gibbs return (0); 8261a1fbd0bSJustin T. Gibbs } 8271a1fbd0bSJustin T. Gibbs 828454bf169SScott Long static int 829454bf169SScott Long ahd_aic7902_setup(struct ahd_softc *ahd) 830454bf169SScott Long { 831454bf169SScott Long ahd_dev_softc_t pci; 832454bf169SScott Long u_int rev; 833454bf169SScott Long 834454bf169SScott Long pci = ahd->dev_softc; 835454bf169SScott Long rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1); 836454bf169SScott Long if (rev < ID_AIC7902_PCI_REV_A4) { 837454bf169SScott Long printf("%s: Unable to attach to unsupported chip revision %d\n", 838454bf169SScott Long ahd_name(ahd), rev); 839454bf169SScott Long ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/1); 840454bf169SScott Long return (ENXIO); 841454bf169SScott Long } 842454bf169SScott Long ahd->channel = ahd_get_pci_function(pci) + 'A'; 843454bf169SScott Long ahd->chip = AHD_AIC7902; 844454bf169SScott Long ahd->features = AHD_AIC7902_FE; 845454bf169SScott Long if (rev < ID_AIC7902_PCI_REV_B0) { 846454bf169SScott Long /* 847454bf169SScott Long * Enable A series workarounds. 848454bf169SScott Long */ 849454bf169SScott Long ahd->bugs |= AHD_SENT_SCB_UPDATE_BUG|AHD_ABORT_LQI_BUG 850454bf169SScott Long | AHD_PKT_BITBUCKET_BUG|AHD_LONG_SETIMO_BUG 851454bf169SScott Long | AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG 852454bf169SScott Long | AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG 853454bf169SScott Long | AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG 854454bf169SScott Long | AHD_PCIX_CHIPRST_BUG|AHD_PKTIZED_STATUS_BUG 855454bf169SScott Long | AHD_PKT_LUN_BUG|AHD_MDFF_WSCBPTR_BUG 856454bf169SScott Long | AHD_REG_SLOW_SETTLE_BUG|AHD_SET_MODE_BUG 857454bf169SScott Long | AHD_BUSFREEREV_BUG|AHD_NONPACKFIFO_BUG 858454bf169SScott Long | AHD_PACED_NEGTABLE_BUG; 859454bf169SScott Long 860454bf169SScott Long /* 861454bf169SScott Long * IO Cell paramter setup. 862454bf169SScott Long */ 863454bf169SScott Long AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29); 864454bf169SScott Long 865454bf169SScott Long if ((ahd->flags & AHD_HP_BOARD) == 0) 866454bf169SScott Long AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVA); 867454bf169SScott Long } else { 868454bf169SScott Long u_int devconfig1; 869454bf169SScott Long 870454bf169SScott Long ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS 871454bf169SScott Long | AHD_NEW_DFCNTRL_OPTS; 872454bf169SScott Long ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_ABORT_LQI_BUG 873454bf169SScott Long | AHD_INTCOLLISION_BUG; 874454bf169SScott Long 875454bf169SScott Long /* 876454bf169SScott Long * IO Cell paramter setup. 877454bf169SScott Long */ 878454bf169SScott Long AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29); 879454bf169SScott Long AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB); 880454bf169SScott Long AHD_SET_AMPLITUDE(ahd, AHD_AMPLITUDE_DEF); 881454bf169SScott Long 882454bf169SScott Long /* 883454bf169SScott Long * Set the PREQDIS bit for H2B which disables some workaround 884454bf169SScott Long * that doesn't work on regular PCI busses. 885454bf169SScott Long * XXX - Find out exactly what this does from the hardware 886454bf169SScott Long * folks! 887454bf169SScott Long */ 888454bf169SScott Long devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); 889454bf169SScott Long ahd_pci_write_config(pci, DEVCONFIG1, 890454bf169SScott Long devconfig1|PREQDIS, /*bytes*/1); 891454bf169SScott Long devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); 892454bf169SScott Long } 893454bf169SScott Long 894454bf169SScott Long return (0); 895454bf169SScott Long } 896