1 /* $NetBSD: aac_pci.c,v 1.7 2003/01/31 00:07:39 thorpej 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.7 2003/01/31 00:07:39 thorpej 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, 252 AAC_HWIF_I960RX, 253 0, 254 "Adaptec ASR-2200S" 255 }, 256 { 257 PCI_VENDOR_ADP2, 258 PCI_PRODUCT_ADP2_ASR2200S, 259 PCI_VENDOR_ADP2, 260 PCI_PRODUCT_ADP2_ASR2120S, 261 AAC_HWIF_I960RX, 262 0, 263 "Adaptec ASR-2120S" 264 }, 265 { 266 PCI_VENDOR_DEC, 267 PCI_PRODUCT_DEC_21554, 268 PCI_VENDOR_ADP2, 269 PCI_PRODUCT_ADP2_AAC364, 270 AAC_HWIF_STRONGARM, 271 0, 272 "Adaptec AAC-364" 273 }, 274 { 275 PCI_VENDOR_DEC, 276 PCI_PRODUCT_DEC_21554, 277 PCI_VENDOR_ADP2, 278 PCI_PRODUCT_ADP2_ASR5400S, 279 AAC_HWIF_STRONGARM, 280 0, 281 "Adaptec ASR-5400S" 282 }, 283 { 284 PCI_VENDOR_DEC, 285 PCI_PRODUCT_DEC_21554, 286 PCI_VENDOR_ADP2, 287 PCI_PRODUCT_ADP2_PERC_2QC, 288 AAC_HWIF_STRONGARM, 289 AAC_QUIRK_PERC2QC, 290 "Dell PERC 2/QC" 291 }, 292 { 293 PCI_VENDOR_DEC, 294 PCI_PRODUCT_DEC_21554, 295 PCI_VENDOR_ADP2, 296 PCI_PRODUCT_ADP2_PERC_3QC, 297 AAC_HWIF_STRONGARM, 298 0, 299 "Dell PERC 3/QC" 300 }, 301 { 302 PCI_VENDOR_DEC, 303 PCI_PRODUCT_DEC_21554, 304 PCI_VENDOR_HP, 305 PCI_PRODUCT_HP_NETRAID_4M, 306 AAC_HWIF_STRONGARM, 307 0, 308 "HP NetRAID-4M" 309 }, 310 }; 311 312 CFATTACH_DECL(aac_pci, sizeof(struct aac_softc), 313 aac_pci_match, aac_pci_attach, NULL, NULL); 314 315 const struct aac_ident * 316 aac_find_ident(struct pci_attach_args *pa) 317 { 318 const struct aac_ident *m, *mm; 319 u_int32_t subsysid; 320 321 m = aac_ident; 322 mm = aac_ident + (sizeof(aac_ident) / sizeof(aac_ident[0])); 323 324 while (m < mm) { 325 if (m->vendor == PCI_VENDOR(pa->pa_id) && 326 m->device == PCI_PRODUCT(pa->pa_id)) { 327 subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, 328 PCI_SUBSYS_ID_REG); 329 if (m->subvendor == PCI_VENDOR(subsysid) && 330 m->subdevice == PCI_PRODUCT(subsysid)) 331 return (m); 332 } 333 m++; 334 } 335 336 return (NULL); 337 } 338 339 int 340 aac_pci_match(struct device *parent, struct cfdata *match, void *aux) 341 { 342 struct pci_attach_args *pa; 343 344 pa = aux; 345 346 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) 347 return (0); 348 349 return (aac_find_ident(pa) != NULL); 350 } 351 352 void 353 aac_pci_attach(struct device *parent, struct device *self, void *aux) 354 { 355 struct pci_attach_args *pa; 356 pci_chipset_tag_t pc; 357 struct aac_softc *sc; 358 u_int16_t command; 359 bus_addr_t membase; 360 bus_size_t memsize; 361 pci_intr_handle_t ih; 362 const char *intrstr; 363 int state; 364 const struct aac_ident *m; 365 366 pa = aux; 367 pc = pa->pa_pc; 368 sc = (struct aac_softc *)self; 369 state = 0; 370 371 aprint_naive(": RAID controller\n"); 372 aprint_normal(": "); 373 374 /* 375 * Verify that the adapter is correctly set up in PCI space. 376 */ 377 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 378 command |= PCI_COMMAND_MASTER_ENABLE; 379 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); 380 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 381 AAC_DPRINTF(AAC_D_MISC, ("pci command status reg 0x08x ")); 382 383 if ((command & PCI_COMMAND_MASTER_ENABLE) == 0) { 384 aprint_error("can't enable bus-master feature\n"); 385 goto bail_out; 386 } 387 388 if ((command & PCI_COMMAND_MEM_ENABLE) == 0) { 389 aprint_error("memory window not available\n"); 390 goto bail_out; 391 } 392 393 /* 394 * Map control/status registers. 395 */ 396 if (pci_mapreg_map(pa, PCI_MAPREG_START, 397 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt, 398 &sc->sc_memh, &membase, &memsize)) { 399 aprint_error("can't find mem space\n"); 400 goto bail_out; 401 } 402 state++; 403 404 if (pci_intr_map(pa, &ih)) { 405 aprint_error("couldn't map interrupt\n"); 406 goto bail_out; 407 } 408 intrstr = pci_intr_string(pc, ih); 409 sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc); 410 if (sc->sc_ih == NULL) { 411 aprint_error("couldn't establish interrupt"); 412 if (intrstr != NULL) 413 aprint_normal(" at %s", intrstr); 414 aprint_normal("\n"); 415 goto bail_out; 416 } 417 state++; 418 419 sc->sc_dmat = pa->pa_dmat; 420 421 m = aac_find_ident(pa); 422 aprint_normal("%s\n", m->prodstr); 423 if (intrstr != NULL) 424 aprint_normal("%s: interrupting at %s\n", 425 sc->sc_dv.dv_xname, intrstr); 426 427 sc->sc_hwif = m->hwif; 428 sc->sc_quirks = m->quirks; 429 switch (sc->sc_hwif) { 430 case AAC_HWIF_I960RX: 431 AAC_DPRINTF(AAC_D_MISC, 432 ("set hardware up for i960Rx")); 433 sc->sc_if = aac_rx_interface; 434 break; 435 436 case AAC_HWIF_STRONGARM: 437 AAC_DPRINTF(AAC_D_MISC, 438 ("set hardware up for StrongARM")); 439 sc->sc_if = aac_sa_interface; 440 break; 441 } 442 443 if (!aac_attach(sc)) 444 return; 445 446 bail_out: 447 if (state > 1) 448 pci_intr_disestablish(pc, sc->sc_ih); 449 if (state > 0) 450 bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize); 451 } 452 453 /* 454 * Read the current firmware status word. 455 */ 456 int 457 aac_sa_get_fwstatus(struct aac_softc *sc) 458 { 459 460 return (AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 461 } 462 463 int 464 aac_rx_get_fwstatus(struct aac_softc *sc) 465 { 466 467 return (AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 468 } 469 470 /* 471 * Notify the controller of a change in a given queue 472 */ 473 474 void 475 aac_sa_qnotify(struct aac_softc *sc, int qbit) 476 { 477 478 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 479 } 480 481 void 482 aac_rx_qnotify(struct aac_softc *sc, int qbit) 483 { 484 485 AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 486 } 487 488 /* 489 * Get the interrupt reason bits 490 */ 491 int 492 aac_sa_get_istatus(struct aac_softc *sc) 493 { 494 495 return (AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 496 } 497 498 int 499 aac_rx_get_istatus(struct aac_softc *sc) 500 { 501 502 return (AAC_GETREG4(sc, AAC_RX_ODBR)); 503 } 504 505 /* 506 * Clear some interrupt reason bits 507 */ 508 void 509 aac_sa_clear_istatus(struct aac_softc *sc, int mask) 510 { 511 512 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 513 } 514 515 void 516 aac_rx_clear_istatus(struct aac_softc *sc, int mask) 517 { 518 519 AAC_SETREG4(sc, AAC_RX_ODBR, mask); 520 } 521 522 /* 523 * Populate the mailbox and set the command word 524 */ 525 void 526 aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 527 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 528 u_int32_t arg3) 529 { 530 531 AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 532 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 533 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 534 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 535 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 536 } 537 538 void 539 aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 540 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 541 u_int32_t arg3) 542 { 543 544 AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 545 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 546 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 547 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 548 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 549 } 550 551 /* 552 * Fetch the immediate command status word 553 */ 554 int 555 aac_sa_get_mailboxstatus(struct aac_softc *sc) 556 { 557 558 return (AAC_GETREG4(sc, AAC_SA_MAILBOX)); 559 } 560 561 int 562 aac_rx_get_mailboxstatus(struct aac_softc *sc) 563 { 564 565 return (AAC_GETREG4(sc, AAC_RX_MAILBOX)); 566 } 567 568 /* 569 * Set/clear interrupt masks 570 */ 571 void 572 aac_sa_set_interrupts(struct aac_softc *sc, int enable) 573 { 574 575 if (enable) 576 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 577 else 578 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 579 } 580 581 void 582 aac_rx_set_interrupts(struct aac_softc *sc, int enable) 583 { 584 585 if (enable) 586 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 587 else 588 AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 589 } 590