1 /* $NetBSD: aac_pci.c,v 1.16 2005/12/11 12:22:48 christos 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 2005/12/11 12:22:48 christos 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 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 } static 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