1/*	$NetBSD: ciss_pci.c,v 1.8 2009/05/12 08:23:00 cegger Exp $	*/
2/*	$OpenBSD: ciss_pci.c,v 1.9 2005/12/13 15:56:01 brad Exp $	*/
3
4/*
5 * Copyright (c) 2005 Michael Shalayeff
6 * All rights reserved.
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
17 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
18 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/cdefs.h>
22__KERNEL_RCSID(0, "$NetBSD: ciss_pci.c,v 1.8 2009/05/12 08:23:00 cegger Exp $");
23
24#include <sys/param.h>
25#include <sys/systm.h>
26#include <sys/kernel.h>
27#include <sys/malloc.h>
28#include <sys/device.h>
29
30#include <dev/pci/pcidevs.h>
31#include <dev/pci/pcivar.h>
32
33#include <sys/bus.h>
34
35#include <dev/scsipi/scsipi_all.h>
36#include <dev/scsipi/scsipi_disk.h>
37#include <dev/scsipi/scsipiconf.h>
38
39#include <dev/ic/cissreg.h>
40#include <dev/ic/cissvar.h>
41
42#define	CISS_BAR	0x10
43
44int	ciss_pci_match(device_t, cfdata_t, void *);
45void	ciss_pci_attach(device_t, device_t, void *);
46
47CFATTACH_DECL(ciss_pci, sizeof(struct ciss_softc),
48	ciss_pci_match, ciss_pci_attach, NULL, NULL);
49
50const struct {
51	int vendor;
52	int product;
53	const char *name;
54} ciss_pci_devices[] = {
55	{
56		PCI_VENDOR_COMPAQ,
57		PCI_PRODUCT_COMPAQ_CSA532,
58		"Compaq Smart Array 532"
59	},
60	{
61		PCI_VENDOR_COMPAQ,
62		PCI_PRODUCT_COMPAQ_CSA5300,
63		"Compaq Smart Array 5300 V1"
64	},
65	{
66		PCI_VENDOR_COMPAQ,
67		PCI_PRODUCT_COMPAQ_CSA5300_2,
68		"Compaq Smart Array 5300 V2"
69	},
70	{
71		PCI_VENDOR_COMPAQ,
72		PCI_PRODUCT_COMPAQ_CSA5312,
73		"Compaq Smart Array 5312"
74	},
75	{
76		PCI_VENDOR_COMPAQ,
77		PCI_PRODUCT_COMPAQ_CSA5i,
78		"Compaq Smart Array 5i"
79	},
80	{
81		PCI_VENDOR_COMPAQ,
82		PCI_PRODUCT_COMPAQ_CSA5i_2,
83		"Compaq Smart Array 5i V2"
84	},
85	{
86		PCI_VENDOR_COMPAQ,
87		PCI_PRODUCT_COMPAQ_CSA6i,
88		"Compaq Smart Array 6i"
89	},
90	{
91		PCI_VENDOR_COMPAQ,
92		PCI_PRODUCT_COMPAQ_CSA641,
93		"Compaq Smart Array 641"
94	},
95	{
96		PCI_VENDOR_COMPAQ,
97		PCI_PRODUCT_COMPAQ_CSA642,
98		"Compaq Smart Array 642"
99	},
100	{
101		PCI_VENDOR_COMPAQ,
102		PCI_PRODUCT_COMPAQ_CSA6400,
103		"Compaq Smart Array 6400"
104	},
105	{
106		PCI_VENDOR_COMPAQ,
107		PCI_PRODUCT_COMPAQ_CSA6400EM,
108		"Compaq Smart Array 6400EM"
109	},
110	{
111		PCI_VENDOR_COMPAQ,
112		PCI_PRODUCT_COMPAQ_CSA6422,
113		"Compaq Smart Array 6422"
114	},
115	{
116		PCI_VENDOR_COMPAQ,
117		PCI_PRODUCT_COMPAQ_CSA64XX,
118		"Compaq Smart Array 64XX"
119	},
120	{
121		PCI_VENDOR_HP,
122		PCI_PRODUCT_HP_HPSAE200,
123		"Smart Array E200"
124	},
125	{
126		PCI_VENDOR_HP,
127		PCI_PRODUCT_HP_HPSAE200I_1,
128		"HP Smart Array E200I-1"
129	},
130	{
131		PCI_VENDOR_HP,
132		PCI_PRODUCT_HP_HPSAE200I_2,
133		"HP Smart Array E200I-2"
134	},
135	{
136		PCI_VENDOR_HP,
137		PCI_PRODUCT_HP_HPSAE200I_3,
138		"HP Smart Array E200I-3"
139	},
140	{
141		PCI_VENDOR_HP,
142		PCI_PRODUCT_HP_HPSAP600,
143		"HP Smart Array P600"
144	},
145	{
146		PCI_VENDOR_HP,
147		PCI_PRODUCT_HP_HPSAP800,
148		"HP Smart Array P800"
149	},
150	{
151		PCI_VENDOR_HP,
152		PCI_PRODUCT_HP_HPSAV100,
153		"HP Smart Array V100"
154	},
155	{
156		PCI_VENDOR_HP,
157		PCI_PRODUCT_HP_HPSA_1,
158		"HP Smart Array 1"
159	},
160	{
161		PCI_VENDOR_HP,
162		PCI_PRODUCT_HP_HPSA_2,
163		"HP Smart Array 2"
164	},
165	{
166		PCI_VENDOR_HP,
167		PCI_PRODUCT_HP_HPSA_3,
168		"HP Smart Array 3"
169	},
170	{
171		PCI_VENDOR_HP,
172		PCI_PRODUCT_HP_HPSA_4,
173		"HP Smart Array 4"
174	},
175	{
176		PCI_VENDOR_HP,
177		PCI_PRODUCT_HP_HPSA_5,
178		"HP Smart Array 5"
179	},
180	{
181		PCI_VENDOR_HP,
182		PCI_PRODUCT_HP_HPSA_6,
183		"HP Smart Array 6"
184	},
185	{
186		PCI_VENDOR_HP,
187		PCI_PRODUCT_HP_HPSA_7,
188		"HP Smart Array 7"
189	},
190	{
191		PCI_VENDOR_HP,
192		PCI_PRODUCT_HP_HPSA_8,
193		"HP Smart Array 8"
194	},
195	{
196		PCI_VENDOR_HP,
197		PCI_PRODUCT_HP_HPSA_9,
198		"HP Smart Array 9"
199	},
200	{
201		PCI_VENDOR_HP,
202		PCI_PRODUCT_HP_HPSA_10,
203		"HP Smart Array 10"
204	},
205	{
206		PCI_VENDOR_HP,
207		PCI_PRODUCT_HP_HPSA_11,
208		"HP Smart Array 11"
209	},
210	{
211		PCI_VENDOR_HP,
212		PCI_PRODUCT_HP_HPSA_12,
213		"HP Smart Array 12"
214	},
215	{
216		PCI_VENDOR_HP,
217		PCI_PRODUCT_HP_HPSA_13,
218		"HP Smart Array 13"
219	},
220	{
221		0,
222		0,
223		NULL
224	}
225};
226
227int
228ciss_pci_match(device_t parent, cfdata_t match, void *aux)
229{
230	struct pci_attach_args *pa = aux;
231	pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
232	int i;
233
234	for (i = 0; ciss_pci_devices[i].vendor; i++)
235	{
236		if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor &&
237		     PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) ||
238		    (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor &&
239		     PCI_PRODUCT(reg) == ciss_pci_devices[i].product))
240			return 1;
241	}
242
243	return 0;
244}
245
246void
247ciss_pci_attach(device_t parent, device_t self, void *aux)
248{
249	struct ciss_softc *sc = device_private(self);
250	struct pci_attach_args *pa = aux;
251	bus_size_t size, cfgsz;
252	pci_intr_handle_t ih;
253	const char *intrstr;
254	int cfg_bar, memtype;
255	pcireg_t reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
256	int i;
257
258	for (i = 0; ciss_pci_devices[i].vendor; i++)
259	{
260		if ((PCI_VENDOR(pa->pa_id) == ciss_pci_devices[i].vendor &&
261		     PCI_PRODUCT(pa->pa_id) == ciss_pci_devices[i].product) ||
262		    (PCI_VENDOR(reg) == ciss_pci_devices[i].vendor &&
263		     PCI_PRODUCT(reg) == ciss_pci_devices[i].product))
264		{
265			printf(": %s\n", ciss_pci_devices[i].name);
266			break;
267		}
268	}
269
270	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CISS_BAR);
271	if (memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT) &&
272	    memtype != (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) {
273		printf(": wrong BAR type\n");
274		return;
275	}
276	if (pci_mapreg_map(pa, CISS_BAR, memtype, 0,
277	    &sc->sc_iot, &sc->sc_ioh, NULL, &size)) {
278		printf(": can't map controller i/o space\n");
279		return;
280	}
281	sc->sc_dmat = pa->pa_dmat;
282
283	sc->iem = CISS_READYENA;
284	reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
285	if (PCI_VENDOR(reg) == PCI_VENDOR_COMPAQ &&
286	    (PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5i ||
287	     PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA532 ||
288	     PCI_PRODUCT(reg) == PCI_PRODUCT_COMPAQ_CSA5312))
289		sc->iem = CISS_READYENAB;
290
291	cfg_bar = bus_space_read_2(sc->sc_iot, sc->sc_ioh, CISS_CFG_BAR);
292	sc->cfgoff = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_CFG_OFF);
293	if (cfg_bar != CISS_BAR) {
294		if (pci_mapreg_map(pa, cfg_bar, PCI_MAPREG_TYPE_MEM, 0,
295		    NULL, &sc->cfg_ioh, NULL, &cfgsz)) {
296			printf(": can't map controller config space\n");
297			bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
298			return;
299		}
300	} else {
301		sc->cfg_ioh = sc->sc_ioh;
302		cfgsz = size;
303	}
304
305	if (sc->cfgoff + sizeof(struct ciss_config) > cfgsz) {
306		printf(": unfit config space\n");
307		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
308		if (cfg_bar != CISS_BAR)
309			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
310		return;
311	}
312
313	/* disable interrupts until ready */
314	bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR,
315	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) | sc->iem);
316
317	if (pci_intr_map(pa, &ih)) {
318		printf(": can't map interrupt\n");
319		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
320		if (cfg_bar != CISS_BAR)
321			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
322		return;
323	}
324	intrstr = pci_intr_string(pa->pa_pc, ih);
325	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ciss_intr, sc);
326	if (!sc->sc_ih) {
327		aprint_error_dev(&sc->sc_dev, "can't establish interrupt");
328		if (intrstr)
329			aprint_error(" at %s", intrstr);
330		aprint_error("\n");
331		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
332		if (cfg_bar != CISS_BAR)
333			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
334	}
335
336	printf("%s: interrupting at %s\n%s", device_xname(&sc->sc_dev), intrstr,
337	       device_xname(&sc->sc_dev));
338
339	if (ciss_attach(sc)) {
340		pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
341		sc->sc_ih = NULL;
342		bus_space_unmap(sc->sc_iot, sc->sc_ioh, size);
343		if (cfg_bar != CISS_BAR)
344			bus_space_unmap(sc->sc_iot, sc->cfg_ioh, cfgsz);
345		return;
346	}
347
348	/* enable interrupts now */
349	bus_space_write_4(sc->sc_iot, sc->sc_ioh, CISS_IMR,
350	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, CISS_IMR) & ~sc->iem);
351}
352