1 /* $NetBSD: aac_pci.c,v 1.6 2002/10/02 16:50:59 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.6 2002/10/02 16:50:59 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 printf(": "); 372 373 /* 374 * Verify that the adapter is correctly set up in PCI space. 375 */ 376 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 377 command |= PCI_COMMAND_MASTER_ENABLE; 378 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); 379 command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); 380 AAC_DPRINTF(AAC_D_MISC, ("pci command status reg 0x08x ")); 381 382 if ((command & PCI_COMMAND_MASTER_ENABLE) == 0) { 383 printf("can't enable bus-master feature\n"); 384 goto bail_out; 385 } 386 387 if ((command & PCI_COMMAND_MEM_ENABLE) == 0) { 388 printf("memory window not available\n"); 389 goto bail_out; 390 } 391 392 /* 393 * Map control/status registers. 394 */ 395 if (pci_mapreg_map(pa, PCI_MAPREG_START, 396 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->sc_memt, 397 &sc->sc_memh, &membase, &memsize)) { 398 printf("can't find mem space\n"); 399 goto bail_out; 400 } 401 state++; 402 403 if (pci_intr_map(pa, &ih)) { 404 printf("couldn't map interrupt\n"); 405 goto bail_out; 406 } 407 intrstr = pci_intr_string(pc, ih); 408 sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, aac_intr, sc); 409 if (sc->sc_ih == NULL) { 410 printf("couldn't establish interrupt"); 411 if (intrstr != NULL) 412 printf(" at %s", intrstr); 413 printf("\n"); 414 goto bail_out; 415 } 416 state++; 417 418 sc->sc_dmat = pa->pa_dmat; 419 420 m = aac_find_ident(pa); 421 printf("%s\n", m->prodstr); 422 if (intrstr != NULL) 423 printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr); 424 425 sc->sc_hwif = m->hwif; 426 sc->sc_quirks = m->quirks; 427 switch (sc->sc_hwif) { 428 case AAC_HWIF_I960RX: 429 AAC_DPRINTF(AAC_D_MISC, 430 ("set hardware up for i960Rx")); 431 sc->sc_if = aac_rx_interface; 432 break; 433 434 case AAC_HWIF_STRONGARM: 435 AAC_DPRINTF(AAC_D_MISC, 436 ("set hardware up for StrongARM")); 437 sc->sc_if = aac_sa_interface; 438 break; 439 } 440 441 if (!aac_attach(sc)) 442 return; 443 444 bail_out: 445 if (state > 1) 446 pci_intr_disestablish(pc, sc->sc_ih); 447 if (state > 0) 448 bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize); 449 } 450 451 /* 452 * Read the current firmware status word. 453 */ 454 int 455 aac_sa_get_fwstatus(struct aac_softc *sc) 456 { 457 458 return (AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 459 } 460 461 int 462 aac_rx_get_fwstatus(struct aac_softc *sc) 463 { 464 465 return (AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 466 } 467 468 /* 469 * Notify the controller of a change in a given queue 470 */ 471 472 void 473 aac_sa_qnotify(struct aac_softc *sc, int qbit) 474 { 475 476 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 477 } 478 479 void 480 aac_rx_qnotify(struct aac_softc *sc, int qbit) 481 { 482 483 AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 484 } 485 486 /* 487 * Get the interrupt reason bits 488 */ 489 int 490 aac_sa_get_istatus(struct aac_softc *sc) 491 { 492 493 return (AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 494 } 495 496 int 497 aac_rx_get_istatus(struct aac_softc *sc) 498 { 499 500 return (AAC_GETREG4(sc, AAC_RX_ODBR)); 501 } 502 503 /* 504 * Clear some interrupt reason bits 505 */ 506 void 507 aac_sa_clear_istatus(struct aac_softc *sc, int mask) 508 { 509 510 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 511 } 512 513 void 514 aac_rx_clear_istatus(struct aac_softc *sc, int mask) 515 { 516 517 AAC_SETREG4(sc, AAC_RX_ODBR, mask); 518 } 519 520 /* 521 * Populate the mailbox and set the command word 522 */ 523 void 524 aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 525 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 526 u_int32_t arg3) 527 { 528 529 AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 530 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 531 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 532 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 533 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 534 } 535 536 void 537 aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 538 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 539 u_int32_t arg3) 540 { 541 542 AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 543 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 544 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 545 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 546 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 547 } 548 549 /* 550 * Fetch the immediate command status word 551 */ 552 int 553 aac_sa_get_mailboxstatus(struct aac_softc *sc) 554 { 555 556 return (AAC_GETREG4(sc, AAC_SA_MAILBOX)); 557 } 558 559 int 560 aac_rx_get_mailboxstatus(struct aac_softc *sc) 561 { 562 563 return (AAC_GETREG4(sc, AAC_RX_MAILBOX)); 564 } 565 566 /* 567 * Set/clear interrupt masks 568 */ 569 void 570 aac_sa_set_interrupts(struct aac_softc *sc, int enable) 571 { 572 573 if (enable) 574 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 575 else 576 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 577 } 578 579 void 580 aac_rx_set_interrupts(struct aac_softc *sc, int enable) 581 { 582 583 if (enable) 584 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 585 else 586 AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 587 } 588