1 /* $NetBSD: aac_pci.c,v 1.10 2004/05/10 06:21:09 gendalia 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.10 2004/05/10 06:21:09 gendalia 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 int aac_pci_match(struct device *, struct cfdata *, void *); 96 void aac_pci_attach(struct device *, struct device *, void *); 97 const struct aac_ident *aac_find_ident(struct pci_attach_args *); 98 99 /* i960Rx interface */ 100 int aac_rx_get_fwstatus(struct aac_softc *); 101 void aac_rx_qnotify(struct aac_softc *, int); 102 int aac_rx_get_istatus(struct aac_softc *); 103 void aac_rx_clear_istatus(struct aac_softc *, int); 104 void aac_rx_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, 105 u_int32_t, u_int32_t, u_int32_t); 106 int aac_rx_get_mailboxstatus(struct aac_softc *); 107 void aac_rx_set_interrupts(struct aac_softc *, int); 108 109 /* StrongARM interface */ 110 int aac_sa_get_fwstatus(struct aac_softc *); 111 void aac_sa_qnotify(struct aac_softc *, int); 112 int aac_sa_get_istatus(struct aac_softc *); 113 void aac_sa_clear_istatus(struct aac_softc *, int); 114 void aac_sa_set_mailbox(struct aac_softc *, u_int32_t, u_int32_t, 115 u_int32_t, u_int32_t, u_int32_t); 116 int aac_sa_get_mailboxstatus(struct aac_softc *); 117 void aac_sa_set_interrupts(struct aac_softc *, int); 118 119 const struct aac_interface aac_rx_interface = { 120 aac_rx_get_fwstatus, 121 aac_rx_qnotify, 122 aac_rx_get_istatus, 123 aac_rx_clear_istatus, 124 aac_rx_set_mailbox, 125 aac_rx_get_mailboxstatus, 126 aac_rx_set_interrupts 127 }; 128 129 const struct aac_interface aac_sa_interface = { 130 aac_sa_get_fwstatus, 131 aac_sa_qnotify, 132 aac_sa_get_istatus, 133 aac_sa_clear_istatus, 134 aac_sa_set_mailbox, 135 aac_sa_get_mailboxstatus, 136 aac_sa_set_interrupts 137 }; 138 139 struct aac_ident { 140 u_short vendor; 141 u_short device; 142 u_short subvendor; 143 u_short subdevice; 144 u_short hwif; 145 u_short quirks; 146 const char *prodstr; 147 } const aac_ident[] = { 148 { 149 PCI_VENDOR_DELL, 150 PCI_PRODUCT_DELL_PERC_2SI, 151 PCI_VENDOR_DELL, 152 PCI_PRODUCT_DELL_PERC_2SI, 153 AAC_HWIF_I960RX, 154 0, 155 "Dell PERC 2/Si" 156 }, 157 { 158 PCI_VENDOR_DELL, 159 PCI_PRODUCT_DELL_PERC_3DI, 160 PCI_VENDOR_DELL, 161 PCI_PRODUCT_DELL_PERC_3DI, 162 AAC_HWIF_I960RX, 163 0, 164 "Dell PERC 3/Di" 165 }, 166 { 167 PCI_VENDOR_DELL, 168 PCI_PRODUCT_DELL_PERC_3DI, 169 PCI_VENDOR_DELL, 170 PCI_PRODUCT_DELL_PERC_3DI_SUB2, 171 AAC_HWIF_I960RX, 172 0, 173 "Dell PERC 3/Di" 174 }, 175 { 176 PCI_VENDOR_DELL, 177 PCI_PRODUCT_DELL_PERC_3DI, 178 PCI_VENDOR_DELL, 179 PCI_PRODUCT_DELL_PERC_3DI_SUB3, 180 AAC_HWIF_I960RX, 181 0, 182 "Dell PERC 3/Di" 183 }, 184 { 185 PCI_VENDOR_DELL, 186 PCI_PRODUCT_DELL_PERC_3DI_2, 187 PCI_VENDOR_DELL, 188 PCI_PRODUCT_DELL_PERC_3DI_2_SUB, 189 AAC_HWIF_I960RX, 190 0, 191 "Dell PERC 3/Di" 192 }, 193 { 194 PCI_VENDOR_DELL, 195 PCI_PRODUCT_DELL_PERC_3DI_3, 196 PCI_VENDOR_DELL, 197 PCI_PRODUCT_DELL_PERC_3DI_3_SUB, 198 AAC_HWIF_I960RX, 199 0, 200 "Dell PERC 3/Di" 201 }, 202 { 203 PCI_VENDOR_DELL, 204 PCI_PRODUCT_DELL_PERC_3DI_3, 205 PCI_VENDOR_DELL, 206 PCI_PRODUCT_DELL_PERC_3DI_3_SUB2, 207 AAC_HWIF_I960RX, 208 0, 209 "Dell PERC 3/Di" 210 }, 211 { 212 PCI_VENDOR_DELL, 213 PCI_PRODUCT_DELL_PERC_3DI_3, 214 PCI_VENDOR_DELL, 215 PCI_PRODUCT_DELL_PERC_3DI_3_SUB3, 216 AAC_HWIF_I960RX, 217 0, 218 "Dell PERC 3/Di" 219 }, 220 { 221 PCI_VENDOR_DELL, 222 PCI_PRODUCT_DELL_PERC_3SI, 223 PCI_VENDOR_DELL, 224 PCI_PRODUCT_DELL_PERC_3SI, 225 AAC_HWIF_I960RX, 226 0, 227 "Dell PERC 3/Si" 228 }, 229 { 230 PCI_VENDOR_DELL, 231 PCI_PRODUCT_DELL_PERC_3SI_2, 232 PCI_VENDOR_DELL, 233 PCI_PRODUCT_DELL_PERC_3SI_2_SUB, 234 AAC_HWIF_I960RX, 235 0, 236 "Dell PERC 3/Si" 237 }, 238 { 239 PCI_VENDOR_ADP2, 240 PCI_PRODUCT_ADP2_AAC2622, 241 PCI_VENDOR_ADP2, 242 PCI_PRODUCT_ADP2_AAC2622, 243 AAC_HWIF_I960RX, 244 0, 245 "Adaptec ADP-2622" 246 }, 247 { 248 PCI_VENDOR_ADP2, 249 PCI_PRODUCT_ADP2_ASR2200S, 250 PCI_VENDOR_ADP2, 251 PCI_PRODUCT_ADP2_ASR2200S_SUB2M, 252 AAC_HWIF_I960RX, 253 0, 254 "Adaptec ASR-2200S" 255 }, 256 { 257 PCI_VENDOR_ADP2, 258 PCI_PRODUCT_ADP2_ASR2200S, 259 PCI_VENDOR_DELL, 260 PCI_PRODUCT_ADP2_ASR2200S_SUB2M, 261 AAC_HWIF_I960RX, 262 0, 263 "Dell PERC 320/DC" 264 }, 265 { 266 PCI_VENDOR_ADP2, 267 PCI_PRODUCT_ADP2_ASR2200S, 268 PCI_VENDOR_ADP2, 269 PCI_PRODUCT_ADP2_ASR2200S, 270 AAC_HWIF_I960RX, 271 0, 272 "Adaptec ASR-2200S" 273 }, 274 { 275 PCI_VENDOR_ADP2, 276 PCI_PRODUCT_ADP2_ASR2200S, 277 PCI_VENDOR_ADP2, 278 PCI_PRODUCT_ADP2_AAR2810SA, 279 AAC_HWIF_I960RX, 280 0, 281 "Adaptec AAR-2810SA" 282 }, 283 { 284 PCI_VENDOR_ADP2, 285 PCI_PRODUCT_ADP2_ASR2200S, 286 PCI_VENDOR_ADP2, 287 PCI_PRODUCT_ADP2_ASR2120S, 288 AAC_HWIF_I960RX, 289 0, 290 "Adaptec ASR-2120S" 291 }, 292 { 293 PCI_VENDOR_ADP2, 294 PCI_PRODUCT_ADP2_ASR2200S, 295 PCI_VENDOR_ADP2, 296 0x0290, 297 AAC_HWIF_I960RX, 298 0, 299 "Adaptec ASR-2410SA" 300 }, 301 { 302 PCI_VENDOR_DEC, 303 PCI_PRODUCT_DEC_21554, 304 PCI_VENDOR_ADP2, 305 PCI_PRODUCT_ADP2_AAC364, 306 AAC_HWIF_STRONGARM, 307 0, 308 "Adaptec AAC-364" 309 }, 310 { 311 PCI_VENDOR_DEC, 312 PCI_PRODUCT_DEC_21554, 313 PCI_VENDOR_ADP2, 314 PCI_PRODUCT_ADP2_ASR5400S, 315 AAC_HWIF_STRONGARM, 316 0, 317 "Adaptec ASR-5400S" 318 }, 319 { 320 PCI_VENDOR_DEC, 321 PCI_PRODUCT_DEC_21554, 322 PCI_VENDOR_ADP2, 323 PCI_PRODUCT_ADP2_PERC_2QC, 324 AAC_HWIF_STRONGARM, 325 AAC_QUIRK_PERC2QC, 326 "Dell PERC 2/QC" 327 }, 328 { 329 PCI_VENDOR_DEC, 330 PCI_PRODUCT_DEC_21554, 331 PCI_VENDOR_ADP2, 332 PCI_PRODUCT_ADP2_PERC_3QC, 333 AAC_HWIF_STRONGARM, 334 0, 335 "Dell PERC 3/QC" 336 }, 337 { 338 PCI_VENDOR_DEC, 339 PCI_PRODUCT_DEC_21554, 340 PCI_VENDOR_HP, 341 PCI_PRODUCT_HP_NETRAID_4M, 342 AAC_HWIF_STRONGARM, 343 0, 344 "HP NetRAID-4M" 345 }, 346 }; 347 348 CFATTACH_DECL(aac_pci, sizeof(struct aac_softc), 349 aac_pci_match, aac_pci_attach, NULL, NULL); 350 351 const struct aac_ident * 352 aac_find_ident(struct pci_attach_args *pa) 353 { 354 const struct aac_ident *m, *mm; 355 u_int32_t subsysid; 356 357 m = aac_ident; 358 mm = aac_ident + (sizeof(aac_ident) / sizeof(aac_ident[0])); 359 360 while (m < mm) { 361 if (m->vendor == PCI_VENDOR(pa->pa_id) && 362 m->device == PCI_PRODUCT(pa->pa_id)) { 363 subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, 364 PCI_SUBSYS_ID_REG); 365 if (m->subvendor == PCI_VENDOR(subsysid) && 366 m->subdevice == PCI_PRODUCT(subsysid)) 367 return (m); 368 } 369 m++; 370 } 371 372 return (NULL); 373 } 374 375 int 376 aac_pci_match(struct device *parent, struct cfdata *match, void *aux) 377 { 378 struct pci_attach_args *pa; 379 380 pa = aux; 381 382 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) 383 return (0); 384 385 return (aac_find_ident(pa) != NULL); 386 } 387 388 void 389 aac_pci_attach(struct device *parent, struct device *self, void *aux) 390 { 391 struct pci_attach_args *pa; 392 pci_chipset_tag_t pc; 393 struct aac_softc *sc; 394 u_int16_t command; 395 bus_addr_t membase; 396 bus_size_t memsize; 397 pci_intr_handle_t ih; 398 const char *intrstr; 399 int state; 400 const struct aac_ident *m; 401 402 pa = aux; 403 pc = pa->pa_pc; 404 sc = (struct aac_softc *)self; 405 state = 0; 406 407 aprint_naive(": RAID controller\n"); 408 aprint_normal(": "); 409 410 /* 411 * Verify that the adapter is correctly set up in PCI space. 412 */ 413 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 414 command |= PCI_COMMAND_MASTER_ENABLE; 415 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); 416 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 417 AAC_DPRINTF(AAC_D_MISC, ("pci command status reg 0x08x ")); 418 419 if ((command & PCI_COMMAND_MASTER_ENABLE) == 0) { 420 aprint_error("can't enable bus-master feature\n"); 421 goto bail_out; 422 } 423 424 if ((command & PCI_COMMAND_MEM_ENABLE) == 0) { 425 aprint_error("memory window not available\n"); 426 goto bail_out; 427 } 428 429 /* 430 * Map control/status registers. 431 */ 432 if (pci_mapreg_map(pa, PCI_MAPREG_START, 433 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt, 434 &sc->sc_memh, &membase, &memsize)) { 435 aprint_error("can't find mem space\n"); 436 goto bail_out; 437 } 438 state++; 439 440 if (pci_intr_map(pa, &ih)) { 441 aprint_error("couldn't map interrupt\n"); 442 goto bail_out; 443 } 444 intrstr = pci_intr_string(pc, ih); 445 sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc); 446 if (sc->sc_ih == NULL) { 447 aprint_error("couldn't establish interrupt"); 448 if (intrstr != NULL) 449 aprint_normal(" at %s", intrstr); 450 aprint_normal("\n"); 451 goto bail_out; 452 } 453 state++; 454 455 sc->sc_dmat = pa->pa_dmat; 456 457 m = aac_find_ident(pa); 458 aprint_normal("%s\n", m->prodstr); 459 if (intrstr != NULL) 460 aprint_normal("%s: interrupting at %s\n", 461 sc->sc_dv.dv_xname, intrstr); 462 463 sc->sc_hwif = m->hwif; 464 sc->sc_quirks = m->quirks; 465 switch (sc->sc_hwif) { 466 case AAC_HWIF_I960RX: 467 AAC_DPRINTF(AAC_D_MISC, 468 ("set hardware up for i960Rx")); 469 sc->sc_if = aac_rx_interface; 470 break; 471 472 case AAC_HWIF_STRONGARM: 473 AAC_DPRINTF(AAC_D_MISC, 474 ("set hardware up for StrongARM")); 475 sc->sc_if = aac_sa_interface; 476 break; 477 } 478 479 if (!aac_attach(sc)) 480 return; 481 482 bail_out: 483 if (state > 1) 484 pci_intr_disestablish(pc, sc->sc_ih); 485 if (state > 0) 486 bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize); 487 } 488 489 /* 490 * Read the current firmware status word. 491 */ 492 int 493 aac_sa_get_fwstatus(struct aac_softc *sc) 494 { 495 496 return (AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 497 } 498 499 int 500 aac_rx_get_fwstatus(struct aac_softc *sc) 501 { 502 503 return (AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 504 } 505 506 /* 507 * Notify the controller of a change in a given queue 508 */ 509 510 void 511 aac_sa_qnotify(struct aac_softc *sc, int qbit) 512 { 513 514 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 515 } 516 517 void 518 aac_rx_qnotify(struct aac_softc *sc, int qbit) 519 { 520 521 AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 522 } 523 524 /* 525 * Get the interrupt reason bits 526 */ 527 int 528 aac_sa_get_istatus(struct aac_softc *sc) 529 { 530 531 return (AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 532 } 533 534 int 535 aac_rx_get_istatus(struct aac_softc *sc) 536 { 537 538 return (AAC_GETREG4(sc, AAC_RX_ODBR)); 539 } 540 541 /* 542 * Clear some interrupt reason bits 543 */ 544 void 545 aac_sa_clear_istatus(struct aac_softc *sc, int mask) 546 { 547 548 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 549 } 550 551 void 552 aac_rx_clear_istatus(struct aac_softc *sc, int mask) 553 { 554 555 AAC_SETREG4(sc, AAC_RX_ODBR, mask); 556 } 557 558 /* 559 * Populate the mailbox and set the command word 560 */ 561 void 562 aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 563 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 564 u_int32_t arg3) 565 { 566 567 AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 568 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 569 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 570 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 571 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 572 } 573 574 void 575 aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 576 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 577 u_int32_t arg3) 578 { 579 580 AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 581 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 582 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 583 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 584 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 585 } 586 587 /* 588 * Fetch the immediate command status word 589 */ 590 int 591 aac_sa_get_mailboxstatus(struct aac_softc *sc) 592 { 593 594 return (AAC_GETREG4(sc, AAC_SA_MAILBOX)); 595 } 596 597 int 598 aac_rx_get_mailboxstatus(struct aac_softc *sc) 599 { 600 601 return (AAC_GETREG4(sc, AAC_RX_MAILBOX)); 602 } 603 604 /* 605 * Set/clear interrupt masks 606 */ 607 void 608 aac_sa_set_interrupts(struct aac_softc *sc, int enable) 609 { 610 611 if (enable) 612 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 613 else 614 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 615 } 616 617 void 618 aac_rx_set_interrupts(struct aac_softc *sc, int enable) 619 { 620 621 if (enable) 622 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 623 else 624 AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 625 } 626