1/*	$OpenBSD: aac_pci.c,v 1.29 2024/05/24 06:02:53 jsg Exp $	*/
2
3/*-
4 * Copyright (c) 2000 Michael Smith
5 * Copyright (c) 2000 BSDi
6 * Copyright (c) 2000 Niklas Hallqvist
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 *	$FreeBSD: /c/ncvs/src/sys/dev/aac/aac_pci.c,v 1.1 2000/09/13 03:20:34 msmith Exp $
31 */
32
33/*
34 * This driver would not have rewritten for OpenBSD if it was not for the
35 * hardware donation from Nocom.  I want to thank them for their support.
36 * Of course, credit should go to Mike Smith for the original work he did
37 * in the FreeBSD driver where I found lots of inspiration.
38 * - Niklas Hallqvist
39 */
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/device.h>
44#include <sys/queue.h>
45#include <sys/rwlock.h>
46
47#include <machine/bus.h>
48#include <machine/intr.h>
49
50#include <scsi/scsi_all.h>
51#include <scsi/scsiconf.h>
52
53#include <dev/pci/pcidevs.h>
54#include <dev/pci/pcireg.h>
55#include <dev/pci/pcivar.h>
56
57#include <dev/ic/aacreg.h>
58#include <dev/ic/aacvar.h>
59
60int	aac_pci_probe(struct device *, void *, void *);
61void	aac_pci_attach(struct device *, struct device *, void *);
62
63/* Adaptec */
64#define PCI_PRODUCT_ADP2_AACASR2200S   0x0285
65#define PCI_PRODUCT_ADP2_AACASR2120S   0x0286
66#define PCI_PRODUCT_ADP2_AACADPSATA2C  0x0289
67#define PCI_PRODUCT_ADP2_AACASR2230S   0x028c
68#define PCI_PRODUCT_ADP2_AACASR2130S   0x028d
69#define PCI_PRODUCT_ADP2_AACADPSATA4C  0x0290
70#define PCI_PRODUCT_ADP2_AACADPSATA6C  0x0291
71#define PCI_PRODUCT_ADP2_AACADPSATA8C  0x0292
72#define PCI_PRODUCT_ADP2_AACADPSATA16C 0x0293
73
74/* Dell */
75#define PCI_PRODUCT_ADP2_AACCERCSATA6C 0x0291
76#define PCI_PRODUCT_ADP2_AACPERC320DC  0x0287
77
78/* IBM */
79#define PCI_PRODUCT_ADP2_AACSERVERAID8I 0x02f2
80#define PCI_PRODUCT_ADP2_AACSERVERAID8I_2 0x0312
81#define PCI_PRODUCT_ADP2_AACSERVERAID8K 0x9580
82#define PCI_PRODUCT_ADP2_AACSERVERAID8S 0x034d
83
84struct aac_sub_ident {
85	u_int16_t subvendor;
86	u_int16_t subdevice;
87	char *desc;
88} aac_sub_identifiers[] = {
89	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACADPSATA2C, "Adaptec 1210SA" }, /* guess */
90	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2130S, "Adaptec 2130S" },
91	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2230S, "Adaptec 2230S" },
92	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACADPSATA4C, "Adaptec 2410SA" },
93	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACADPSATA6C, "Adaptec 2610SA" },
94	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACADPSATA8C, "Adaptec 2810SA" }, /* guess */
95	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACADPSATA16C, "Adaptec 21610SA" }, /* guess */
96	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2120S, "Adaptec 2120S" },
97	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2200S, "Adaptec 2200S" },
98	{ PCI_VENDOR_DELL, PCI_PRODUCT_ADP2_AACCERCSATA6C, "Dell CERC-SATA" },
99	{ PCI_VENDOR_DELL, PCI_PRODUCT_ADP2_AACPERC320DC, "Dell PERC 320/DC" },
100	{ PCI_VENDOR_IBM, PCI_PRODUCT_ADP2_AACSERVERAID8I, "IBM ServeRAID-8i" },
101	{ PCI_VENDOR_IBM, PCI_PRODUCT_ADP2_AACSERVERAID8I_2, "IBM ServeRAID-8i" },
102	{ PCI_VENDOR_IBM, PCI_PRODUCT_ADP2_AACSERVERAID8K, "IBM ServeRAID-8k" },
103	{ PCI_VENDOR_IBM, PCI_PRODUCT_ADP2_AACSERVERAID8S, "IBM ServeRAID-8s" },
104	{ 0, 0, "" }
105};
106
107struct aac_ident {
108	u_int16_t vendor;
109	u_int16_t device;
110	u_int16_t subvendor;
111	u_int16_t subdevice;
112	int	hwif;
113} aac_identifiers[] = {
114	/* Dell PERC 2/Si models */
115	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_2SI, PCI_VENDOR_DELL,
116	    PCI_PRODUCT_DELL_PERC_2SI, AAC_HWIF_I960RX },
117	/* Dell PERC 3/Di models */
118	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI, PCI_VENDOR_DELL,
119	    PCI_PRODUCT_DELL_PERC_3DI, AAC_HWIF_I960RX },
120	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI, PCI_VENDOR_DELL,
121	    PCI_PRODUCT_DELL_PERC_3DI_3, AAC_HWIF_I960RX },
122	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI, PCI_VENDOR_DELL,
123	    PCI_PRODUCT_DELL_PERC_3DI_SUB2, AAC_HWIF_I960RX },
124	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI, PCI_VENDOR_DELL,
125	    PCI_PRODUCT_DELL_PERC_3DI_SUB3, AAC_HWIF_I960RX },
126	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI_3, PCI_VENDOR_DELL,
127	    PCI_PRODUCT_DELL_PERC_3DI_3_SUB, AAC_HWIF_I960RX },
128	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI_3, PCI_VENDOR_DELL,
129	    PCI_PRODUCT_DELL_PERC_3DI_3_SUB2, AAC_HWIF_I960RX },
130	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3DI_3, PCI_VENDOR_DELL,
131	    PCI_PRODUCT_DELL_PERC_3DI_3_SUB3, AAC_HWIF_I960RX },
132	/* Dell PERC 3/Si models */
133	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3SI, PCI_VENDOR_DELL,
134	    PCI_PRODUCT_DELL_PERC_3SI, AAC_HWIF_I960RX },
135	{ PCI_VENDOR_DELL, PCI_PRODUCT_DELL_PERC_3SI_2, PCI_VENDOR_DELL,
136	    PCI_PRODUCT_DELL_PERC_3SI_2_SUB, AAC_HWIF_I960RX },
137	/* Adaptec SATA RAID 2 channel XXX guess */
138	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
139	    PCI_PRODUCT_ADP2_AACADPSATA2C, AAC_HWIF_I960RX },
140	/* Adaptec SATA RAID 4 channel */
141	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
142	    PCI_PRODUCT_ADP2_AACADPSATA4C, AAC_HWIF_I960RX },
143	/* Adaptec SATA RAID 6 channel XXX guess */
144	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
145	    PCI_PRODUCT_ADP2_AACADPSATA6C, AAC_HWIF_I960RX },
146	/* Adaptec SATA RAID 8 channel XXX guess */
147	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
148	    PCI_PRODUCT_ADP2_AACADPSATA8C, AAC_HWIF_I960RX },
149	/* Adaptec SATA RAID 16 channel XXX guess */
150	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
151	    PCI_PRODUCT_ADP2_AACADPSATA16C, AAC_HWIF_I960RX },
152	/* Dell CERC-SATA */
153	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_DELL,
154	    PCI_PRODUCT_ADP2_AACCERCSATA6C, AAC_HWIF_I960RX },
155	/* Dell PERC 320/DC */
156	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_DELL,
157	    PCI_PRODUCT_ADP2_AACPERC320DC, AAC_HWIF_I960RX },
158	/* Adaptec ADP-2622 */
159	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AAC2622, PCI_VENDOR_ADP2,
160	    PCI_PRODUCT_ADP2_AAC2622, AAC_HWIF_I960RX },
161	/* Adaptec ADP-364 */
162	{ PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21554, PCI_VENDOR_ADP2,
163	    PCI_PRODUCT_ADP2_AAC364, AAC_HWIF_STRONGARM },
164	/* Adaptec ADP-3642 */
165	{ PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21554, PCI_VENDOR_ADP2,
166	    PCI_PRODUCT_ADP2_AAC3642, AAC_HWIF_STRONGARM },
167	/* Dell PERC 2/QC */
168	{ PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21554, PCI_VENDOR_ADP2,
169	    PCI_PRODUCT_ADP2_PERC_2QC, AAC_HWIF_STRONGARM },
170	/* HP NetRAID-4M */
171	{ PCI_VENDOR_DEC, PCI_PRODUCT_DEC_21554, PCI_VENDOR_HP,
172	    PCI_PRODUCT_HP_NETRAID_4M, AAC_HWIF_STRONGARM },
173	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
174	    PCI_PRODUCT_ADP2_ASR2120S, AAC_HWIF_I960RX },
175	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_ASR2200S, PCI_VENDOR_ADP2,
176	    PCI_PRODUCT_ADP2_ASR2200S, AAC_HWIF_I960RX },
177	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2120S, PCI_VENDOR_ADP2,
178	    PCI_PRODUCT_ADP2_AACASR2130S, AAC_HWIF_RKT },
179	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2120S, PCI_VENDOR_ADP2,
180	    PCI_PRODUCT_ADP2_AACASR2230S, AAC_HWIF_RKT },
181	/* IBM ServeRAID-8i/8k/8s */
182	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2200S, PCI_VENDOR_IBM,
183	    PCI_PRODUCT_ADP2_AACSERVERAID8I, AAC_HWIF_I960RX },
184	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2200S, PCI_VENDOR_IBM,
185	    PCI_PRODUCT_ADP2_AACSERVERAID8I_2, AAC_HWIF_I960RX },
186	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2120S, PCI_VENDOR_IBM,
187	    PCI_PRODUCT_ADP2_AACSERVERAID8K, AAC_HWIF_RKT },
188	{ PCI_VENDOR_ADP2, PCI_PRODUCT_ADP2_AACASR2200S, PCI_VENDOR_IBM,
189	    PCI_PRODUCT_ADP2_AACSERVERAID8S, AAC_HWIF_I960RX },
190	{ 0, 0, 0, 0 }
191};
192
193const struct cfattach aac_pci_ca = {
194	sizeof (struct aac_softc), aac_pci_probe, aac_pci_attach
195};
196
197/*
198 * Determine whether this is one of our supported adapters.
199 */
200int
201aac_pci_probe(struct device *parent, void *match, void *aux)
202{
203        struct pci_attach_args *pa = aux;
204	struct aac_ident *m;
205	u_int32_t subsysid;
206
207	for (m = aac_identifiers; m->vendor != 0; m++)
208		if (m->vendor == PCI_VENDOR(pa->pa_id) &&
209		    m->device == PCI_PRODUCT(pa->pa_id)) {
210			subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag,
211			    PCI_SUBSYS_ID_REG);
212			if (m->subvendor == PCI_VENDOR(subsysid) &&
213			    m->subdevice == PCI_PRODUCT(subsysid))
214				return (1);
215		}
216	return (0);
217}
218
219void
220aac_pci_attach(struct device *parent, struct device *self, void *aux)
221{
222	struct pci_attach_args *pa = aux;
223	pci_chipset_tag_t pc = pa->pa_pc;
224	struct aac_softc *sc = (void *)self;
225	bus_addr_t membase;
226	bus_size_t memsize;
227	pci_intr_handle_t ih;
228	const char *intrstr;
229	int state = 0;
230	struct aac_ident *m;
231	struct aac_sub_ident *subid;
232	u_int32_t subsysid;
233	pcireg_t memtype;
234
235	printf(": ");
236	subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
237	if ((PCI_VENDOR(pa->pa_id) != PCI_VENDOR(subsysid)) ||
238	    (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT(subsysid))) {
239		for (subid = aac_sub_identifiers; subid->subvendor != 0;
240		    subid++) {
241			if (subid->subvendor == PCI_VENDOR(subsysid) &&
242			    subid->subdevice == PCI_PRODUCT(subsysid)) {
243				printf("%s ", subid->desc);
244				break;
245			}
246		}
247	}
248
249	/*
250	 * Map control/status registers.
251	 */
252	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
253	if (pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &sc->aac_memt,
254	    &sc->aac_memh, &membase, &memsize, AAC_REGSIZE)) {
255		printf("can't find mem space\n");
256		goto bail_out;
257	}
258	state++;
259
260	if (pci_intr_map(pa, &ih)) {
261		printf("couldn't map interrupt\n");
262		goto bail_out;
263	}
264	intrstr = pci_intr_string(pc, ih);
265	sc->aac_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc,
266	    sc->aac_dev.dv_xname);
267	if (sc->aac_ih == NULL) {
268		printf("couldn't establish interrupt");
269		if (intrstr != NULL)
270			printf(" at %s", intrstr);
271		printf("\n");
272		goto bail_out;
273	}
274	state++;
275	if (intrstr != NULL)
276		printf("%s\n", intrstr);
277
278	sc->aac_dmat = pa->pa_dmat;
279
280	for (m = aac_identifiers; m->vendor != 0; m++)
281		if (m->vendor == PCI_VENDOR(pa->pa_id) &&
282		    m->device == PCI_PRODUCT(pa->pa_id)) {
283			if (m->subvendor == PCI_VENDOR(subsysid) &&
284			    m->subdevice == PCI_PRODUCT(subsysid)) {
285				sc->aac_hwif = m->hwif;
286				switch(sc->aac_hwif) {
287				case AAC_HWIF_I960RX:
288					AAC_DPRINTF(AAC_D_MISC,
289					    ("set hardware up for i960Rx"));
290					sc->aac_if = aac_rx_interface;
291					break;
292				case AAC_HWIF_STRONGARM:
293					AAC_DPRINTF(AAC_D_MISC,
294					    ("set hardware up for StrongARM"));
295					sc->aac_if = aac_sa_interface;
296					break;
297				case AAC_HWIF_FALCON:
298					AAC_DPRINTF(AAC_D_MISC,
299					   ("set hardware up for Falcon/PPC"));
300					sc->aac_if = aac_fa_interface;
301					break;
302				case AAC_HWIF_RKT:
303					AAC_DPRINTF(AAC_D_MISC,
304					   ("set hardware up for Rocket/MIPS"));
305					sc->aac_if = aac_rkt_interface;
306					break;
307				default:
308					sc->aac_hwif = AAC_HWIF_UNKNOWN;
309					break;
310				}
311				break;
312			}
313		}
314
315	if (aac_attach(sc))
316		goto bail_out;
317
318	return;
319
320 bail_out:
321	if (state > 1)
322		pci_intr_disestablish(pc, sc->aac_ih);
323	if (state > 0)
324		bus_space_unmap(sc->aac_memt, sc->aac_memh, memsize);
325	return;
326}
327