xref: /freebsd/sys/dev/aic7xxx/aic79xx_pci.c (revision 718cf2ccb9956613756ab15d7a0e28f2c8e91cab)
1098ca2bdSWarner Losh /*-
217d24755SJustin T. Gibbs  * Product specific probe and attach routines for:
317d24755SJustin T. Gibbs  *	aic7901 and aic7902 SCSI controllers
417d24755SJustin T. Gibbs  *
5*718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
6*718cf2ccSPedro F. Giffuni  *
717d24755SJustin T. Gibbs  * Copyright (c) 1994-2001 Justin T. Gibbs.
81a1fbd0bSJustin T. Gibbs  * Copyright (c) 2000-2002 Adaptec Inc.
917d24755SJustin T. Gibbs  * All rights reserved.
1017d24755SJustin T. Gibbs  *
1117d24755SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
1217d24755SJustin T. Gibbs  * modification, are permitted provided that the following conditions
1317d24755SJustin T. Gibbs  * are met:
1417d24755SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
1517d24755SJustin T. Gibbs  *    notice, this list of conditions, and the following disclaimer,
1617d24755SJustin T. Gibbs  *    without modification.
1717d24755SJustin T. Gibbs  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1817d24755SJustin T. Gibbs  *    substantially similar to the "NO WARRANTY" disclaimer below
1917d24755SJustin T. Gibbs  *    ("Disclaimer") and any redistribution must be conditioned upon
2017d24755SJustin T. Gibbs  *    including a substantially similar Disclaimer requirement for further
2117d24755SJustin T. Gibbs  *    binary redistribution.
2217d24755SJustin T. Gibbs  * 3. Neither the names of the above-listed copyright holders nor the names
2317d24755SJustin T. Gibbs  *    of any contributors may be used to endorse or promote products derived
2417d24755SJustin T. Gibbs  *    from this software without specific prior written permission.
2517d24755SJustin T. Gibbs  *
2617d24755SJustin T. Gibbs  * Alternatively, this software may be distributed under the terms of the
2717d24755SJustin T. Gibbs  * GNU General Public License ("GPL") version 2 as published by the Free
2817d24755SJustin T. Gibbs  * Software Foundation.
2917d24755SJustin T. Gibbs  *
3017d24755SJustin T. Gibbs  * NO WARRANTY
3117d24755SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3217d24755SJustin T. Gibbs  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3317d24755SJustin T. Gibbs  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3417d24755SJustin T. Gibbs  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3517d24755SJustin T. Gibbs  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3617d24755SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3717d24755SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3817d24755SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3917d24755SJustin T. Gibbs  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4017d24755SJustin T. Gibbs  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4117d24755SJustin T. Gibbs  * POSSIBILITY OF SUCH DAMAGES.
4217d24755SJustin T. Gibbs  *
4322dbd4c6SJustin T. Gibbs  * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#88 $
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
50b3b25f2cSJustin T. Gibbs #include <sys/cdefs.h>
51b3b25f2cSJustin T. Gibbs __FBSDID("$FreeBSD$");
5217d24755SJustin T. Gibbs #include <dev/aic7xxx/aic79xx_osm.h>
5317d24755SJustin T. Gibbs #include <dev/aic7xxx/aic79xx_inline.h>
5417d24755SJustin T. Gibbs #endif
5517d24755SJustin T. Gibbs 
5617d24755SJustin T. Gibbs static __inline uint64_t
5717d24755SJustin T. Gibbs ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
5817d24755SJustin T. Gibbs {
5917d24755SJustin T. Gibbs 	uint64_t id;
6017d24755SJustin T. Gibbs 
6117d24755SJustin T. Gibbs 	id = subvendor
6217d24755SJustin T. Gibbs 	   | (subdevice << 16)
6317d24755SJustin T. Gibbs 	   | ((uint64_t)vendor << 32)
6417d24755SJustin T. Gibbs 	   | ((uint64_t)device << 48);
6517d24755SJustin T. Gibbs 
6617d24755SJustin T. Gibbs 	return (id);
6717d24755SJustin T. Gibbs }
6817d24755SJustin T. Gibbs 
6917d24755SJustin T. Gibbs #define ID_ALL_MASK			0xFFFFFFFFFFFFFFFFull
704164174aSJustin T. Gibbs #define ID_ALL_IROC_MASK		0xFF7FFFFFFFFFFFFFull
7117d24755SJustin T. Gibbs #define ID_DEV_VENDOR_MASK		0xFFFFFFFF00000000ull
7217d24755SJustin T. Gibbs #define ID_9005_GENERIC_MASK		0xFFF0FFFF00000000ull
734164174aSJustin T. Gibbs #define ID_9005_GENERIC_IROC_MASK	0xFF70FFFF00000000ull
7417d24755SJustin T. Gibbs 
7517d24755SJustin T. Gibbs #define ID_AIC7901			0x800F9005FFFF9005ull
761a1fbd0bSJustin T. Gibbs #define ID_AHA_29320A			0x8000900500609005ull
77197696e9SJustin T. Gibbs #define ID_AHA_29320ALP			0x8017900500449005ull
78197696e9SJustin T. Gibbs 
79197696e9SJustin T. Gibbs #define ID_AIC7901A			0x801E9005FFFF9005ull
80454bf169SScott Long #define ID_AHA_29320LP			0x8014900500449005ull
8117d24755SJustin T. Gibbs 
8217d24755SJustin T. Gibbs #define ID_AIC7902			0x801F9005FFFF9005ull
83454bf169SScott Long #define ID_AIC7902_B			0x801D9005FFFF9005ull
8417d24755SJustin T. Gibbs #define ID_AHA_39320			0x8010900500409005ull
85b3b25f2cSJustin T. Gibbs #define ID_AHA_29320			0x8012900500429005ull
86b3b25f2cSJustin T. Gibbs #define ID_AHA_29320B			0x8013900500439005ull
87197696e9SJustin T. Gibbs #define ID_AHA_39320_B			0x8015900500409005ull
8822dbd4c6SJustin T. Gibbs #define ID_AHA_39320_B_DELL		0x8015900501681028ull
89acae33b0SJustin T. Gibbs #define ID_AHA_39320A			0x8016900500409005ull
9017d24755SJustin T. Gibbs #define ID_AHA_39320D			0x8011900500419005ull
91454bf169SScott Long #define ID_AHA_39320D_B			0x801C900500419005ull
92454bf169SScott Long #define ID_AHA_39320D_HP		0x8011900500AC0E11ull
93454bf169SScott Long #define ID_AHA_39320D_B_HP		0x801C900500AC0E11ull
94a4522488SChristian Brueffer #define ID_AHA_39320LPE 		0x8017900500459005ull
9517d24755SJustin T. Gibbs #define ID_AIC7902_PCI_REV_A4		0x3
961a1fbd0bSJustin T. Gibbs #define ID_AIC7902_PCI_REV_B0		0x10
97454bf169SScott Long #define SUBID_HP			0x0E11
987cfc62d8SAchim Leubner #define DEVICE8081			0x8081
997cfc62d8SAchim Leubner #define DEVICE8088			0x8088
1007cfc62d8SAchim Leubner #define DEVICE8089			0x8089
1017cfc62d8SAchim Leubner #define ADAPTECVENDORID			0x9005
1027cfc62d8SAchim Leubner #define SUBVENDOR9005			0x9005
10317d24755SJustin T. Gibbs 
1044164174aSJustin T. Gibbs #define DEVID_9005_HOSTRAID(id) ((id) & 0x80)
1054164174aSJustin T. Gibbs 
10617d24755SJustin T. Gibbs #define DEVID_9005_TYPE(id) ((id) & 0xF)
10717d24755SJustin T. Gibbs #define		DEVID_9005_TYPE_HBA		0x0	/* Standard Card */
10817d24755SJustin T. Gibbs #define		DEVID_9005_TYPE_HBA_2EXT	0x1	/* 2 External Ports */
10917d24755SJustin T. Gibbs #define		DEVID_9005_TYPE_MB		0xF	/* On Motherboard */
11017d24755SJustin T. Gibbs 
11117d24755SJustin T. Gibbs #define DEVID_9005_MFUNC(id) ((id) & 0x10)
11217d24755SJustin T. Gibbs 
11317d24755SJustin T. Gibbs #define DEVID_9005_PACKETIZED(id) ((id) & 0x8000)
11417d24755SJustin T. Gibbs 
11517d24755SJustin T. Gibbs #define SUBID_9005_TYPE(id) ((id) & 0xF)
11617d24755SJustin T. Gibbs #define		SUBID_9005_TYPE_HBA		0x0	/* Standard Card */
11717d24755SJustin T. Gibbs #define		SUBID_9005_TYPE_MB		0xF	/* On Motherboard */
11817d24755SJustin T. Gibbs 
11917d24755SJustin T. Gibbs #define SUBID_9005_AUTOTERM(id)	(((id) & 0x10) == 0)
12017d24755SJustin T. Gibbs 
12117d24755SJustin T. Gibbs #define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20)
12217d24755SJustin T. Gibbs 
12317d24755SJustin T. Gibbs #define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6)
12417d24755SJustin T. Gibbs #define		SUBID_9005_SEEPTYPE_NONE	0x0
12517d24755SJustin T. Gibbs #define		SUBID_9005_SEEPTYPE_4K		0x1
12617d24755SJustin T. Gibbs 
127197696e9SJustin T. Gibbs static ahd_device_setup_t ahd_aic7901_setup;
1281a1fbd0bSJustin T. Gibbs static ahd_device_setup_t ahd_aic7901A_setup;
129454bf169SScott Long static ahd_device_setup_t ahd_aic7902_setup;
130c8ee7177SJustin T. Gibbs static ahd_device_setup_t ahd_aic790X_setup;
13117d24755SJustin T. Gibbs 
13217d24755SJustin T. Gibbs struct ahd_pci_identity ahd_pci_ident_table [] =
13317d24755SJustin T. Gibbs {
134197696e9SJustin T. Gibbs 	/* aic7901 based controllers */
135197696e9SJustin T. Gibbs 	{
136197696e9SJustin T. Gibbs 		ID_AHA_29320A,
137197696e9SJustin T. Gibbs 		ID_ALL_MASK,
138197696e9SJustin T. Gibbs 		"Adaptec 29320A Ultra320 SCSI adapter",
139197696e9SJustin T. Gibbs 		ahd_aic7901_setup
140197696e9SJustin T. Gibbs 	},
141197696e9SJustin T. Gibbs 	{
142197696e9SJustin T. Gibbs 		ID_AHA_29320ALP,
143197696e9SJustin T. Gibbs 		ID_ALL_MASK,
144197696e9SJustin T. Gibbs 		"Adaptec 29320ALP Ultra320 SCSI adapter",
145197696e9SJustin T. Gibbs 		ahd_aic7901_setup
146197696e9SJustin T. Gibbs 	},
147454bf169SScott Long 	/* aic7901A based controllers */
148454bf169SScott Long 	{
149454bf169SScott Long 		ID_AHA_29320LP,
150454bf169SScott Long 		ID_ALL_MASK,
151454bf169SScott Long 		"Adaptec 29320LP Ultra320 SCSI adapter",
152454bf169SScott Long 		ahd_aic7901A_setup
153454bf169SScott Long 	},
15417d24755SJustin T. Gibbs 	/* aic7902 based controllers */
15517d24755SJustin T. Gibbs 	{
156b3b25f2cSJustin T. Gibbs 		ID_AHA_29320,
157b3b25f2cSJustin T. Gibbs 		ID_ALL_MASK,
158b3b25f2cSJustin T. Gibbs 		"Adaptec 29320 Ultra320 SCSI adapter",
159b3b25f2cSJustin T. Gibbs 		ahd_aic7902_setup
160b3b25f2cSJustin T. Gibbs 	},
161b3b25f2cSJustin T. Gibbs 	{
162b3b25f2cSJustin T. Gibbs 		ID_AHA_29320B,
163b3b25f2cSJustin T. Gibbs 		ID_ALL_MASK,
164b3b25f2cSJustin T. Gibbs 		"Adaptec 29320B Ultra320 SCSI adapter",
165b3b25f2cSJustin T. Gibbs 		ahd_aic7902_setup
166b3b25f2cSJustin T. Gibbs 	},
167b3b25f2cSJustin T. Gibbs 	{
16817d24755SJustin T. Gibbs 		ID_AHA_39320,
16917d24755SJustin T. Gibbs 		ID_ALL_MASK,
17017d24755SJustin T. Gibbs 		"Adaptec 39320 Ultra320 SCSI adapter",
17117d24755SJustin T. Gibbs 		ahd_aic7902_setup
17217d24755SJustin T. Gibbs 	},
17317d24755SJustin T. Gibbs 	{
174197696e9SJustin T. Gibbs 		ID_AHA_39320_B,
175197696e9SJustin T. Gibbs 		ID_ALL_MASK,
176197696e9SJustin T. Gibbs 		"Adaptec 39320 Ultra320 SCSI adapter",
177197696e9SJustin T. Gibbs 		ahd_aic7902_setup
178197696e9SJustin T. Gibbs 	},
179197696e9SJustin T. Gibbs 	{
18022dbd4c6SJustin T. Gibbs 		ID_AHA_39320_B_DELL,
18122dbd4c6SJustin T. Gibbs 		ID_ALL_MASK,
18222dbd4c6SJustin T. Gibbs 		"Adaptec (Dell OEM) 39320 Ultra320 SCSI adapter",
18322dbd4c6SJustin T. Gibbs 		ahd_aic7902_setup
18422dbd4c6SJustin T. Gibbs 	},
18522dbd4c6SJustin T. Gibbs 	{
186acae33b0SJustin T. Gibbs 		ID_AHA_39320A,
187acae33b0SJustin T. Gibbs 		ID_ALL_MASK,
188acae33b0SJustin T. Gibbs 		"Adaptec 39320A Ultra320 SCSI adapter",
189acae33b0SJustin T. Gibbs 		ahd_aic7902_setup
190acae33b0SJustin T. Gibbs 	},
191acae33b0SJustin T. Gibbs 	{
19217d24755SJustin T. Gibbs 		ID_AHA_39320D,
19317d24755SJustin T. Gibbs 		ID_ALL_MASK,
19417d24755SJustin T. Gibbs 		"Adaptec 39320D Ultra320 SCSI adapter",
19517d24755SJustin T. Gibbs 		ahd_aic7902_setup
19617d24755SJustin T. Gibbs 	},
19717d24755SJustin T. Gibbs 	{
198454bf169SScott Long 		ID_AHA_39320D_HP,
19917d24755SJustin T. Gibbs 		ID_ALL_MASK,
200454bf169SScott Long 		"Adaptec (HP OEM) 39320D Ultra320 SCSI adapter",
201454bf169SScott Long 		ahd_aic7902_setup
202454bf169SScott Long 	},
203454bf169SScott Long 	{
204454bf169SScott Long 		ID_AHA_39320D_B,
205454bf169SScott Long 		ID_ALL_MASK,
206454bf169SScott Long 		"Adaptec 39320D Ultra320 SCSI adapter",
207454bf169SScott Long 		ahd_aic7902_setup
208454bf169SScott Long 	},
209454bf169SScott Long 	{
210454bf169SScott Long 		ID_AHA_39320D_B_HP,
211454bf169SScott Long 		ID_ALL_MASK,
212454bf169SScott Long 		"Adaptec (HP OEM) 39320D Ultra320 SCSI adapter",
21317d24755SJustin T. Gibbs 		ahd_aic7902_setup
21417d24755SJustin T. Gibbs 	},
215a4522488SChristian Brueffer 	{
216a4522488SChristian Brueffer 		ID_AHA_39320LPE,
217a4522488SChristian Brueffer 		ID_ALL_MASK,
218a4522488SChristian Brueffer 		"Adaptec 39320LPE Ultra320 SCSI adapter",
219a4522488SChristian Brueffer 		ahd_aic7902_setup
220a4522488SChristian Brueffer 	},
22117d24755SJustin T. Gibbs 	/* Generic chip probes for devices we don't know 'exactly' */
22217d24755SJustin T. Gibbs 	{
2234164174aSJustin T. Gibbs 		ID_AIC7901 & ID_9005_GENERIC_MASK,
22422dbd4c6SJustin T. Gibbs 		ID_9005_GENERIC_MASK,
225197696e9SJustin T. Gibbs 		"Adaptec AIC7901 Ultra320 SCSI adapter",
226197696e9SJustin T. Gibbs 		ahd_aic7901_setup
227197696e9SJustin T. Gibbs 	},
228197696e9SJustin T. Gibbs 	{
22997cae63dSScott Long 		ID_AIC7901A & ID_DEV_VENDOR_MASK,
23097cae63dSScott Long 		ID_DEV_VENDOR_MASK,
231454bf169SScott Long 		"Adaptec AIC7901A Ultra320 SCSI adapter",
232454bf169SScott Long 		ahd_aic7901A_setup
23317d24755SJustin T. Gibbs 	},
23417d24755SJustin T. Gibbs 	{
23517d24755SJustin T. Gibbs 		ID_AIC7902 & ID_9005_GENERIC_MASK,
23617d24755SJustin T. Gibbs 		ID_9005_GENERIC_MASK,
237454bf169SScott Long 		"Adaptec AIC7902 Ultra320 SCSI adapter",
23817d24755SJustin T. Gibbs 		ahd_aic7902_setup
23917d24755SJustin T. Gibbs 	}
24017d24755SJustin T. Gibbs };
24117d24755SJustin T. Gibbs 
24217d24755SJustin T. Gibbs const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table);
24317d24755SJustin T. Gibbs 
24417d24755SJustin T. Gibbs #define	DEVCONFIG		0x40
24517d24755SJustin T. Gibbs #define		PCIXINITPAT	0x0000E000ul
24617d24755SJustin T. Gibbs #define			PCIXINIT_PCI33_66	0x0000E000ul
24717d24755SJustin T. Gibbs #define			PCIXINIT_PCIX50_66	0x0000C000ul
24817d24755SJustin T. Gibbs #define			PCIXINIT_PCIX66_100	0x0000A000ul
24917d24755SJustin T. Gibbs #define			PCIXINIT_PCIX100_133	0x00008000ul
25017d24755SJustin T. Gibbs #define	PCI_BUS_MODES_INDEX(devconfig)	\
25117d24755SJustin T. Gibbs 	(((devconfig) & PCIXINITPAT) >> 13)
25217d24755SJustin T. Gibbs static const char *pci_bus_modes[] =
25317d24755SJustin T. Gibbs {
25417d24755SJustin T. Gibbs 	"PCI bus mode unknown",
25517d24755SJustin T. Gibbs 	"PCI bus mode unknown",
25617d24755SJustin T. Gibbs 	"PCI bus mode unknown",
25717d24755SJustin T. Gibbs 	"PCI bus mode unknown",
25879649302SGavin Atkinson 	"PCI-X 101-133MHz",
25979649302SGavin Atkinson 	"PCI-X 67-100MHz",
26079649302SGavin Atkinson 	"PCI-X 50-66MHz",
26179649302SGavin Atkinson 	"PCI 33 or 66MHz"
26217d24755SJustin T. Gibbs };
26317d24755SJustin T. Gibbs 
26417d24755SJustin T. Gibbs #define		TESTMODE	0x00000800ul
26517d24755SJustin T. Gibbs #define		IRDY_RST	0x00000200ul
26617d24755SJustin T. Gibbs #define		FRAME_RST	0x00000100ul
26717d24755SJustin T. Gibbs #define		PCI64BIT	0x00000080ul
26817d24755SJustin T. Gibbs #define		MRDCEN		0x00000040ul
26917d24755SJustin T. Gibbs #define		ENDIANSEL	0x00000020ul
27017d24755SJustin T. Gibbs #define		MIXQWENDIANEN	0x00000008ul
27117d24755SJustin T. Gibbs #define		DACEN		0x00000004ul
27217d24755SJustin T. Gibbs #define		STPWLEVEL	0x00000002ul
27317d24755SJustin T. Gibbs #define		QWENDIANSEL	0x00000001ul
27417d24755SJustin T. Gibbs 
27517d24755SJustin T. Gibbs #define	DEVCONFIG1		0x44
27617d24755SJustin T. Gibbs #define		PREQDIS		0x01
27717d24755SJustin T. Gibbs 
27817d24755SJustin T. Gibbs #define	CSIZE_LATTIME		0x0c
27917d24755SJustin T. Gibbs #define		CACHESIZE	0x000000fful
28017d24755SJustin T. Gibbs #define		LATTIME		0x0000ff00ul
28117d24755SJustin T. Gibbs 
28217d24755SJustin T. Gibbs static int	ahd_check_extport(struct ahd_softc *ahd);
28317d24755SJustin T. Gibbs static void	ahd_configure_termination(struct ahd_softc *ahd,
28417d24755SJustin T. Gibbs 					  u_int adapter_control);
28517d24755SJustin T. Gibbs static void	ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
28617d24755SJustin T. Gibbs 
28717d24755SJustin T. Gibbs struct ahd_pci_identity *
288b3b25f2cSJustin T. Gibbs ahd_find_pci_device(aic_dev_softc_t pci)
28917d24755SJustin T. Gibbs {
29017d24755SJustin T. Gibbs 	uint64_t  full_id;
29117d24755SJustin T. Gibbs 	uint16_t  device;
29217d24755SJustin T. Gibbs 	uint16_t  vendor;
29317d24755SJustin T. Gibbs 	uint16_t  subdevice;
29417d24755SJustin T. Gibbs 	uint16_t  subvendor;
29517d24755SJustin T. Gibbs 	struct	  ahd_pci_identity *entry;
29617d24755SJustin T. Gibbs 	u_int	  i;
29717d24755SJustin T. Gibbs 
298b3b25f2cSJustin T. Gibbs 	vendor = aic_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
299b3b25f2cSJustin T. Gibbs 	device = aic_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
300b3b25f2cSJustin T. Gibbs 	subvendor = aic_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
301b3b25f2cSJustin T. Gibbs 	subdevice = aic_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
3027cfc62d8SAchim Leubner 
3037cfc62d8SAchim Leubner 	if ((vendor == ADAPTECVENDORID) && (subvendor == SUBVENDOR9005)) {
3047cfc62d8SAchim Leubner 		if ((device == DEVICE8081) || (device == DEVICE8088) ||
3057cfc62d8SAchim Leubner 			(device == DEVICE8089)) {
3067cfc62d8SAchim Leubner 			printf("Controller device ID conflict with PMC Adaptec HBA\n");
3077cfc62d8SAchim Leubner 			return (NULL);
3087cfc62d8SAchim Leubner 		}
3097cfc62d8SAchim Leubner 	}
3107cfc62d8SAchim Leubner 
31117d24755SJustin T. Gibbs 	full_id = ahd_compose_id(device,
31217d24755SJustin T. Gibbs 				 vendor,
31317d24755SJustin T. Gibbs 				 subdevice,
31417d24755SJustin T. Gibbs 				 subvendor);
31517d24755SJustin T. Gibbs 
3164164174aSJustin T. Gibbs 	/*
3174164174aSJustin T. Gibbs 	 * If we are configured to attach to HostRAID
3184164174aSJustin T. Gibbs 	 * controllers, mask out the IROC/HostRAID bit
3194164174aSJustin T. Gibbs 	 * in the
3204164174aSJustin T. Gibbs 	 */
3214164174aSJustin T. Gibbs 	if (ahd_attach_to_HostRAID_controllers)
3224164174aSJustin T. Gibbs 		full_id &= ID_ALL_IROC_MASK;
3234164174aSJustin T. Gibbs 
32417d24755SJustin T. Gibbs 	for (i = 0; i < ahd_num_pci_devs; i++) {
32517d24755SJustin T. Gibbs 		entry = &ahd_pci_ident_table[i];
32617d24755SJustin T. Gibbs 		if (entry->full_id == (full_id & entry->id_mask)) {
32717d24755SJustin T. Gibbs 			/* Honor exclusion entries. */
32817d24755SJustin T. Gibbs 			if (entry->name == NULL)
32917d24755SJustin T. Gibbs 				return (NULL);
33017d24755SJustin T. Gibbs 			return (entry);
33117d24755SJustin T. Gibbs 		}
33217d24755SJustin T. Gibbs 	}
33317d24755SJustin T. Gibbs 	return (NULL);
33417d24755SJustin T. Gibbs }
33517d24755SJustin T. Gibbs 
33617d24755SJustin T. Gibbs int
33717d24755SJustin T. Gibbs ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
33817d24755SJustin T. Gibbs {
33917d24755SJustin T. Gibbs 	u_int		 command;
34017d24755SJustin T. Gibbs 	uint32_t	 devconfig;
3414164174aSJustin T. Gibbs 	uint16_t	 device;
34217d24755SJustin T. Gibbs 	uint16_t	 subvendor;
34317d24755SJustin T. Gibbs 	int		 error;
34417d24755SJustin T. Gibbs 
345454bf169SScott Long 	ahd->description = entry->name;
346454bf169SScott Long 	/*
3474164174aSJustin T. Gibbs 	 * Record if this is a HostRAID board.
3484164174aSJustin T. Gibbs 	 */
3494164174aSJustin T. Gibbs 	device = aic_pci_read_config(ahd->dev_softc,
3504164174aSJustin T. Gibbs 				     PCIR_DEVICE, /*bytes*/2);
3514164174aSJustin T. Gibbs 	if (DEVID_9005_HOSTRAID(device))
3524164174aSJustin T. Gibbs 		ahd->flags |= AHD_HOSTRAID_BOARD;
3534164174aSJustin T. Gibbs 
3544164174aSJustin T. Gibbs 	/*
355454bf169SScott Long 	 * Record if this is an HP board.
356454bf169SScott Long 	 */
357b3b25f2cSJustin T. Gibbs 	subvendor = aic_pci_read_config(ahd->dev_softc,
358454bf169SScott Long 					PCIR_SUBVEND_0, /*bytes*/2);
359454bf169SScott Long 	if (subvendor == SUBID_HP)
360454bf169SScott Long 		ahd->flags |= AHD_HP_BOARD;
361454bf169SScott Long 
36217d24755SJustin T. Gibbs 	error = entry->setup(ahd);
36317d24755SJustin T. Gibbs 	if (error != 0)
36417d24755SJustin T. Gibbs 		return (error);
36517d24755SJustin T. Gibbs 
3666eb7ebfeSJohn Baldwin 	/*
3676eb7ebfeSJohn Baldwin 	 * Find the PCI-X cap pointer.  If we don't find it,
3686eb7ebfeSJohn Baldwin 	 * pcix_ptr will be 0.
3696eb7ebfeSJohn Baldwin 	 */
3703b0a4aefSJohn Baldwin 	pci_find_cap(ahd->dev_softc, PCIY_PCIX, &ahd->pcix_ptr);
371b3b25f2cSJustin T. Gibbs 	devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
37217d24755SJustin T. Gibbs 	if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) {
37317d24755SJustin T. Gibbs 		ahd->chip |= AHD_PCI;
37417d24755SJustin T. Gibbs 		/* Disable PCIX workarounds when running in PCI mode. */
37517d24755SJustin T. Gibbs 		ahd->bugs &= ~AHD_PCIX_BUG_MASK;
37617d24755SJustin T. Gibbs 	} else {
37717d24755SJustin T. Gibbs 		ahd->chip |= AHD_PCIX;
3786eb7ebfeSJohn Baldwin 		if (ahd->pcix_ptr == 0)
3796eb7ebfeSJohn Baldwin 			return (ENXIO);
38017d24755SJustin T. Gibbs 	}
38117d24755SJustin T. Gibbs 	ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)];
38217d24755SJustin T. Gibbs 
383b3b25f2cSJustin T. Gibbs 	aic_power_state_change(ahd, AIC_POWER_STATE_D0);
38417d24755SJustin T. Gibbs 
38517d24755SJustin T. Gibbs 	error = ahd_pci_map_registers(ahd);
38617d24755SJustin T. Gibbs 	if (error != 0)
38717d24755SJustin T. Gibbs 		return (error);
38817d24755SJustin T. Gibbs 
38917d24755SJustin T. Gibbs 	/*
39017d24755SJustin T. Gibbs 	 * If we need to support high memory, enable dual
39117d24755SJustin T. Gibbs 	 * address cycles.  This bit must be set to enable
39217d24755SJustin T. Gibbs 	 * high address bit generation even if we are on a
39317d24755SJustin T. Gibbs 	 * 64bit bus (PCI64BIT set in devconfig).
39417d24755SJustin T. Gibbs 	 */
39517d24755SJustin T. Gibbs 	if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
39617d24755SJustin T. Gibbs 		uint32_t devconfig;
39717d24755SJustin T. Gibbs 
39817d24755SJustin T. Gibbs 		if (bootverbose)
39917d24755SJustin T. Gibbs 			printf("%s: Enabling 39Bit Addressing\n",
40017d24755SJustin T. Gibbs 			       ahd_name(ahd));
401b3b25f2cSJustin T. Gibbs 		devconfig = aic_pci_read_config(ahd->dev_softc,
40217d24755SJustin T. Gibbs 						DEVCONFIG, /*bytes*/4);
40317d24755SJustin T. Gibbs 		devconfig |= DACEN;
404b3b25f2cSJustin T. Gibbs 		aic_pci_write_config(ahd->dev_softc, DEVCONFIG,
40517d24755SJustin T. Gibbs 				     devconfig, /*bytes*/4);
40617d24755SJustin T. Gibbs 	}
40717d24755SJustin T. Gibbs 
40817d24755SJustin T. Gibbs 	/* Ensure busmastering is enabled */
409b3b25f2cSJustin T. Gibbs 	command = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
41017d24755SJustin T. Gibbs 	command |= PCIM_CMD_BUSMASTEREN;
411b3b25f2cSJustin T. Gibbs 	aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
41217d24755SJustin T. Gibbs 
41317d24755SJustin T. Gibbs 	error = ahd_softc_init(ahd);
41417d24755SJustin T. Gibbs 	if (error != 0)
41517d24755SJustin T. Gibbs 		return (error);
41617d24755SJustin T. Gibbs 
41717d24755SJustin T. Gibbs 	ahd->bus_intr = ahd_pci_intr;
41817d24755SJustin T. Gibbs 
4191d528d67SJustin T. Gibbs 	error = ahd_reset(ahd, /*reinit*/FALSE);
42017d24755SJustin T. Gibbs 	if (error != 0)
42117d24755SJustin T. Gibbs 		return (ENXIO);
42217d24755SJustin T. Gibbs 
42317d24755SJustin T. Gibbs 	ahd->pci_cachesize =
424b3b25f2cSJustin T. Gibbs 	    aic_pci_read_config(ahd->dev_softc, CSIZE_LATTIME,
42517d24755SJustin T. Gibbs 				/*bytes*/1) & CACHESIZE;
42617d24755SJustin T. Gibbs 	ahd->pci_cachesize *= 4;
42717d24755SJustin T. Gibbs 
42817d24755SJustin T. Gibbs 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
42917d24755SJustin T. Gibbs 	/* See if we have a SEEPROM and perform auto-term */
43017d24755SJustin T. Gibbs 	error = ahd_check_extport(ahd);
43117d24755SJustin T. Gibbs 	if (error != 0)
43217d24755SJustin T. Gibbs 		return (error);
43317d24755SJustin T. Gibbs 
43417d24755SJustin T. Gibbs 	/* Core initialization */
43517d24755SJustin T. Gibbs 	error = ahd_init(ahd);
43617d24755SJustin T. Gibbs 	if (error != 0)
43717d24755SJustin T. Gibbs 		return (error);
43817d24755SJustin T. Gibbs 
43917d24755SJustin T. Gibbs 	/*
44017d24755SJustin T. Gibbs 	 * Allow interrupts now that we are completely setup.
44117d24755SJustin T. Gibbs 	 */
44217d24755SJustin T. Gibbs 	error = ahd_pci_map_int(ahd);
44317d24755SJustin T. Gibbs 	if (error != 0)
44417d24755SJustin T. Gibbs 		return (error);
44517d24755SJustin T. Gibbs 
446032b0a17SScott Long 	ahd_lock(ahd);
44717d24755SJustin T. Gibbs 	/*
44817d24755SJustin T. Gibbs 	 * Link this softc in with all other ahd instances.
44917d24755SJustin T. Gibbs 	 */
45017d24755SJustin T. Gibbs 	ahd_softc_insert(ahd);
451032b0a17SScott Long 	ahd_unlock(ahd);
45217d24755SJustin T. Gibbs 	return (0);
45317d24755SJustin T. Gibbs }
45417d24755SJustin T. Gibbs 
45517d24755SJustin T. Gibbs /*
456454bf169SScott Long  * Perform some simple tests that should catch situations where
457454bf169SScott Long  * our registers are invalidly mapped.
458454bf169SScott Long  */
459454bf169SScott Long int
460454bf169SScott Long ahd_pci_test_register_access(struct ahd_softc *ahd)
461454bf169SScott Long {
4620794987dSJustin T. Gibbs 	uint32_t cmd;
463176b648eSJustin T. Gibbs 	u_int	 targpcistat;
464176b648eSJustin T. Gibbs 	u_int	 pci_status1;
46597cae63dSScott Long 	int	 error;
4660794987dSJustin T. Gibbs 	uint8_t	 hcntrl;
46797cae63dSScott Long 
46897cae63dSScott Long 	error = EIO;
46997cae63dSScott Long 
4700794987dSJustin T. Gibbs 	/*
4710794987dSJustin T. Gibbs 	 * Enable PCI error interrupt status, but suppress NMIs
4720794987dSJustin T. Gibbs 	 * generated by SERR raised due to target aborts.
4730794987dSJustin T. Gibbs 	 */
474b3b25f2cSJustin T. Gibbs 	cmd = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
475b3b25f2cSJustin T. Gibbs 	aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
4760794987dSJustin T. Gibbs 			     cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2);
477454bf169SScott Long 
478454bf169SScott Long 	/*
479454bf169SScott Long 	 * First a simple test to see if any
480454bf169SScott Long 	 * registers can be read.  Reading
481454bf169SScott Long 	 * HCNTRL has no side effects and has
482454bf169SScott Long 	 * at least one bit that is guaranteed to
483454bf169SScott Long 	 * be zero so it is a good register to
484454bf169SScott Long 	 * use for this test.
485454bf169SScott Long 	 */
4860794987dSJustin T. Gibbs 	hcntrl = ahd_inb(ahd, HCNTRL);
4870794987dSJustin T. Gibbs 	if (hcntrl == 0xFF)
48897cae63dSScott Long 		goto fail;
489454bf169SScott Long 
490454bf169SScott Long 	/*
491454bf169SScott Long 	 * Next create a situation where write combining
492454bf169SScott Long 	 * or read prefetching could be initiated by the
493454bf169SScott Long 	 * CPU or host bridge.  Our device does not support
494594c945aSPedro F. Giffuni 	 * either, so look for data corruption and/or flagged
495ba079c0dSScott Long 	 * PCI errors.  First pause without causing another
496ba079c0dSScott Long 	 * chip reset.
497454bf169SScott Long 	 */
498ba079c0dSScott Long 	hcntrl &= ~CHIPRST;
4990794987dSJustin T. Gibbs 	ahd_outb(ahd, HCNTRL, hcntrl|PAUSE);
5000794987dSJustin T. Gibbs 	while (ahd_is_paused(ahd) == 0)
5010794987dSJustin T. Gibbs 		;
502176b648eSJustin T. Gibbs 
503176b648eSJustin T. Gibbs 	/* Clear any PCI errors that occurred before our driver attached. */
504176b648eSJustin T. Gibbs 	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
505176b648eSJustin T. Gibbs 	targpcistat = ahd_inb(ahd, TARGPCISTAT);
506176b648eSJustin T. Gibbs 	ahd_outb(ahd, TARGPCISTAT, targpcistat);
507b3b25f2cSJustin T. Gibbs 	pci_status1 = aic_pci_read_config(ahd->dev_softc,
508176b648eSJustin T. Gibbs 					  PCIR_STATUS + 1, /*bytes*/1);
509b3b25f2cSJustin T. Gibbs 	aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
510176b648eSJustin T. Gibbs 			     pci_status1, /*bytes*/1);
511176b648eSJustin T. Gibbs 	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
512176b648eSJustin T. Gibbs 	ahd_outb(ahd, CLRINT, CLRPCIINT);
513176b648eSJustin T. Gibbs 
5140794987dSJustin T. Gibbs 	ahd_outb(ahd, SEQCTL0, PERRORDIS);
51597cae63dSScott Long 	ahd_outl(ahd, SRAM_BASE, 0x5aa555aa);
51697cae63dSScott Long 	if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa)
51797cae63dSScott Long 		goto fail;
518454bf169SScott Long 
519454bf169SScott Long 	if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) {
52097cae63dSScott Long 		u_int targpcistat;
52197cae63dSScott Long 
52297cae63dSScott Long 		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
52397cae63dSScott Long 		targpcistat = ahd_inb(ahd, TARGPCISTAT);
52497cae63dSScott Long 		if ((targpcistat & STA) != 0)
52597cae63dSScott Long 			goto fail;
52697cae63dSScott Long 	}
52797cae63dSScott Long 
52897cae63dSScott Long 	error = 0;
52997cae63dSScott Long 
53097cae63dSScott Long fail:
53197cae63dSScott Long 	if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) {
532454bf169SScott Long 
533454bf169SScott Long 		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
534454bf169SScott Long 		targpcistat = ahd_inb(ahd, TARGPCISTAT);
535454bf169SScott Long 
536454bf169SScott Long 		/* Silently clear any latched errors. */
537454bf169SScott Long 		ahd_outb(ahd, TARGPCISTAT, targpcistat);
538b3b25f2cSJustin T. Gibbs 		pci_status1 = aic_pci_read_config(ahd->dev_softc,
539454bf169SScott Long 						  PCIR_STATUS + 1, /*bytes*/1);
540b3b25f2cSJustin T. Gibbs 		aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
541454bf169SScott Long 				     pci_status1, /*bytes*/1);
54297cae63dSScott Long 		ahd_outb(ahd, CLRINT, CLRPCIINT);
543454bf169SScott Long 	}
5440794987dSJustin T. Gibbs 	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS);
545b3b25f2cSJustin T. Gibbs 	aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);
54697cae63dSScott Long 	return (error);
547454bf169SScott Long }
548454bf169SScott Long 
549454bf169SScott Long /*
55017d24755SJustin T. Gibbs  * Check the external port logic for a serial eeprom
55117d24755SJustin T. Gibbs  * and termination/cable detection contrls.
55217d24755SJustin T. Gibbs  */
55317d24755SJustin T. Gibbs static int
55417d24755SJustin T. Gibbs ahd_check_extport(struct ahd_softc *ahd)
55517d24755SJustin T. Gibbs {
556d7cff4abSJustin T. Gibbs 	struct	vpd_config vpd;
55717d24755SJustin T. Gibbs 	struct	seeprom_config *sc;
55817d24755SJustin T. Gibbs 	u_int	adapter_control;
55917d24755SJustin T. Gibbs 	int	have_seeprom;
56017d24755SJustin T. Gibbs 	int	error;
56117d24755SJustin T. Gibbs 
56217d24755SJustin T. Gibbs 	sc = ahd->seep_config;
56317d24755SJustin T. Gibbs 	have_seeprom = ahd_acquire_seeprom(ahd);
56417d24755SJustin T. Gibbs 	if (have_seeprom) {
56517d24755SJustin T. Gibbs 		u_int start_addr;
56617d24755SJustin T. Gibbs 
567d7cff4abSJustin T. Gibbs 		/*
568d7cff4abSJustin T. Gibbs 		 * Fetch VPD for this function and parse it.
569d7cff4abSJustin T. Gibbs 		 */
570d7cff4abSJustin T. Gibbs 		if (bootverbose)
571d7cff4abSJustin T. Gibbs 			printf("%s: Reading VPD from SEEPROM...",
572d7cff4abSJustin T. Gibbs 			       ahd_name(ahd));
573d7cff4abSJustin T. Gibbs 
574d7cff4abSJustin T. Gibbs 		/* Address is always in units of 16bit words */
575d7cff4abSJustin T. Gibbs 		start_addr = ((2 * sizeof(*sc))
576d7cff4abSJustin T. Gibbs 			    + (sizeof(vpd) * (ahd->channel - 'A'))) / 2;
577d7cff4abSJustin T. Gibbs 
578d7cff4abSJustin T. Gibbs 		error = ahd_read_seeprom(ahd, (uint16_t *)&vpd,
579d7cff4abSJustin T. Gibbs 					 start_addr, sizeof(vpd)/2,
580d7cff4abSJustin T. Gibbs 					 /*bytestream*/TRUE);
581d7cff4abSJustin T. Gibbs 		if (error == 0)
582d7cff4abSJustin T. Gibbs 			error = ahd_parse_vpddata(ahd, &vpd);
583d7cff4abSJustin T. Gibbs 		if (bootverbose)
584d7cff4abSJustin T. Gibbs 			printf("%s: VPD parsing %s\n",
585d7cff4abSJustin T. Gibbs 			       ahd_name(ahd),
586d7cff4abSJustin T. Gibbs 			       error == 0 ? "successful" : "failed");
587d7cff4abSJustin T. Gibbs 
58817d24755SJustin T. Gibbs 		if (bootverbose)
58917d24755SJustin T. Gibbs 			printf("%s: Reading SEEPROM...", ahd_name(ahd));
59017d24755SJustin T. Gibbs 
59117d24755SJustin T. Gibbs 		/* Address is always in units of 16bit words */
59217d24755SJustin T. Gibbs 		start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
59317d24755SJustin T. Gibbs 
59417d24755SJustin T. Gibbs 		error = ahd_read_seeprom(ahd, (uint16_t *)sc,
595d7cff4abSJustin T. Gibbs 					 start_addr, sizeof(*sc)/2,
596d7cff4abSJustin T. Gibbs 					 /*bytestream*/FALSE);
59717d24755SJustin T. Gibbs 
59817d24755SJustin T. Gibbs 		if (error != 0) {
59917d24755SJustin T. Gibbs 			printf("Unable to read SEEPROM\n");
60017d24755SJustin T. Gibbs 			have_seeprom = 0;
60117d24755SJustin T. Gibbs 		} else {
60217d24755SJustin T. Gibbs 			have_seeprom = ahd_verify_cksum(sc);
60317d24755SJustin T. Gibbs 
60417d24755SJustin T. Gibbs 			if (bootverbose) {
60517d24755SJustin T. Gibbs 				if (have_seeprom == 0)
60617d24755SJustin T. Gibbs 					printf ("checksum error\n");
60717d24755SJustin T. Gibbs 				else
60817d24755SJustin T. Gibbs 					printf ("done.\n");
60917d24755SJustin T. Gibbs 			}
61017d24755SJustin T. Gibbs 		}
61117d24755SJustin T. Gibbs 		ahd_release_seeprom(ahd);
61217d24755SJustin T. Gibbs 	}
61317d24755SJustin T. Gibbs 
61417d24755SJustin T. Gibbs 	if (!have_seeprom) {
61517d24755SJustin T. Gibbs 		u_int	  nvram_scb;
61617d24755SJustin T. Gibbs 
61717d24755SJustin T. Gibbs 		/*
61817d24755SJustin T. Gibbs 		 * Pull scratch ram settings and treat them as
61917d24755SJustin T. Gibbs 		 * if they are the contents of an seeprom if
62017d24755SJustin T. Gibbs 		 * the 'ADPT', 'BIOS', or 'ASPI' signature is found
62117d24755SJustin T. Gibbs 		 * in SCB 0xFF.  We manually compose the data as 16bit
62217d24755SJustin T. Gibbs 		 * values to avoid endian issues.
62317d24755SJustin T. Gibbs 		 */
62417d24755SJustin T. Gibbs 		ahd_set_scbptr(ahd, 0xFF);
62517d24755SJustin T. Gibbs 		nvram_scb = ahd_inb_scbram(ahd, SCB_BASE + NVRAM_SCB_OFFSET);
62617d24755SJustin T. Gibbs 		if (nvram_scb != 0xFF
62717d24755SJustin T. Gibbs 		 && ((ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A'
62817d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'D'
62917d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P'
63017d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'T')
63117d24755SJustin T. Gibbs 		  || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'B'
63217d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'I'
63317d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'O'
63417d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'S')
63517d24755SJustin T. Gibbs 		  || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A'
63617d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'S'
63717d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P'
63817d24755SJustin T. Gibbs 		   && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'I'))) {
63917d24755SJustin T. Gibbs 			uint16_t *sc_data;
64017d24755SJustin T. Gibbs 			int	  i;
64117d24755SJustin T. Gibbs 
64217d24755SJustin T. Gibbs 			ahd_set_scbptr(ahd, nvram_scb);
64317d24755SJustin T. Gibbs 			sc_data = (uint16_t *)sc;
64417d24755SJustin T. Gibbs 			for (i = 0; i < 64; i += 2)
64517d24755SJustin T. Gibbs 				*sc_data++ = ahd_inw_scbram(ahd, SCB_BASE+i);
64617d24755SJustin T. Gibbs 			have_seeprom = ahd_verify_cksum(sc);
64717d24755SJustin T. Gibbs 			if (have_seeprom)
64817d24755SJustin T. Gibbs 				ahd->flags |= AHD_SCB_CONFIG_USED;
64917d24755SJustin T. Gibbs 		}
65017d24755SJustin T. Gibbs 	}
65117d24755SJustin T. Gibbs 
652f4e98881SRuslan Ermilov #ifdef AHD_DEBUG
65317d24755SJustin T. Gibbs 	if (have_seeprom != 0
65417d24755SJustin T. Gibbs 	 && (ahd_debug & AHD_DUMP_SEEPROM) != 0) {
655d7cff4abSJustin T. Gibbs 		uint16_t *sc_data;
65617d24755SJustin T. Gibbs 		int	  i;
65717d24755SJustin T. Gibbs 
65817d24755SJustin T. Gibbs 		printf("%s: Seeprom Contents:", ahd_name(ahd));
659d7cff4abSJustin T. Gibbs 		sc_data = (uint16_t *)sc;
66017d24755SJustin T. Gibbs 		for (i = 0; i < (sizeof(*sc)); i += 2)
661d7cff4abSJustin T. Gibbs 			printf("\n\t0x%.4x", sc_data[i]);
66217d24755SJustin T. Gibbs 		printf("\n");
66317d24755SJustin T. Gibbs 	}
66417d24755SJustin T. Gibbs #endif
66517d24755SJustin T. Gibbs 
66617d24755SJustin T. Gibbs 	if (!have_seeprom) {
66717d24755SJustin T. Gibbs 		if (bootverbose)
66817d24755SJustin T. Gibbs 			printf("%s: No SEEPROM available.\n", ahd_name(ahd));
66917d24755SJustin T. Gibbs 		ahd->flags |= AHD_USEDEFAULTS;
67017d24755SJustin T. Gibbs 		error = ahd_default_config(ahd);
67117d24755SJustin T. Gibbs 		adapter_control = CFAUTOTERM|CFSEAUTOTERM;
67217d24755SJustin T. Gibbs 		free(ahd->seep_config, M_DEVBUF);
67317d24755SJustin T. Gibbs 		ahd->seep_config = NULL;
67417d24755SJustin T. Gibbs 	} else {
67517d24755SJustin T. Gibbs 		error = ahd_parse_cfgdata(ahd, sc);
67617d24755SJustin T. Gibbs 		adapter_control = sc->adapter_control;
67717d24755SJustin T. Gibbs 	}
67817d24755SJustin T. Gibbs 	if (error != 0)
67917d24755SJustin T. Gibbs 		return (error);
68017d24755SJustin T. Gibbs 
68117d24755SJustin T. Gibbs 	ahd_configure_termination(ahd, adapter_control);
68217d24755SJustin T. Gibbs 
68317d24755SJustin T. Gibbs 	return (0);
68417d24755SJustin T. Gibbs }
68517d24755SJustin T. Gibbs 
68617d24755SJustin T. Gibbs static void
68717d24755SJustin T. Gibbs ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
68817d24755SJustin T. Gibbs {
68917d24755SJustin T. Gibbs 	int	 error;
69017d24755SJustin T. Gibbs 	u_int	 sxfrctl1;
69117d24755SJustin T. Gibbs 	uint8_t	 termctl;
69217d24755SJustin T. Gibbs 	uint32_t devconfig;
69317d24755SJustin T. Gibbs 
694b3b25f2cSJustin T. Gibbs 	devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
69517d24755SJustin T. Gibbs 	devconfig &= ~STPWLEVEL;
6961a1fbd0bSJustin T. Gibbs 	if ((ahd->flags & AHD_STPWLEVEL_A) != 0)
69717d24755SJustin T. Gibbs 		devconfig |= STPWLEVEL;
6981a1fbd0bSJustin T. Gibbs 	if (bootverbose)
6991a1fbd0bSJustin T. Gibbs 		printf("%s: STPWLEVEL is %s\n",
7001a1fbd0bSJustin T. Gibbs 		       ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off");
701b3b25f2cSJustin T. Gibbs 	aic_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
70217d24755SJustin T. Gibbs 
70317d24755SJustin T. Gibbs 	/* Make sure current sensing is off. */
70417d24755SJustin T. Gibbs 	if ((ahd->flags & AHD_CURRENT_SENSING) != 0) {
70517d24755SJustin T. Gibbs 		(void)ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0);
70617d24755SJustin T. Gibbs 	}
70717d24755SJustin T. Gibbs 
70817d24755SJustin T. Gibbs 	/*
70917d24755SJustin T. Gibbs 	 * Read to sense.  Write to set.
71017d24755SJustin T. Gibbs 	 */
71117d24755SJustin T. Gibbs 	error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl);
71217d24755SJustin T. Gibbs 	if ((adapter_control & CFAUTOTERM) == 0) {
71317d24755SJustin T. Gibbs 		if (bootverbose)
71417d24755SJustin T. Gibbs 			printf("%s: Manual Primary Termination\n",
71517d24755SJustin T. Gibbs 			       ahd_name(ahd));
71617d24755SJustin T. Gibbs 		termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH);
71717d24755SJustin T. Gibbs 		if ((adapter_control & CFSTERM) != 0)
71817d24755SJustin T. Gibbs 			termctl |= FLX_TERMCTL_ENPRILOW;
71917d24755SJustin T. Gibbs 		if ((adapter_control & CFWSTERM) != 0)
72017d24755SJustin T. Gibbs 			termctl |= FLX_TERMCTL_ENPRIHIGH;
72117d24755SJustin T. Gibbs 	} else if (error != 0) {
72217d24755SJustin T. Gibbs 		printf("%s: Primary Auto-Term Sensing failed! "
72317d24755SJustin T. Gibbs 		       "Using Defaults.\n", ahd_name(ahd));
72417d24755SJustin T. Gibbs 		termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH;
72517d24755SJustin T. Gibbs 	}
72617d24755SJustin T. Gibbs 
72717d24755SJustin T. Gibbs 	if ((adapter_control & CFSEAUTOTERM) == 0) {
72817d24755SJustin T. Gibbs 		if (bootverbose)
72917d24755SJustin T. Gibbs 			printf("%s: Manual Secondary Termination\n",
73017d24755SJustin T. Gibbs 			       ahd_name(ahd));
73117d24755SJustin T. Gibbs 		termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH);
73217d24755SJustin T. Gibbs 		if ((adapter_control & CFSELOWTERM) != 0)
73317d24755SJustin T. Gibbs 			termctl |= FLX_TERMCTL_ENSECLOW;
73417d24755SJustin T. Gibbs 		if ((adapter_control & CFSEHIGHTERM) != 0)
73517d24755SJustin T. Gibbs 			termctl |= FLX_TERMCTL_ENSECHIGH;
73617d24755SJustin T. Gibbs 	} else if (error != 0) {
73717d24755SJustin T. Gibbs 		printf("%s: Secondary Auto-Term Sensing failed! "
73817d24755SJustin T. Gibbs 		       "Using Defaults.\n", ahd_name(ahd));
73917d24755SJustin T. Gibbs 		termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH;
74017d24755SJustin T. Gibbs 	}
74117d24755SJustin T. Gibbs 
74217d24755SJustin T. Gibbs 	/*
74317d24755SJustin T. Gibbs 	 * Now set the termination based on what we found.
74417d24755SJustin T. Gibbs 	 */
74517d24755SJustin T. Gibbs 	sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN;
746b3b25f2cSJustin T. Gibbs 	ahd->flags &= ~AHD_TERM_ENB_A;
74717d24755SJustin T. Gibbs 	if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) {
74817d24755SJustin T. Gibbs 		ahd->flags |= AHD_TERM_ENB_A;
74917d24755SJustin T. Gibbs 		sxfrctl1 |= STPWEN;
75017d24755SJustin T. Gibbs 	}
75117d24755SJustin T. Gibbs 	/* Must set the latch once in order to be effective. */
75217d24755SJustin T. Gibbs 	ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN);
75317d24755SJustin T. Gibbs 	ahd_outb(ahd, SXFRCTL1, sxfrctl1);
75417d24755SJustin T. Gibbs 
75517d24755SJustin T. Gibbs 	error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl);
75617d24755SJustin T. Gibbs 	if (error != 0) {
75717d24755SJustin T. Gibbs 		printf("%s: Unable to set termination settings!\n",
75817d24755SJustin T. Gibbs 		       ahd_name(ahd));
75917d24755SJustin T. Gibbs 	} else if (bootverbose) {
76017d24755SJustin T. Gibbs 		printf("%s: Primary High byte termination %sabled\n",
76117d24755SJustin T. Gibbs 		       ahd_name(ahd),
76217d24755SJustin T. Gibbs 		       (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis");
76317d24755SJustin T. Gibbs 
76417d24755SJustin T. Gibbs 		printf("%s: Primary Low byte termination %sabled\n",
76517d24755SJustin T. Gibbs 		       ahd_name(ahd),
76617d24755SJustin T. Gibbs 		       (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis");
76717d24755SJustin T. Gibbs 
76817d24755SJustin T. Gibbs 		printf("%s: Secondary High byte termination %sabled\n",
76917d24755SJustin T. Gibbs 		       ahd_name(ahd),
77017d24755SJustin T. Gibbs 		       (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis");
77117d24755SJustin T. Gibbs 
77217d24755SJustin T. Gibbs 		printf("%s: Secondary Low byte termination %sabled\n",
77317d24755SJustin T. Gibbs 		       ahd_name(ahd),
77417d24755SJustin T. Gibbs 		       (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis");
77517d24755SJustin T. Gibbs 	}
77617d24755SJustin T. Gibbs 	return;
77717d24755SJustin T. Gibbs }
77817d24755SJustin T. Gibbs 
77917d24755SJustin T. Gibbs #define	DPE	0x80
78017d24755SJustin T. Gibbs #define SSE	0x40
78117d24755SJustin T. Gibbs #define	RMA	0x20
78217d24755SJustin T. Gibbs #define	RTA	0x10
78317d24755SJustin T. Gibbs #define STA	0x08
78417d24755SJustin T. Gibbs #define DPR	0x01
78517d24755SJustin T. Gibbs 
78617d24755SJustin T. Gibbs static const char *split_status_source[] =
78717d24755SJustin T. Gibbs {
78817d24755SJustin T. Gibbs 	"DFF0",
78917d24755SJustin T. Gibbs 	"DFF1",
79017d24755SJustin T. Gibbs 	"OVLY",
79117d24755SJustin T. Gibbs 	"CMC",
79217d24755SJustin T. Gibbs };
79317d24755SJustin T. Gibbs 
79417d24755SJustin T. Gibbs static const char *pci_status_source[] =
79517d24755SJustin T. Gibbs {
79617d24755SJustin T. Gibbs 	"DFF0",
79717d24755SJustin T. Gibbs 	"DFF1",
79817d24755SJustin T. Gibbs 	"SG",
79917d24755SJustin T. Gibbs 	"CMC",
80017d24755SJustin T. Gibbs 	"OVLY",
80117d24755SJustin T. Gibbs 	"NONE",
80217d24755SJustin T. Gibbs 	"MSI",
80317d24755SJustin T. Gibbs 	"TARG"
80417d24755SJustin T. Gibbs };
80517d24755SJustin T. Gibbs 
80617d24755SJustin T. Gibbs static const char *split_status_strings[] =
80717d24755SJustin T. Gibbs {
808acae33b0SJustin T. Gibbs 	"%s: Received split response in %s.\n",
80917d24755SJustin T. Gibbs 	"%s: Received split completion error message in %s\n",
81017d24755SJustin T. Gibbs 	"%s: Receive overrun in %s\n",
81117d24755SJustin T. Gibbs 	"%s: Count not complete in %s\n",
81217d24755SJustin T. Gibbs 	"%s: Split completion data bucket in %s\n",
81317d24755SJustin T. Gibbs 	"%s: Split completion address error in %s\n",
81417d24755SJustin T. Gibbs 	"%s: Split completion byte count error in %s\n",
815acae33b0SJustin T. Gibbs 	"%s: Signaled Target-abort to early terminate a split in %s\n"
81617d24755SJustin T. Gibbs };
81717d24755SJustin T. Gibbs 
81817d24755SJustin T. Gibbs static const char *pci_status_strings[] =
81917d24755SJustin T. Gibbs {
82017d24755SJustin T. Gibbs 	"%s: Data Parity Error has been reported via PERR# in %s\n",
82117d24755SJustin T. Gibbs 	"%s: Target initial wait state error in %s\n",
82217d24755SJustin T. Gibbs 	"%s: Split completion read data parity error in %s\n",
82317d24755SJustin T. Gibbs 	"%s: Split completion address attribute parity error in %s\n",
82417d24755SJustin T. Gibbs 	"%s: Received a Target Abort in %s\n",
82517d24755SJustin T. Gibbs 	"%s: Received a Master Abort in %s\n",
82617d24755SJustin T. Gibbs 	"%s: Signal System Error Detected in %s\n",
82717d24755SJustin T. Gibbs 	"%s: Address or Write Phase Parity Error Detected in %s.\n"
82817d24755SJustin T. Gibbs };
82917d24755SJustin T. Gibbs 
83017d24755SJustin T. Gibbs void
83117d24755SJustin T. Gibbs ahd_pci_intr(struct ahd_softc *ahd)
83217d24755SJustin T. Gibbs {
83317d24755SJustin T. Gibbs 	uint8_t		pci_status[8];
83417d24755SJustin T. Gibbs 	ahd_mode_state	saved_modes;
83517d24755SJustin T. Gibbs 	u_int		pci_status1;
83617d24755SJustin T. Gibbs 	u_int		intstat;
83717d24755SJustin T. Gibbs 	u_int		i;
83817d24755SJustin T. Gibbs 	u_int		reg;
83917d24755SJustin T. Gibbs 
84017d24755SJustin T. Gibbs 	intstat = ahd_inb(ahd, INTSTAT);
84117d24755SJustin T. Gibbs 
84217d24755SJustin T. Gibbs 	if ((intstat & SPLTINT) != 0)
84317d24755SJustin T. Gibbs 		ahd_pci_split_intr(ahd, intstat);
84417d24755SJustin T. Gibbs 
84517d24755SJustin T. Gibbs 	if ((intstat & PCIINT) == 0)
84617d24755SJustin T. Gibbs 		return;
84717d24755SJustin T. Gibbs 
84817d24755SJustin T. Gibbs 	printf("%s: PCI error Interrupt\n", ahd_name(ahd));
84917d24755SJustin T. Gibbs 	saved_modes = ahd_save_modes(ahd);
85017d24755SJustin T. Gibbs 	ahd_dump_card_state(ahd);
85117d24755SJustin T. Gibbs 	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
85217d24755SJustin T. Gibbs 	for (i = 0, reg = DF0PCISTAT; i < 8; i++, reg++) {
85317d24755SJustin T. Gibbs 
85417d24755SJustin T. Gibbs 		if (i == 5)
85517d24755SJustin T. Gibbs 			continue;
85617d24755SJustin T. Gibbs 		pci_status[i] = ahd_inb(ahd, reg);
857acae33b0SJustin T. Gibbs 		/* Clear latched errors.  So our interrupt deasserts. */
85817d24755SJustin T. Gibbs 		ahd_outb(ahd, reg, pci_status[i]);
85917d24755SJustin T. Gibbs 	}
86017d24755SJustin T. Gibbs 
86117d24755SJustin T. Gibbs 	for (i = 0; i < 8; i++) {
86217d24755SJustin T. Gibbs 		u_int bit;
86317d24755SJustin T. Gibbs 
86417d24755SJustin T. Gibbs 		if (i == 5)
86517d24755SJustin T. Gibbs 			continue;
86617d24755SJustin T. Gibbs 
86717d24755SJustin T. Gibbs 		for (bit = 0; bit < 8; bit++) {
86817d24755SJustin T. Gibbs 
86917d24755SJustin T. Gibbs 			if ((pci_status[i] & (0x1 << bit)) != 0) {
87017d24755SJustin T. Gibbs 				static const char *s;
87117d24755SJustin T. Gibbs 
87217d24755SJustin T. Gibbs 				s = pci_status_strings[bit];
87317d24755SJustin T. Gibbs 				if (i == 7/*TARG*/ && bit == 3)
87497cae63dSScott Long 					s = "%s: Signaled Target Abort\n";
87517d24755SJustin T. Gibbs 				printf(s, ahd_name(ahd), pci_status_source[i]);
87617d24755SJustin T. Gibbs 			}
87717d24755SJustin T. Gibbs 		}
87817d24755SJustin T. Gibbs 	}
879b3b25f2cSJustin T. Gibbs 	pci_status1 = aic_pci_read_config(ahd->dev_softc,
88017d24755SJustin T. Gibbs 					  PCIR_STATUS + 1, /*bytes*/1);
881b3b25f2cSJustin T. Gibbs 	aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
88217d24755SJustin T. Gibbs 			     pci_status1, /*bytes*/1);
88317d24755SJustin T. Gibbs 	ahd_restore_modes(ahd, saved_modes);
88497cae63dSScott Long 	ahd_outb(ahd, CLRINT, CLRPCIINT);
88517d24755SJustin T. Gibbs 	ahd_unpause(ahd);
88617d24755SJustin T. Gibbs }
88717d24755SJustin T. Gibbs 
88817d24755SJustin T. Gibbs static void
88917d24755SJustin T. Gibbs ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
89017d24755SJustin T. Gibbs {
89117d24755SJustin T. Gibbs 	uint8_t		split_status[4];
89217d24755SJustin T. Gibbs 	uint8_t		split_status1[4];
89317d24755SJustin T. Gibbs 	uint8_t		sg_split_status[2];
89417d24755SJustin T. Gibbs 	uint8_t		sg_split_status1[2];
89517d24755SJustin T. Gibbs 	ahd_mode_state	saved_modes;
89617d24755SJustin T. Gibbs 	u_int		i;
8976eb7ebfeSJohn Baldwin 	uint32_t	pcix_status;
89817d24755SJustin T. Gibbs 
89917d24755SJustin T. Gibbs 	/*
90017d24755SJustin T. Gibbs 	 * Check for splits in all modes.  Modes 0 and 1
90117d24755SJustin T. Gibbs 	 * additionally have SG engine splits to look at.
90217d24755SJustin T. Gibbs 	 */
9036eb7ebfeSJohn Baldwin 	pcix_status = aic_pci_read_config(ahd->dev_softc,
9046eb7ebfeSJohn Baldwin 	    ahd->pcix_ptr + PCIXR_STATUS, /*bytes*/ 4);
90517d24755SJustin T. Gibbs 	printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
9066eb7ebfeSJohn Baldwin 	       ahd_name(ahd), pcix_status >> 16);
90717d24755SJustin T. Gibbs 	saved_modes = ahd_save_modes(ahd);
90817d24755SJustin T. Gibbs 	for (i = 0; i < 4; i++) {
90917d24755SJustin T. Gibbs 		ahd_set_modes(ahd, i, i);
91017d24755SJustin T. Gibbs 
91117d24755SJustin T. Gibbs 		split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0);
91217d24755SJustin T. Gibbs 		split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1);
913acae33b0SJustin T. Gibbs 		/* Clear latched errors.  So our interrupt deasserts. */
91417d24755SJustin T. Gibbs 		ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]);
91517d24755SJustin T. Gibbs 		ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]);
916d7cff4abSJustin T. Gibbs 		if (i > 1)
91717d24755SJustin T. Gibbs 			continue;
91817d24755SJustin T. Gibbs 		sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0);
91917d24755SJustin T. Gibbs 		sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1);
920acae33b0SJustin T. Gibbs 		/* Clear latched errors.  So our interrupt deasserts. */
92117d24755SJustin T. Gibbs 		ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]);
92217d24755SJustin T. Gibbs 		ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]);
92317d24755SJustin T. Gibbs 	}
92417d24755SJustin T. Gibbs 
92517d24755SJustin T. Gibbs 	for (i = 0; i < 4; i++) {
92617d24755SJustin T. Gibbs 		u_int bit;
92717d24755SJustin T. Gibbs 
92817d24755SJustin T. Gibbs 		for (bit = 0; bit < 8; bit++) {
92917d24755SJustin T. Gibbs 
93017d24755SJustin T. Gibbs 			if ((split_status[i] & (0x1 << bit)) != 0) {
93117d24755SJustin T. Gibbs 				static const char *s;
93217d24755SJustin T. Gibbs 
93317d24755SJustin T. Gibbs 				s = split_status_strings[bit];
93417d24755SJustin T. Gibbs 				printf(s, ahd_name(ahd),
93517d24755SJustin T. Gibbs 				       split_status_source[i]);
93617d24755SJustin T. Gibbs 			}
93717d24755SJustin T. Gibbs 
938d7cff4abSJustin T. Gibbs 			if (i > 1)
93917d24755SJustin T. Gibbs 				continue;
94017d24755SJustin T. Gibbs 
94117d24755SJustin T. Gibbs 			if ((sg_split_status[i] & (0x1 << bit)) != 0) {
94217d24755SJustin T. Gibbs 				static const char *s;
94317d24755SJustin T. Gibbs 
94417d24755SJustin T. Gibbs 				s = split_status_strings[bit];
94517d24755SJustin T. Gibbs 				printf(s, ahd_name(ahd), "SG");
94617d24755SJustin T. Gibbs 			}
94717d24755SJustin T. Gibbs 		}
94817d24755SJustin T. Gibbs 	}
94917d24755SJustin T. Gibbs 	/*
95017d24755SJustin T. Gibbs 	 * Clear PCI-X status bits.
95117d24755SJustin T. Gibbs 	 */
9526eb7ebfeSJohn Baldwin 	aic_pci_write_config(ahd->dev_softc, ahd->pcix_ptr + PCIXR_STATUS,
9536eb7ebfeSJohn Baldwin 			     pcix_status, /*bytes*/4);
95497cae63dSScott Long 	ahd_outb(ahd, CLRINT, CLRSPLTINT);
95517d24755SJustin T. Gibbs 	ahd_restore_modes(ahd, saved_modes);
95617d24755SJustin T. Gibbs }
95717d24755SJustin T. Gibbs 
95817d24755SJustin T. Gibbs static int
959197696e9SJustin T. Gibbs ahd_aic7901_setup(struct ahd_softc *ahd)
960197696e9SJustin T. Gibbs {
961197696e9SJustin T. Gibbs 
962197696e9SJustin T. Gibbs 	ahd->chip = AHD_AIC7901;
963c8ee7177SJustin T. Gibbs 	ahd->features = AHD_AIC7901_FE;
964c8ee7177SJustin T. Gibbs 	return (ahd_aic790X_setup(ahd));
965197696e9SJustin T. Gibbs }
966197696e9SJustin T. Gibbs 
967197696e9SJustin T. Gibbs static int
9681a1fbd0bSJustin T. Gibbs ahd_aic7901A_setup(struct ahd_softc *ahd)
9691a1fbd0bSJustin T. Gibbs {
9701a1fbd0bSJustin T. Gibbs 
9711a1fbd0bSJustin T. Gibbs 	ahd->chip = AHD_AIC7901A;
972c8ee7177SJustin T. Gibbs 	ahd->features = AHD_AIC7901A_FE;
973c8ee7177SJustin T. Gibbs 	return (ahd_aic790X_setup(ahd));
9741a1fbd0bSJustin T. Gibbs }
9751a1fbd0bSJustin T. Gibbs 
976454bf169SScott Long static int
977454bf169SScott Long ahd_aic7902_setup(struct ahd_softc *ahd)
978454bf169SScott Long {
979c8ee7177SJustin T. Gibbs 	ahd->chip = AHD_AIC7902;
980c8ee7177SJustin T. Gibbs 	ahd->features = AHD_AIC7902_FE;
981c8ee7177SJustin T. Gibbs 	return (ahd_aic790X_setup(ahd));
982c8ee7177SJustin T. Gibbs }
983c8ee7177SJustin T. Gibbs 
984c8ee7177SJustin T. Gibbs static int
985c8ee7177SJustin T. Gibbs ahd_aic790X_setup(struct ahd_softc *ahd)
986c8ee7177SJustin T. Gibbs {
987b3b25f2cSJustin T. Gibbs 	aic_dev_softc_t pci;
988454bf169SScott Long 	u_int rev;
989454bf169SScott Long 
990454bf169SScott Long 	pci = ahd->dev_softc;
991b3b25f2cSJustin T. Gibbs 	rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
992454bf169SScott Long 	if (rev < ID_AIC7902_PCI_REV_A4) {
993454bf169SScott Long 		printf("%s: Unable to attach to unsupported chip revision %d\n",
994454bf169SScott Long 		       ahd_name(ahd), rev);
995b3b25f2cSJustin T. Gibbs 		aic_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2);
996454bf169SScott Long 		return (ENXIO);
997454bf169SScott Long 	}
998b3b25f2cSJustin T. Gibbs 	ahd->channel = aic_get_pci_function(pci) + 'A';
999454bf169SScott Long 	if (rev < ID_AIC7902_PCI_REV_B0) {
1000454bf169SScott Long 		/*
1001454bf169SScott Long 		 * Enable A series workarounds.
1002454bf169SScott Long 		 */
1003454bf169SScott Long 		ahd->bugs |= AHD_SENT_SCB_UPDATE_BUG|AHD_ABORT_LQI_BUG
1004454bf169SScott Long 			  |  AHD_PKT_BITBUCKET_BUG|AHD_LONG_SETIMO_BUG
1005454bf169SScott Long 			  |  AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG
1006454bf169SScott Long 			  |  AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG
1007454bf169SScott Long 			  |  AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG
10082cd3cc37SJustin T. Gibbs 			  |  AHD_PCIX_CHIPRST_BUG|AHD_PCIX_SCBRAM_RD_BUG
10092cd3cc37SJustin T. Gibbs 			  |  AHD_PKTIZED_STATUS_BUG|AHD_PKT_LUN_BUG
10102cd3cc37SJustin T. Gibbs 			  |  AHD_MDFF_WSCBPTR_BUG|AHD_REG_SLOW_SETTLE_BUG
10112cd3cc37SJustin T. Gibbs 			  |  AHD_SET_MODE_BUG|AHD_BUSFREEREV_BUG
1012d7cff4abSJustin T. Gibbs 			  |  AHD_NONPACKFIFO_BUG|AHD_PACED_NEGTABLE_BUG
1013d7cff4abSJustin T. Gibbs 			  |  AHD_FAINT_LED_BUG;
1014454bf169SScott Long 
1015454bf169SScott Long 		/*
1016594c945aSPedro F. Giffuni 		 * IO Cell parameter setup.
1017454bf169SScott Long 		 */
1018454bf169SScott Long 		AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
1019454bf169SScott Long 
1020454bf169SScott Long 		if ((ahd->flags & AHD_HP_BOARD) == 0)
1021454bf169SScott Long 			AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVA);
1022454bf169SScott Long 	} else {
1023454bf169SScott Long 		u_int devconfig1;
1024454bf169SScott Long 
1025454bf169SScott Long 		ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS
10264ddea3e2SJustin T. Gibbs 			      |  AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY;
102705899a48SJustin T. Gibbs 		ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
1028c8ee7177SJustin T. Gibbs 
1029c8ee7177SJustin T. Gibbs 		/*
1030c8ee7177SJustin T. Gibbs 		 * Some issues have been resolved in the 7901B.
1031c8ee7177SJustin T. Gibbs 		 */
1032c8ee7177SJustin T. Gibbs 		if ((ahd->features & AHD_MULTI_FUNC) != 0)
103305899a48SJustin T. Gibbs 			ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG
103405899a48SJustin T. Gibbs 				  |  AHD_BUSFREEREV_BUG;
1035454bf169SScott Long 
1036454bf169SScott Long 		/*
1037594c945aSPedro F. Giffuni 		 * IO Cell parameter setup.
1038454bf169SScott Long 		 */
1039454bf169SScott Long 		AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
1040454bf169SScott Long 		AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB);
1041454bf169SScott Long 		AHD_SET_AMPLITUDE(ahd, AHD_AMPLITUDE_DEF);
1042454bf169SScott Long 
1043454bf169SScott Long 		/*
1044454bf169SScott Long 		 * Set the PREQDIS bit for H2B which disables some workaround
1045454bf169SScott Long 		 * that doesn't work on regular PCI busses.
1046454bf169SScott Long 		 * XXX - Find out exactly what this does from the hardware
1047454bf169SScott Long 		 * 	 folks!
1048454bf169SScott Long 		 */
1049b3b25f2cSJustin T. Gibbs 		devconfig1 = aic_pci_read_config(pci, DEVCONFIG1, /*bytes*/1);
1050b3b25f2cSJustin T. Gibbs 		aic_pci_write_config(pci, DEVCONFIG1,
1051454bf169SScott Long 				     devconfig1|PREQDIS, /*bytes*/1);
1052b3b25f2cSJustin T. Gibbs 		devconfig1 = aic_pci_read_config(pci, DEVCONFIG1, /*bytes*/1);
1053454bf169SScott Long 	}
1054454bf169SScott Long 
1055454bf169SScott Long 	return (0);
1056454bf169SScott Long }
1057