xref: /freebsd/sys/dev/aic7xxx/aic79xx_pci.c (revision 454bf1693ad2014f7c1a7251d40ad6fb7400ddc1)
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