aac_pci.c revision 1.16.8.1 1 /* $NetBSD: aac_pci.c,v 1.16.8.1 2006/09/03 15:24:21 yamt Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*-
40 * Copyright (c) 2000 Michael Smith
41 * Copyright (c) 2000 BSDi
42 * Copyright (c) 2000 Niklas Hallqvist
43 * All rights reserved.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 * notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 * notice, this list of conditions and the following disclaimer in the
52 * documentation and/or other materials provided with the distribution.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * from FreeBSD: aac_pci.c,v 1.1 2000/09/13 03:20:34 msmith Exp
67 * via OpenBSD: aac_pci.c,v 1.7 2002/03/14 01:26:58 millert Exp
68 */
69
70 /*
71 * PCI front-end for the `aac' driver.
72 */
73
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: aac_pci.c,v 1.16.8.1 2006/09/03 15:24:21 yamt Exp $");
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/device.h>
80 #include <sys/kernel.h>
81 #include <sys/malloc.h>
82 #include <sys/queue.h>
83
84 #include <machine/bus.h>
85 #include <machine/endian.h>
86 #include <machine/intr.h>
87
88 #include <dev/pci/pcidevs.h>
89 #include <dev/pci/pcireg.h>
90 #include <dev/pci/pcivar.h>
91
92 #include <dev/ic/aacreg.h>
93 #include <dev/ic/aacvar.h>
94
95 /* i960Rx interface */
96 static int aac_rx_get_fwstatus(struct aac_softc *);
97 static void aac_rx_qnotify(struct aac_softc *, int);
98 static int aac_rx_get_istatus(struct aac_softc *);
99 static void aac_rx_clear_istatus(struct aac_softc *, int);
100 static void aac_rx_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t,
101 u_int32_t, u_int32_t, u_int32_t);
102 static uint32_t aac_rx_get_mailbox(struct aac_softc *, int);
103 static void aac_rx_set_interrupts(struct aac_softc *, int);
104
105 /* StrongARM interface */
106 static int aac_sa_get_fwstatus(struct aac_softc *);
107 static void aac_sa_qnotify(struct aac_softc *, int);
108 static int aac_sa_get_istatus(struct aac_softc *);
109 static void aac_sa_clear_istatus(struct aac_softc *, int);
110 static void aac_sa_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t,
111 u_int32_t, u_int32_t, u_int32_t);
112 static uint32_t aac_sa_get_mailbox(struct aac_softc *, int);
113 static void aac_sa_set_interrupts(struct aac_softc *, int);
114
115 static const struct aac_interface aac_rx_interface = {
116 aac_rx_get_fwstatus,
117 aac_rx_qnotify,
118 aac_rx_get_istatus,
119 aac_rx_clear_istatus,
120 aac_rx_set_mailbox,
121 aac_rx_get_mailbox,
122 aac_rx_set_interrupts
123 };
124
125 static const struct aac_interface aac_sa_interface = {
126 aac_sa_get_fwstatus,
127 aac_sa_qnotify,
128 aac_sa_get_istatus,
129 aac_sa_clear_istatus,
130 aac_sa_set_mailbox,
131 aac_sa_get_mailbox,
132 aac_sa_set_interrupts
133 };
134
135 static struct aac_ident {
136 u_short vendor;
137 u_short device;
138 u_short subvendor;
139 u_short subdevice;
140 u_short hwif;
141 u_short quirks;
142 const char *prodstr;
143 } const aac_ident[] = {
144 {
145 PCI_VENDOR_DELL,
146 PCI_PRODUCT_DELL_PERC_2SI,
147 PCI_VENDOR_DELL,
148 PCI_PRODUCT_DELL_PERC_2SI,
149 AAC_HWIF_I960RX,
150 0,
151 "Dell PERC 2/Si"
152 },
153 {
154 PCI_VENDOR_DELL,
155 PCI_PRODUCT_DELL_PERC_3DI,
156 PCI_VENDOR_DELL,
157 PCI_PRODUCT_DELL_PERC_3DI,
158 AAC_HWIF_I960RX,
159 0,
160 "Dell PERC 3/Di"
161 },
162 {
163 PCI_VENDOR_DELL,
164 PCI_PRODUCT_DELL_PERC_3DI,
165 PCI_VENDOR_DELL,
166 PCI_PRODUCT_DELL_PERC_3DI_SUB2,
167 AAC_HWIF_I960RX,
168 0,
169 "Dell PERC 3/Di"
170 },
171 {
172 PCI_VENDOR_DELL,
173 PCI_PRODUCT_DELL_PERC_3DI,
174 PCI_VENDOR_DELL,
175 PCI_PRODUCT_DELL_PERC_3DI_SUB3,
176 AAC_HWIF_I960RX,
177 0,
178 "Dell PERC 3/Di"
179 },
180 {
181 PCI_VENDOR_DELL,
182 PCI_PRODUCT_DELL_PERC_3DI_2,
183 PCI_VENDOR_DELL,
184 PCI_PRODUCT_DELL_PERC_3DI_2_SUB,
185 AAC_HWIF_I960RX,
186 0,
187 "Dell PERC 3/Di"
188 },
189 {
190 PCI_VENDOR_DELL,
191 PCI_PRODUCT_DELL_PERC_3DI_3,
192 PCI_VENDOR_DELL,
193 PCI_PRODUCT_DELL_PERC_3DI_3_SUB,
194 AAC_HWIF_I960RX,
195 0,
196 "Dell PERC 3/Di"
197 },
198 {
199 PCI_VENDOR_DELL,
200 PCI_PRODUCT_DELL_PERC_3DI_3,
201 PCI_VENDOR_DELL,
202 PCI_PRODUCT_DELL_PERC_3DI_3_SUB2,
203 AAC_HWIF_I960RX,
204 0,
205 "Dell PERC 3/Di"
206 },
207 {
208 PCI_VENDOR_DELL,
209 PCI_PRODUCT_DELL_PERC_3DI_3,
210 PCI_VENDOR_DELL,
211 PCI_PRODUCT_DELL_PERC_3DI_3_SUB3,
212 AAC_HWIF_I960RX,
213 0,
214 "Dell PERC 3/Di"
215 },
216 {
217 PCI_VENDOR_DELL,
218 PCI_PRODUCT_DELL_PERC_3SI,
219 PCI_VENDOR_DELL,
220 PCI_PRODUCT_DELL_PERC_3SI,
221 AAC_HWIF_I960RX,
222 0,
223 "Dell PERC 3/Si"
224 },
225 {
226 PCI_VENDOR_DELL,
227 PCI_PRODUCT_DELL_PERC_3SI_2,
228 PCI_VENDOR_DELL,
229 PCI_PRODUCT_DELL_PERC_3SI_2_SUB,
230 AAC_HWIF_I960RX,
231 0,
232 "Dell PERC 3/Si"
233 },
234 {
235 PCI_VENDOR_ADP2,
236 PCI_PRODUCT_ADP2_ASR2200S,
237 PCI_VENDOR_DELL,
238 PCI_PRODUCT_DELL_CERC_1_5,
239 AAC_HWIF_I960RX,
240 AAC_QUIRK_NO4GB,
241 "Dell CERC SATA RAID 1.5/6ch"
242 },
243 {
244 PCI_VENDOR_ADP2,
245 PCI_PRODUCT_ADP2_AAC2622,
246 PCI_VENDOR_ADP2,
247 PCI_PRODUCT_ADP2_AAC2622,
248 AAC_HWIF_I960RX,
249 0,
250 "Adaptec ADP-2622"
251 },
252 {
253 PCI_VENDOR_ADP2,
254 PCI_PRODUCT_ADP2_ASR2200S,
255 PCI_VENDOR_ADP2,
256 PCI_PRODUCT_ADP2_ASR2200S_SUB2M,
257 AAC_HWIF_I960RX,
258 0,
259 "Adaptec ASR-2200S"
260 },
261 {
262 PCI_VENDOR_ADP2,
263 PCI_PRODUCT_ADP2_ASR2200S,
264 PCI_VENDOR_DELL,
265 PCI_PRODUCT_ADP2_ASR2200S_SUB2M,
266 AAC_HWIF_I960RX,
267 0,
268 "Dell PERC 320/DC"
269 },
270 {
271 PCI_VENDOR_ADP2,
272 PCI_PRODUCT_ADP2_ASR2200S,
273 PCI_VENDOR_ADP2,
274 PCI_PRODUCT_ADP2_ASR2200S,
275 AAC_HWIF_I960RX,
276 0,
277 "Adaptec ASR-2200S"
278 },
279 {
280 PCI_VENDOR_ADP2,
281 PCI_PRODUCT_ADP2_ASR2200S,
282 PCI_VENDOR_ADP2,
283 PCI_PRODUCT_ADP2_AAR2810SA,
284 AAC_HWIF_I960RX,
285 0,
286 "Adaptec AAR-2810SA"
287 },
288 {
289 PCI_VENDOR_ADP2,
290 PCI_PRODUCT_ADP2_ASR2200S,
291 PCI_VENDOR_ADP2,
292 PCI_PRODUCT_ADP2_ASR2120S,
293 AAC_HWIF_I960RX,
294 0,
295 "Adaptec ASR-2120S"
296 },
297 {
298 PCI_VENDOR_ADP2,
299 PCI_PRODUCT_ADP2_ASR2200S,
300 PCI_VENDOR_ADP2,
301 PCI_PRODUCT_ADP2_ASR2410SA,
302 AAC_HWIF_I960RX,
303 0,
304 "Adaptec ASR-2410SA"
305 },
306 {
307 PCI_VENDOR_DEC,
308 PCI_PRODUCT_DEC_21554,
309 PCI_VENDOR_ADP2,
310 PCI_PRODUCT_ADP2_AAC364,
311 AAC_HWIF_STRONGARM,
312 0,
313 "Adaptec AAC-364"
314 },
315 {
316 PCI_VENDOR_DEC,
317 PCI_PRODUCT_DEC_21554,
318 PCI_VENDOR_ADP2,
319 PCI_PRODUCT_ADP2_ASR5400S,
320 AAC_HWIF_STRONGARM,
321 0,
322 "Adaptec ASR-5400S"
323 },
324 {
325 PCI_VENDOR_DEC,
326 PCI_PRODUCT_DEC_21554,
327 PCI_VENDOR_ADP2,
328 PCI_PRODUCT_ADP2_PERC_2QC,
329 AAC_HWIF_STRONGARM,
330 AAC_QUIRK_PERC2QC,
331 "Dell PERC 2/QC"
332 },
333 {
334 PCI_VENDOR_DEC,
335 PCI_PRODUCT_DEC_21554,
336 PCI_VENDOR_ADP2,
337 PCI_PRODUCT_ADP2_PERC_3QC,
338 AAC_HWIF_STRONGARM,
339 0,
340 "Dell PERC 3/QC"
341 },
342 {
343 PCI_VENDOR_DEC,
344 PCI_PRODUCT_DEC_21554,
345 PCI_VENDOR_HP,
346 PCI_PRODUCT_HP_NETRAID_4M,
347 AAC_HWIF_STRONGARM,
348 0,
349 "HP NetRAID-4M"
350 },
351 };
352
353 static const struct aac_ident *
354 aac_find_ident(struct pci_attach_args *pa)
355 {
356 const struct aac_ident *m, *mm;
357 u_int32_t subsysid;
358
359 m = aac_ident;
360 mm = aac_ident + (sizeof(aac_ident) / sizeof(aac_ident[0]));
361
362 while (m < mm) {
363 if (m->vendor == PCI_VENDOR(pa->pa_id) &&
364 m->device == PCI_PRODUCT(pa->pa_id)) {
365 subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag,
366 PCI_SUBSYS_ID_REG);
367 if (m->subvendor == PCI_VENDOR(subsysid) &&
368 m->subdevice == PCI_PRODUCT(subsysid))
369 return (m);
370 }
371 m++;
372 }
373
374 return (NULL);
375 }
376
377 static int
378 aac_pci_match(struct device *parent, struct cfdata *match, void *aux)
379 {
380 struct pci_attach_args *pa;
381
382 pa = aux;
383
384 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
385 return (0);
386
387 return (aac_find_ident(pa) != NULL);
388 }
389
390 static void
391 aac_pci_attach(struct device *parent, struct device *self, void *aux)
392 {
393 struct pci_attach_args *pa;
394 pci_chipset_tag_t pc;
395 struct aac_softc *sc;
396 u_int16_t command;
397 bus_addr_t membase;
398 bus_size_t memsize;
399 pci_intr_handle_t ih;
400 const char *intrstr;
401 int state;
402 const struct aac_ident *m;
403
404 pa = aux;
405 pc = pa->pa_pc;
406 sc = (struct aac_softc *)self;
407 state = 0;
408
409 aprint_naive(": RAID controller\n");
410 aprint_normal(": ");
411
412 /*
413 * Verify that the adapter is correctly set up in PCI space.
414 */
415 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
416 command |= PCI_COMMAND_MASTER_ENABLE;
417 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
418 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
419 AAC_DPRINTF(AAC_D_MISC, ("pci command status reg 0x08x "));
420
421 if ((command & PCI_COMMAND_MASTER_ENABLE) == 0) {
422 aprint_error("can't enable bus-master feature\n");
423 goto bail_out;
424 }
425
426 if ((command & PCI_COMMAND_MEM_ENABLE) == 0) {
427 aprint_error("memory window not available\n");
428 goto bail_out;
429 }
430
431 /*
432 * Map control/status registers.
433 */
434 if (pci_mapreg_map(pa, PCI_MAPREG_START,
435 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt,
436 &sc->sc_memh, &membase, &memsize)) {
437 aprint_error("can't find mem space\n");
438 goto bail_out;
439 }
440 state++;
441
442 if (pci_intr_map(pa, &ih)) {
443 aprint_error("couldn't map interrupt\n");
444 goto bail_out;
445 }
446 intrstr = pci_intr_string(pc, ih);
447 sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc);
448 if (sc->sc_ih == NULL) {
449 aprint_error("couldn't establish interrupt");
450 if (intrstr != NULL)
451 aprint_normal(" at %s", intrstr);
452 aprint_normal("\n");
453 goto bail_out;
454 }
455 state++;
456
457 sc->sc_dmat = pa->pa_dmat;
458
459 m = aac_find_ident(pa);
460 aprint_normal("%s\n", m->prodstr);
461 if (intrstr != NULL)
462 aprint_normal("%s: interrupting at %s\n",
463 sc->sc_dv.dv_xname, intrstr);
464
465 sc->sc_hwif = m->hwif;
466 sc->sc_quirks = m->quirks;
467 switch (sc->sc_hwif) {
468 case AAC_HWIF_I960RX:
469 AAC_DPRINTF(AAC_D_MISC,
470 ("set hardware up for i960Rx"));
471 sc->sc_if = aac_rx_interface;
472 break;
473
474 case AAC_HWIF_STRONGARM:
475 AAC_DPRINTF(AAC_D_MISC,
476 ("set hardware up for StrongARM"));
477 sc->sc_if = aac_sa_interface;
478 break;
479 }
480
481 if (!aac_attach(sc))
482 return;
483
484 bail_out:
485 if (state > 1)
486 pci_intr_disestablish(pc, sc->sc_ih);
487 if (state > 0)
488 bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize);
489 }
490
491 CFATTACH_DECL(aac_pci, sizeof(struct aac_softc),
492 aac_pci_match, aac_pci_attach, NULL, NULL);
493
494 /*
495 * Read the current firmware status word.
496 */
497 static int
498 aac_sa_get_fwstatus(struct aac_softc *sc)
499 {
500
501 return (AAC_GETREG4(sc, AAC_SA_FWSTATUS));
502 }
503
504 static int
505 aac_rx_get_fwstatus(struct aac_softc *sc)
506 {
507
508 return (AAC_GETREG4(sc, AAC_RX_FWSTATUS));
509 }
510
511 /*
512 * Notify the controller of a change in a given queue
513 */
514
515 static void
516 aac_sa_qnotify(struct aac_softc *sc, int qbit)
517 {
518
519 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit);
520 }
521
522 static void
523 aac_rx_qnotify(struct aac_softc *sc, int qbit)
524 {
525
526 AAC_SETREG4(sc, AAC_RX_IDBR, qbit);
527 }
528
529 /*
530 * Get the interrupt reason bits
531 */
532 static int
533 aac_sa_get_istatus(struct aac_softc *sc)
534 {
535
536 return (AAC_GETREG2(sc, AAC_SA_DOORBELL0));
537 }
538
539 static int
540 aac_rx_get_istatus(struct aac_softc *sc)
541 {
542
543 return (AAC_GETREG4(sc, AAC_RX_ODBR));
544 }
545
546 /*
547 * Clear some interrupt reason bits
548 */
549 static void
550 aac_sa_clear_istatus(struct aac_softc *sc, int mask)
551 {
552
553 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask);
554 }
555
556 static void
557 aac_rx_clear_istatus(struct aac_softc *sc, int mask)
558 {
559
560 AAC_SETREG4(sc, AAC_RX_ODBR, mask);
561 }
562
563 /*
564 * Populate the mailbox and set the command word
565 */
566 static void
567 aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command,
568 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
569 u_int32_t arg3)
570 {
571
572 AAC_SETREG4(sc, AAC_SA_MAILBOX, command);
573 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0);
574 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1);
575 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2);
576 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3);
577 }
578
579 static void
580 aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command,
581 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2,
582 u_int32_t arg3)
583 {
584
585 AAC_SETREG4(sc, AAC_RX_MAILBOX, command);
586 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0);
587 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1);
588 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2);
589 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3);
590 }
591
592 /*
593 * Fetch the specified mailbox
594 */
595 static uint32_t
596 aac_sa_get_mailbox(struct aac_softc *sc, int mb)
597 {
598
599 return (AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4)));
600 }
601
602 static uint32_t
603 aac_rx_get_mailbox(struct aac_softc *sc, int mb)
604 {
605
606 return (AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4)));
607 }
608
609 /*
610 * Set/clear interrupt masks
611 */
612 static void
613 aac_sa_set_interrupts(struct aac_softc *sc, int enable)
614 {
615
616 if (enable)
617 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS);
618 else
619 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0);
620 }
621
622 static void
623 aac_rx_set_interrupts(struct aac_softc *sc, int enable)
624 {
625
626 if (enable)
627 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS);
628 else
629 AAC_SETREG4(sc, AAC_RX_OIMR, ~0);
630 }
631