1 | /* $NetBSD: aac_pci.c,v 1.38 2016/09/27 03:33:32 pgoyette 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 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /*- |
33 | * Copyright (c) 2000 Michael Smith |
34 | * Copyright (c) 2000 BSDi |
35 | * Copyright (c) 2000 Niklas Hallqvist |
36 | * All rights reserved. |
37 | * |
38 | * Redistribution and use in source and binary forms, with or without |
39 | * modification, are permitted provided that the following conditions |
40 | * are met: |
41 | * 1. Redistributions of source code must retain the above copyright |
42 | * notice, this list of conditions and the following disclaimer. |
43 | * 2. Redistributions in binary form must reproduce the above copyright |
44 | * notice, this list of conditions and the following disclaimer in the |
45 | * documentation and/or other materials provided with the distribution. |
46 | * |
47 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
48 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
49 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
50 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
51 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
52 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
53 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
54 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
55 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
56 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
57 | * SUCH DAMAGE. |
58 | * |
59 | * from FreeBSD: aac_pci.c,v 1.1 2000/09/13 03:20:34 msmith Exp |
60 | * via OpenBSD: aac_pci.c,v 1.7 2002/03/14 01:26:58 millert Exp |
61 | */ |
62 | |
63 | /* |
64 | * PCI front-end for the `aac' driver. |
65 | */ |
66 | |
67 | #include <sys/cdefs.h> |
68 | __KERNEL_RCSID(0, "$NetBSD: aac_pci.c,v 1.38 2016/09/27 03:33:32 pgoyette Exp $" ); |
69 | |
70 | #include <sys/param.h> |
71 | #include <sys/systm.h> |
72 | #include <sys/device.h> |
73 | #include <sys/kernel.h> |
74 | #include <sys/malloc.h> |
75 | #include <sys/queue.h> |
76 | |
77 | #include <sys/bus.h> |
78 | #include <machine/endian.h> |
79 | #include <sys/intr.h> |
80 | |
81 | #include <dev/pci/pcidevs.h> |
82 | #include <dev/pci/pcireg.h> |
83 | #include <dev/pci/pcivar.h> |
84 | |
85 | #include <dev/ic/aacreg.h> |
86 | #include <dev/ic/aacvar.h> |
87 | |
88 | struct aac_pci_softc { |
89 | struct aac_softc sc_aac; |
90 | pci_chipset_tag_t sc_pc; |
91 | pci_intr_handle_t sc_ih; |
92 | }; |
93 | |
94 | /* i960Rx interface */ |
95 | static int aac_rx_get_fwstatus(struct aac_softc *); |
96 | static void aac_rx_qnotify(struct aac_softc *, int); |
97 | static int aac_rx_get_istatus(struct aac_softc *); |
98 | static void aac_rx_clear_istatus(struct aac_softc *, int); |
99 | static void aac_rx_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, |
100 | u_int32_t, u_int32_t, u_int32_t); |
101 | static uint32_t aac_rx_get_mailbox(struct aac_softc *, int); |
102 | static void aac_rx_set_interrupts(struct aac_softc *, int); |
103 | static int aac_rx_send_command(struct aac_softc *, struct aac_ccb *); |
104 | static int aac_rx_get_outb_queue(struct aac_softc *); |
105 | static void aac_rx_set_outb_queue(struct aac_softc *, int); |
106 | |
107 | /* StrongARM interface */ |
108 | static int aac_sa_get_fwstatus(struct aac_softc *); |
109 | static void aac_sa_qnotify(struct aac_softc *, int); |
110 | static int aac_sa_get_istatus(struct aac_softc *); |
111 | static void aac_sa_clear_istatus(struct aac_softc *, int); |
112 | static void aac_sa_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, |
113 | u_int32_t, u_int32_t, u_int32_t); |
114 | static uint32_t aac_sa_get_mailbox(struct aac_softc *, int); |
115 | static void aac_sa_set_interrupts(struct aac_softc *, int); |
116 | |
117 | /* Rocket/MIPS interface */ |
118 | static int aac_rkt_get_fwstatus(struct aac_softc *); |
119 | static void aac_rkt_qnotify(struct aac_softc *, int); |
120 | static int aac_rkt_get_istatus(struct aac_softc *); |
121 | static void aac_rkt_clear_istatus(struct aac_softc *, int); |
122 | static void aac_rkt_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, |
123 | u_int32_t, u_int32_t, u_int32_t); |
124 | static uint32_t aac_rkt_get_mailbox(struct aac_softc *, int); |
125 | static void aac_rkt_set_interrupts(struct aac_softc *, int); |
126 | static int aac_rkt_send_command(struct aac_softc *, struct aac_ccb *); |
127 | static int aac_rkt_get_outb_queue(struct aac_softc *); |
128 | static void aac_rkt_set_outb_queue(struct aac_softc *, int); |
129 | |
130 | static const struct aac_interface aac_rx_interface = { |
131 | aac_rx_get_fwstatus, |
132 | aac_rx_qnotify, |
133 | aac_rx_get_istatus, |
134 | aac_rx_clear_istatus, |
135 | aac_rx_set_mailbox, |
136 | aac_rx_get_mailbox, |
137 | aac_rx_set_interrupts, |
138 | aac_rx_send_command, |
139 | aac_rx_get_outb_queue, |
140 | aac_rx_set_outb_queue |
141 | }; |
142 | |
143 | static const struct aac_interface aac_sa_interface = { |
144 | aac_sa_get_fwstatus, |
145 | aac_sa_qnotify, |
146 | aac_sa_get_istatus, |
147 | aac_sa_clear_istatus, |
148 | aac_sa_set_mailbox, |
149 | aac_sa_get_mailbox, |
150 | aac_sa_set_interrupts, |
151 | NULL, NULL, NULL |
152 | }; |
153 | |
154 | static const struct aac_interface aac_rkt_interface = { |
155 | aac_rkt_get_fwstatus, |
156 | aac_rkt_qnotify, |
157 | aac_rkt_get_istatus, |
158 | aac_rkt_clear_istatus, |
159 | aac_rkt_set_mailbox, |
160 | aac_rkt_get_mailbox, |
161 | aac_rkt_set_interrupts, |
162 | aac_rkt_send_command, |
163 | aac_rkt_get_outb_queue, |
164 | aac_rkt_set_outb_queue |
165 | }; |
166 | |
167 | static struct aac_ident { |
168 | u_short vendor; |
169 | u_short device; |
170 | u_short subvendor; |
171 | u_short subdevice; |
172 | u_short hwif; |
173 | u_short quirks; |
174 | const char *prodstr; |
175 | } const aac_ident[] = { |
176 | { |
177 | PCI_VENDOR_DELL, |
178 | PCI_PRODUCT_DELL_PERC_2SI, |
179 | PCI_VENDOR_DELL, |
180 | PCI_PRODUCT_DELL_PERC_2SI, |
181 | AAC_HWIF_I960RX, |
182 | 0, |
183 | "Dell PERC 2/Si" |
184 | }, |
185 | { |
186 | PCI_VENDOR_DELL, |
187 | PCI_PRODUCT_DELL_PERC_3DI, |
188 | PCI_VENDOR_DELL, |
189 | PCI_PRODUCT_DELL_PERC_3DI, |
190 | AAC_HWIF_I960RX, |
191 | 0, |
192 | "Dell PERC 3/Di" |
193 | }, |
194 | { |
195 | PCI_VENDOR_DELL, |
196 | PCI_PRODUCT_DELL_PERC_3DI, |
197 | PCI_VENDOR_DELL, |
198 | PCI_PRODUCT_DELL_PERC_3DI_SUB2, |
199 | AAC_HWIF_I960RX, |
200 | 0, |
201 | "Dell PERC 3/Di" |
202 | }, |
203 | { |
204 | PCI_VENDOR_DELL, |
205 | PCI_PRODUCT_DELL_PERC_3DI, |
206 | PCI_VENDOR_DELL, |
207 | PCI_PRODUCT_DELL_PERC_3DI_SUB3, |
208 | AAC_HWIF_I960RX, |
209 | 0, |
210 | "Dell PERC 3/Di" |
211 | }, |
212 | { |
213 | PCI_VENDOR_DELL, |
214 | PCI_PRODUCT_DELL_PERC_3DI_2, |
215 | PCI_VENDOR_DELL, |
216 | PCI_PRODUCT_DELL_PERC_3DI_2_SUB, |
217 | AAC_HWIF_I960RX, |
218 | 0, |
219 | "Dell PERC 3/Di" |
220 | }, |
221 | { |
222 | PCI_VENDOR_DELL, |
223 | PCI_PRODUCT_DELL_PERC_3DI_3, |
224 | PCI_VENDOR_DELL, |
225 | PCI_PRODUCT_DELL_PERC_3DI_3_SUB, |
226 | AAC_HWIF_I960RX, |
227 | 0, |
228 | "Dell PERC 3/Di" |
229 | }, |
230 | { |
231 | PCI_VENDOR_DELL, |
232 | PCI_PRODUCT_DELL_PERC_3DI_3, |
233 | PCI_VENDOR_DELL, |
234 | PCI_PRODUCT_DELL_PERC_3DI_3_SUB2, |
235 | AAC_HWIF_I960RX, |
236 | 0, |
237 | "Dell PERC 3/Di" |
238 | }, |
239 | { |
240 | PCI_VENDOR_DELL, |
241 | PCI_PRODUCT_DELL_PERC_3DI_3, |
242 | PCI_VENDOR_DELL, |
243 | PCI_PRODUCT_DELL_PERC_3DI_3_SUB3, |
244 | AAC_HWIF_I960RX, |
245 | 0, |
246 | "Dell PERC 3/Di" |
247 | }, |
248 | { |
249 | PCI_VENDOR_DELL, |
250 | PCI_PRODUCT_DELL_PERC_3SI, |
251 | PCI_VENDOR_DELL, |
252 | PCI_PRODUCT_DELL_PERC_3SI, |
253 | AAC_HWIF_I960RX, |
254 | 0, |
255 | "Dell PERC 3/Si" |
256 | }, |
257 | { |
258 | PCI_VENDOR_DELL, |
259 | PCI_PRODUCT_DELL_PERC_3SI_2, |
260 | PCI_VENDOR_DELL, |
261 | PCI_PRODUCT_DELL_PERC_3SI_2_SUB, |
262 | AAC_HWIF_I960RX, |
263 | 0, |
264 | "Dell PERC 3/Si" |
265 | }, |
266 | { |
267 | PCI_VENDOR_ADP2, |
268 | PCI_PRODUCT_ADP2_ASR2200S, |
269 | PCI_VENDOR_DELL, |
270 | PCI_PRODUCT_DELL_CERC_1_5, |
271 | AAC_HWIF_I960RX, |
272 | AAC_QUIRK_NO4GB, |
273 | "Dell CERC SATA RAID 1.5/6ch" |
274 | }, |
275 | { |
276 | PCI_VENDOR_ADP2, |
277 | PCI_PRODUCT_ADP2_AAC2622, |
278 | PCI_VENDOR_ADP2, |
279 | PCI_PRODUCT_ADP2_AAC2622, |
280 | AAC_HWIF_I960RX, |
281 | 0, |
282 | "Adaptec ADP-2622" |
283 | }, |
284 | { |
285 | PCI_VENDOR_ADP2, |
286 | PCI_PRODUCT_ADP2_ASR2200S, |
287 | PCI_VENDOR_ADP2, |
288 | PCI_PRODUCT_ADP2_ASR2200S_SUB2M, |
289 | AAC_HWIF_I960RX, |
290 | AAC_QUIRK_NO4GB | AAC_QUIRK_256FIBS, |
291 | "Adaptec ASR-2200S" |
292 | }, |
293 | { |
294 | PCI_VENDOR_ADP2, |
295 | PCI_PRODUCT_ADP2_ASR2200S, |
296 | PCI_VENDOR_DELL, |
297 | PCI_PRODUCT_ADP2_ASR2200S_SUB2M, |
298 | AAC_HWIF_I960RX, |
299 | AAC_QUIRK_NO4GB | AAC_QUIRK_256FIBS, |
300 | "Dell PERC 320/DC" |
301 | }, |
302 | { |
303 | PCI_VENDOR_ADP2, |
304 | PCI_PRODUCT_ADP2_ASR2200S, |
305 | PCI_VENDOR_ADP2, |
306 | PCI_PRODUCT_ADP2_ASR2200S, |
307 | AAC_HWIF_I960RX, |
308 | AAC_QUIRK_NO4GB | AAC_QUIRK_256FIBS, |
309 | "Adaptec ASR-2200S" |
310 | }, |
311 | { |
312 | PCI_VENDOR_ADP2, |
313 | PCI_PRODUCT_ADP2_ASR2200S, |
314 | PCI_VENDOR_ADP2, |
315 | PCI_PRODUCT_ADP2_AAR2810SA, |
316 | AAC_HWIF_I960RX, |
317 | AAC_QUIRK_NO4GB, |
318 | "Adaptec AAR-2810SA" |
319 | }, |
320 | { |
321 | PCI_VENDOR_ADP2, |
322 | PCI_PRODUCT_ADP2_ASR2200S, |
323 | PCI_VENDOR_ADP2, |
324 | PCI_PRODUCT_ADP2_ASR2120S, |
325 | AAC_HWIF_I960RX, |
326 | AAC_QUIRK_NO4GB | AAC_QUIRK_256FIBS, |
327 | "Adaptec ASR-2120S" |
328 | }, |
329 | { |
330 | PCI_VENDOR_ADP2, |
331 | PCI_PRODUCT_ADP2_ASR2200S, |
332 | PCI_VENDOR_ADP2, |
333 | PCI_PRODUCT_ADP2_ASR2410SA, |
334 | AAC_HWIF_I960RX, |
335 | AAC_QUIRK_NO4GB, |
336 | "Adaptec ASR-2410SA" |
337 | }, |
338 | { |
339 | PCI_VENDOR_ADP2, |
340 | PCI_PRODUCT_ADP2_ASR2200S, |
341 | PCI_VENDOR_HP, |
342 | PCI_PRODUCT_ADP2_HP_M110_G2, |
343 | AAC_HWIF_I960RX, |
344 | AAC_QUIRK_NO4GB, |
345 | "HP ML110 G2 (Adaptec ASR-2610SA)" |
346 | }, |
347 | { |
348 | PCI_VENDOR_ADP2, |
349 | PCI_PRODUCT_ADP2_ASR2120S, |
350 | PCI_VENDOR_IBM, |
351 | PCI_PRODUCT_IBM_SERVERAID8K, |
352 | AAC_HWIF_RKT, |
353 | 0, |
354 | "IBM ServeRAID 8k" |
355 | }, |
356 | { PCI_VENDOR_ADP2, |
357 | PCI_PRODUCT_ADP2_ASR2200S, |
358 | PCI_VENDOR_ADP2, |
359 | PCI_PRODUCT_ADP2_2405, |
360 | AAC_HWIF_I960RX, |
361 | 0, |
362 | "Adaptec RAID 2405" |
363 | }, |
364 | { PCI_VENDOR_ADP2, |
365 | PCI_PRODUCT_ADP2_ASR2200S, |
366 | PCI_VENDOR_ADP2, |
367 | PCI_PRODUCT_ADP2_3405, |
368 | AAC_HWIF_I960RX, |
369 | 0, |
370 | "Adaptec RAID 3405" |
371 | }, |
372 | { PCI_VENDOR_ADP2, |
373 | PCI_PRODUCT_ADP2_ASR2200S, |
374 | PCI_VENDOR_ADP2, |
375 | PCI_PRODUCT_ADP2_3805, |
376 | AAC_HWIF_I960RX, |
377 | 0, |
378 | "Adaptec RAID 3805" |
379 | }, |
380 | { |
381 | PCI_VENDOR_DEC, |
382 | PCI_PRODUCT_DEC_21554, |
383 | PCI_VENDOR_ADP2, |
384 | PCI_PRODUCT_ADP2_AAC364, |
385 | AAC_HWIF_STRONGARM, |
386 | 0, |
387 | "Adaptec AAC-364" |
388 | }, |
389 | { |
390 | PCI_VENDOR_DEC, |
391 | PCI_PRODUCT_DEC_21554, |
392 | PCI_VENDOR_ADP2, |
393 | PCI_PRODUCT_ADP2_ASR5400S, |
394 | AAC_HWIF_STRONGARM, |
395 | AAC_QUIRK_BROKEN_MMAP, |
396 | "Adaptec ASR-5400S" |
397 | }, |
398 | { |
399 | PCI_VENDOR_DEC, |
400 | PCI_PRODUCT_DEC_21554, |
401 | PCI_VENDOR_ADP2, |
402 | PCI_PRODUCT_ADP2_PERC_2QC, |
403 | AAC_HWIF_STRONGARM, |
404 | AAC_QUIRK_PERC2QC, |
405 | "Dell PERC 2/QC" |
406 | }, |
407 | { |
408 | PCI_VENDOR_DEC, |
409 | PCI_PRODUCT_DEC_21554, |
410 | PCI_VENDOR_ADP2, |
411 | PCI_PRODUCT_ADP2_PERC_3QC, |
412 | AAC_HWIF_STRONGARM, |
413 | 0, |
414 | "Dell PERC 3/QC" |
415 | }, |
416 | { |
417 | PCI_VENDOR_DEC, |
418 | PCI_PRODUCT_DEC_21554, |
419 | PCI_VENDOR_HP, |
420 | PCI_PRODUCT_HP_NETRAID_4M, |
421 | AAC_HWIF_STRONGARM, |
422 | 0, |
423 | "HP NetRAID-4M" |
424 | }, |
425 | { |
426 | PCI_VENDOR_ADP2, |
427 | PCI_PRODUCT_ADP2_ASR2200S, |
428 | PCI_VENDOR_SUN, |
429 | PCI_PRODUCT_ADP2_ASR2120S, |
430 | AAC_HWIF_I960RX, |
431 | 0, |
432 | "SG-XPCIESAS-R-IN" |
433 | }, |
434 | }; |
435 | |
436 | static const struct aac_ident * |
437 | aac_find_ident(struct pci_attach_args *pa) |
438 | { |
439 | const struct aac_ident *m, *mm; |
440 | u_int32_t subsysid; |
441 | |
442 | m = aac_ident; |
443 | mm = aac_ident + (sizeof(aac_ident) / sizeof(aac_ident[0])); |
444 | |
445 | while (m < mm) { |
446 | if (m->vendor == PCI_VENDOR(pa->pa_id) && |
447 | m->device == PCI_PRODUCT(pa->pa_id)) { |
448 | subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, |
449 | PCI_SUBSYS_ID_REG); |
450 | if (m->subvendor == PCI_VENDOR(subsysid) && |
451 | m->subdevice == PCI_PRODUCT(subsysid)) |
452 | return (m); |
453 | } |
454 | m++; |
455 | } |
456 | |
457 | return (NULL); |
458 | } |
459 | |
460 | static int |
461 | aac_pci_intr_set(struct aac_softc *sc, int (*hand)(void*), void *arg) |
462 | { |
463 | struct aac_pci_softc *pcisc; |
464 | |
465 | pcisc = (struct aac_pci_softc *) sc; |
466 | |
467 | pci_intr_disestablish(pcisc->sc_pc, sc->sc_ih); |
468 | sc->sc_ih = pci_intr_establish(pcisc->sc_pc, pcisc->sc_ih, |
469 | IPL_BIO, hand, arg); |
470 | if (sc->sc_ih == NULL) { |
471 | return ENXIO; |
472 | } |
473 | return 0; |
474 | } |
475 | |
476 | static int |
477 | aac_pci_match(device_t parent, cfdata_t match, void *aux) |
478 | { |
479 | struct pci_attach_args *pa; |
480 | |
481 | pa = aux; |
482 | |
483 | if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) |
484 | return (0); |
485 | |
486 | return (aac_find_ident(pa) != NULL); |
487 | } |
488 | |
489 | static void |
490 | aac_pci_attach(device_t parent, device_t self, void *aux) |
491 | { |
492 | struct pci_attach_args *pa; |
493 | pci_chipset_tag_t pc; |
494 | struct aac_pci_softc *pcisc; |
495 | struct aac_softc *sc; |
496 | u_int16_t command; |
497 | bus_addr_t membase; |
498 | bus_size_t memsize; |
499 | const char *intrstr; |
500 | int state; |
501 | const struct aac_ident *m; |
502 | char intrbuf[PCI_INTRSTR_LEN]; |
503 | |
504 | pa = aux; |
505 | pc = pa->pa_pc; |
506 | pcisc = device_private(self); |
507 | pcisc->sc_pc = pc; |
508 | sc = &pcisc->sc_aac; |
509 | sc->sc_dv = self; |
510 | state = 0; |
511 | |
512 | aprint_naive(": RAID controller\n" ); |
513 | aprint_normal(": " ); |
514 | |
515 | /* |
516 | * Verify that the adapter is correctly set up in PCI space. |
517 | */ |
518 | command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); |
519 | command |= PCI_COMMAND_MASTER_ENABLE; |
520 | pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); |
521 | command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); |
522 | AAC_DPRINTF(AAC_D_MISC, ("pci command status reg 0x08x " )); |
523 | |
524 | if ((command & PCI_COMMAND_MASTER_ENABLE) == 0) { |
525 | aprint_error("can't enable bus-master feature\n" ); |
526 | goto bail_out; |
527 | } |
528 | |
529 | if ((command & PCI_COMMAND_MEM_ENABLE) == 0) { |
530 | aprint_error("memory window not available\n" ); |
531 | goto bail_out; |
532 | } |
533 | |
534 | /* |
535 | * Map control/status registers. |
536 | */ |
537 | if (pci_mapreg_map(pa, PCI_MAPREG_START, |
538 | PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt, |
539 | &sc->sc_memh, &membase, &memsize)) { |
540 | aprint_error("can't find mem space\n" ); |
541 | goto bail_out; |
542 | } |
543 | state++; |
544 | |
545 | if (pci_intr_map(pa, &pcisc->sc_ih)) { |
546 | aprint_error("couldn't map interrupt\n" ); |
547 | goto bail_out; |
548 | } |
549 | intrstr = pci_intr_string(pc, pcisc->sc_ih, intrbuf, sizeof(intrbuf)); |
550 | sc->sc_ih = pci_intr_establish(pc, pcisc->sc_ih, IPL_BIO, aac_intr, sc); |
551 | if (sc->sc_ih == NULL) { |
552 | aprint_error("couldn't establish interrupt" ); |
553 | if (intrstr != NULL) |
554 | aprint_error(" at %s" , intrstr); |
555 | aprint_error("\n" ); |
556 | goto bail_out; |
557 | } |
558 | state++; |
559 | |
560 | sc->sc_dmat = pa->pa_dmat; |
561 | |
562 | m = aac_find_ident(pa); |
563 | aprint_normal("%s\n" , m->prodstr); |
564 | if (intrstr != NULL) |
565 | aprint_normal_dev(self, "interrupting at %s\n" , intrstr); |
566 | |
567 | sc->sc_hwif = m->hwif; |
568 | sc->sc_quirks = m->quirks; |
569 | switch (sc->sc_hwif) { |
570 | case AAC_HWIF_I960RX: |
571 | AAC_DPRINTF(AAC_D_MISC, |
572 | ("set hardware up for i960Rx" )); |
573 | sc->sc_if = aac_rx_interface; |
574 | break; |
575 | |
576 | case AAC_HWIF_STRONGARM: |
577 | AAC_DPRINTF(AAC_D_MISC, |
578 | ("set hardware up for StrongARM" )); |
579 | sc->sc_if = aac_sa_interface; |
580 | break; |
581 | |
582 | case AAC_HWIF_RKT: |
583 | AAC_DPRINTF(AAC_D_MISC, |
584 | ("set hardware up for MIPS/Rocket" )); |
585 | sc->sc_if = aac_rkt_interface; |
586 | break; |
587 | } |
588 | sc->sc_regsize = memsize; |
589 | sc->sc_intr_set = aac_pci_intr_set; |
590 | |
591 | if (!aac_attach(sc)) |
592 | return; |
593 | |
594 | bail_out: |
595 | if (state > 1) |
596 | pci_intr_disestablish(pc, sc->sc_ih); |
597 | if (state > 0) |
598 | bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize); |
599 | } |
600 | |
601 | /* ARGSUSED */ |
602 | static int |
603 | aac_pci_rescan(device_t self, const char *attr, const int *flags) |
604 | { |
605 | |
606 | return aac_devscan(device_private(self)); |
607 | } |
608 | |
609 | CFATTACH_DECL3_NEW(aac_pci, sizeof(struct aac_pci_softc), |
610 | aac_pci_match, aac_pci_attach, NULL, NULL, aac_pci_rescan, NULL, 0); |
611 | |
612 | /* |
613 | * Read the current firmware status word. |
614 | */ |
615 | static int |
616 | aac_sa_get_fwstatus(struct aac_softc *sc) |
617 | { |
618 | |
619 | return (AAC_GETREG4(sc, AAC_SA_FWSTATUS)); |
620 | } |
621 | |
622 | static int |
623 | aac_rx_get_fwstatus(struct aac_softc *sc) |
624 | { |
625 | |
626 | return (AAC_GETREG4(sc, AAC_RX_FWSTATUS)); |
627 | } |
628 | |
629 | static int |
630 | aac_rkt_get_fwstatus(struct aac_softc *sc) |
631 | { |
632 | |
633 | return (AAC_GETREG4(sc, AAC_RKT_FWSTATUS)); |
634 | } |
635 | |
636 | /* |
637 | * Notify the controller of a change in a given queue |
638 | */ |
639 | |
640 | static void |
641 | aac_sa_qnotify(struct aac_softc *sc, int qbit) |
642 | { |
643 | |
644 | AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); |
645 | } |
646 | |
647 | static void |
648 | aac_rx_qnotify(struct aac_softc *sc, int qbit) |
649 | { |
650 | |
651 | AAC_SETREG4(sc, AAC_RX_IDBR, qbit); |
652 | } |
653 | |
654 | static void |
655 | aac_rkt_qnotify(struct aac_softc *sc, int qbit) |
656 | { |
657 | |
658 | AAC_SETREG4(sc, AAC_RKT_IDBR, qbit); |
659 | } |
660 | |
661 | /* |
662 | * Get the interrupt reason bits |
663 | */ |
664 | static int |
665 | aac_sa_get_istatus(struct aac_softc *sc) |
666 | { |
667 | |
668 | return (AAC_GETREG2(sc, AAC_SA_DOORBELL0)); |
669 | } |
670 | |
671 | static int |
672 | aac_rx_get_istatus(struct aac_softc *sc) |
673 | { |
674 | |
675 | return (AAC_GETREG4(sc, AAC_RX_ODBR)); |
676 | } |
677 | |
678 | static int |
679 | aac_rkt_get_istatus(struct aac_softc *sc) |
680 | { |
681 | |
682 | return (AAC_GETREG4(sc, AAC_RKT_ODBR)); |
683 | } |
684 | |
685 | /* |
686 | * Clear some interrupt reason bits |
687 | */ |
688 | static void |
689 | aac_sa_clear_istatus(struct aac_softc *sc, int mask) |
690 | { |
691 | |
692 | AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); |
693 | } |
694 | |
695 | static void |
696 | aac_rx_clear_istatus(struct aac_softc *sc, int mask) |
697 | { |
698 | |
699 | AAC_SETREG4(sc, AAC_RX_ODBR, mask); |
700 | } |
701 | |
702 | static void |
703 | aac_rkt_clear_istatus(struct aac_softc *sc, int mask) |
704 | { |
705 | |
706 | AAC_SETREG4(sc, AAC_RKT_ODBR, mask); |
707 | } |
708 | |
709 | /* |
710 | * Populate the mailbox and set the command word |
711 | */ |
712 | static void |
713 | aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, |
714 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, |
715 | u_int32_t arg3) |
716 | { |
717 | |
718 | AAC_SETREG4(sc, AAC_SA_MAILBOX, command); |
719 | AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); |
720 | AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); |
721 | AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); |
722 | AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); |
723 | } |
724 | |
725 | static void |
726 | aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, |
727 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, |
728 | u_int32_t arg3) |
729 | { |
730 | |
731 | AAC_SETREG4(sc, AAC_RX_MAILBOX, command); |
732 | AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); |
733 | AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); |
734 | AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); |
735 | AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); |
736 | } |
737 | |
738 | static void |
739 | aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, |
740 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, |
741 | u_int32_t arg3) |
742 | { |
743 | |
744 | AAC_SETREG4(sc, AAC_RKT_MAILBOX, command); |
745 | AAC_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); |
746 | AAC_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); |
747 | AAC_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); |
748 | AAC_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); |
749 | } |
750 | |
751 | /* |
752 | * Fetch the specified mailbox |
753 | */ |
754 | static uint32_t |
755 | aac_sa_get_mailbox(struct aac_softc *sc, int mb) |
756 | { |
757 | |
758 | return (AAC_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); |
759 | } |
760 | |
761 | static uint32_t |
762 | aac_rx_get_mailbox(struct aac_softc *sc, int mb) |
763 | { |
764 | |
765 | return (AAC_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); |
766 | } |
767 | |
768 | static uint32_t |
769 | aac_rkt_get_mailbox(struct aac_softc *sc, int mb) |
770 | { |
771 | |
772 | return (AAC_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); |
773 | } |
774 | |
775 | /* |
776 | * Set/clear interrupt masks |
777 | */ |
778 | static void |
779 | aac_sa_set_interrupts(struct aac_softc *sc, int enable) |
780 | { |
781 | |
782 | if (enable) |
783 | AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); |
784 | else |
785 | AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); |
786 | } |
787 | |
788 | static void |
789 | aac_rx_set_interrupts(struct aac_softc *sc, int enable) |
790 | { |
791 | |
792 | if (enable) { |
793 | if (sc->sc_quirks & AAC_QUIRK_NEW_COMM) |
794 | AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); |
795 | else |
796 | AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); |
797 | } else { |
798 | AAC_SETREG4(sc, AAC_RX_OIMR, ~0); |
799 | } |
800 | } |
801 | |
802 | static void |
803 | aac_rkt_set_interrupts(struct aac_softc *sc, int enable) |
804 | { |
805 | |
806 | if (enable) { |
807 | if (sc->sc_quirks & AAC_QUIRK_NEW_COMM) |
808 | AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); |
809 | else |
810 | AAC_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); |
811 | } else { |
812 | AAC_SETREG4(sc, AAC_RKT_OIMR, ~0); |
813 | } |
814 | } |
815 | |
816 | /* |
817 | * New comm. interface: Send command functions |
818 | */ |
819 | static int |
820 | aac_rx_send_command(struct aac_softc *sc, struct aac_ccb *ac) |
821 | { |
822 | u_int32_t index, device; |
823 | |
824 | index = AAC_GETREG4(sc, AAC_RX_IQUE); |
825 | if (index == 0xffffffffL) |
826 | index = AAC_GETREG4(sc, AAC_RX_IQUE); |
827 | if (index == 0xffffffffL) |
828 | return index; |
829 | #ifdef notyet |
830 | aac_enqueue_busy(ac); |
831 | #endif |
832 | device = index; |
833 | AAC_SETREG4(sc, device, |
834 | htole32((u_int32_t)(ac->ac_fibphys & 0xffffffffUL))); |
835 | device += 4; |
836 | if (sizeof(bus_addr_t) > 4) { |
837 | AAC_SETREG4(sc, device, |
838 | htole32((u_int32_t)((u_int64_t)ac->ac_fibphys >> 32))); |
839 | } else { |
840 | AAC_SETREG4(sc, device, 0); |
841 | } |
842 | device += 4; |
843 | AAC_SETREG4(sc, device, ac->ac_fib->Header.Size); |
844 | AAC_SETREG4(sc, AAC_RX_IQUE, index); |
845 | return 0; |
846 | } |
847 | |
848 | static int |
849 | aac_rkt_send_command(struct aac_softc *sc, struct aac_ccb *ac) |
850 | { |
851 | u_int32_t index, device; |
852 | |
853 | index = AAC_GETREG4(sc, AAC_RKT_IQUE); |
854 | if (index == 0xffffffffL) |
855 | index = AAC_GETREG4(sc, AAC_RKT_IQUE); |
856 | if (index == 0xffffffffL) |
857 | return index; |
858 | #ifdef notyet |
859 | aac_enqueue_busy(ac); |
860 | #endif |
861 | device = index; |
862 | AAC_SETREG4(sc, device, |
863 | htole32((u_int32_t)(ac->ac_fibphys & 0xffffffffUL))); |
864 | device += 4; |
865 | if (sizeof(bus_addr_t) > 4) { |
866 | AAC_SETREG4(sc, device, |
867 | htole32((u_int32_t)((u_int64_t)ac->ac_fibphys >> 32))); |
868 | } else { |
869 | AAC_SETREG4(sc, device, 0); |
870 | } |
871 | device += 4; |
872 | AAC_SETREG4(sc, device, ac->ac_fib->Header.Size); |
873 | AAC_SETREG4(sc, AAC_RKT_IQUE, index); |
874 | return 0; |
875 | } |
876 | |
877 | /* |
878 | * New comm. interface: get, set outbound queue index |
879 | */ |
880 | static int |
881 | aac_rx_get_outb_queue(struct aac_softc *sc) |
882 | { |
883 | |
884 | return AAC_GETREG4(sc, AAC_RX_OQUE); |
885 | } |
886 | |
887 | static int |
888 | aac_rkt_get_outb_queue(struct aac_softc *sc) |
889 | { |
890 | |
891 | return AAC_GETREG4(sc, AAC_RKT_OQUE); |
892 | } |
893 | |
894 | static void |
895 | aac_rx_set_outb_queue(struct aac_softc *sc, int index) |
896 | { |
897 | |
898 | AAC_SETREG4(sc, AAC_RX_OQUE, index); |
899 | } |
900 | |
901 | static void |
902 | aac_rkt_set_outb_queue(struct aac_softc *sc, int index) |
903 | { |
904 | |
905 | AAC_SETREG4(sc, AAC_RKT_OQUE, index); |
906 | } |
907 | |