1 /* $NetBSD: aac_pci.c,v 1.3 2002/08/02 12:44:43 ad 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.3 2002/08/02 12:44:43 ad 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 struct cfattach aac_pci_ca = { 313 sizeof(struct aac_softc), aac_pci_match, aac_pci_attach 314 }; 315 316 const struct aac_ident * 317 aac_find_ident(struct pci_attach_args *pa) 318 { 319 const struct aac_ident *m, *mm; 320 u_int32_t subsysid; 321 322 m = aac_ident; 323 mm = aac_ident + (sizeof(aac_ident) / sizeof(aac_ident[0])); 324 325 while (m < mm) { 326 if (m->vendor == PCI_VENDOR(pa->pa_id) && 327 m->device == PCI_PRODUCT(pa->pa_id)) { 328 subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, 329 PCI_SUBSYS_ID_REG); 330 if (m->subvendor == PCI_VENDOR(subsysid) && 331 m->subdevice == PCI_PRODUCT(subsysid)) 332 return (m); 333 } 334 m++; 335 } 336 337 return (NULL); 338 } 339 340 int 341 aac_pci_match(struct device *parent, struct cfdata *match, void *aux) 342 { 343 struct pci_attach_args *pa; 344 345 pa = aux; 346 347 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O) 348 return (0); 349 350 return (aac_find_ident(pa) != NULL); 351 } 352 353 void 354 aac_pci_attach(struct device *parent, struct device *self, void *aux) 355 { 356 struct pci_attach_args *pa; 357 pci_chipset_tag_t pc; 358 struct aac_softc *sc; 359 u_int16_t command; 360 bus_addr_t membase; 361 bus_size_t memsize; 362 pci_intr_handle_t ih; 363 const char *intrstr; 364 int state; 365 const struct aac_ident *m; 366 367 pa = aux; 368 pc = pa->pa_pc; 369 sc = (struct aac_softc *)self; 370 state = 0; 371 372 printf(": "); 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 printf("can't enable bus-master feature\n"); 385 goto bail_out; 386 } 387 388 if ((command & PCI_COMMAND_MEM_ENABLE) == 0) { 389 printf("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 printf("can't find mem space\n"); 400 goto bail_out; 401 } 402 state++; 403 404 if (pci_intr_map(pa, &ih)) { 405 printf("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 printf("couldn't establish interrupt"); 412 if (intrstr != NULL) 413 printf(" at %s", intrstr); 414 printf("\n"); 415 goto bail_out; 416 } 417 state++; 418 419 sc->sc_dmat = pa->pa_dmat; 420 421 m = aac_find_ident(pa); 422 printf("%s\n", m->prodstr); 423 if (intrstr != NULL) 424 printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr); 425 426 sc->sc_hwif = m->hwif; 427 sc->sc_quirks = m->quirks; 428 switch (sc->sc_hwif) { 429 case AAC_HWIF_I960RX: 430 AAC_DPRINTF(AAC_D_MISC, 431 ("set hardware up for i960Rx")); 432 sc->sc_if = aac_rx_interface; 433 break; 434 435 case AAC_HWIF_STRONGARM: 436 AAC_DPRINTF(AAC_D_MISC, 437 ("set hardware up for StrongARM")); 438 sc->sc_if = aac_sa_interface; 439 break; 440 } 441 442 if (!aac_attach(sc)) 443 return; 444 445 bail_out: 446 if (state > 1) 447 pci_intr_disestablish(pc, sc->sc_ih); 448 if (state > 0) 449 bus_space_unmap(sc->sc_memt, sc->sc_memh, memsize); 450 } 451 452 /* 453 * Read the current firmware status word. 454 */ 455 int 456 aac_sa_get_fwstatus(struct aac_softc *sc) 457 { 458 459 return (AAC_GETREG4(sc, AAC_SA_FWSTATUS)); 460 } 461 462 int 463 aac_rx_get_fwstatus(struct aac_softc *sc) 464 { 465 466 return (AAC_GETREG4(sc, AAC_RX_FWSTATUS)); 467 } 468 469 /* 470 * Notify the controller of a change in a given queue 471 */ 472 473 void 474 aac_sa_qnotify(struct aac_softc *sc, int qbit) 475 { 476 477 AAC_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); 478 } 479 480 void 481 aac_rx_qnotify(struct aac_softc *sc, int qbit) 482 { 483 484 AAC_SETREG4(sc, AAC_RX_IDBR, qbit); 485 } 486 487 /* 488 * Get the interrupt reason bits 489 */ 490 int 491 aac_sa_get_istatus(struct aac_softc *sc) 492 { 493 494 return (AAC_GETREG2(sc, AAC_SA_DOORBELL0)); 495 } 496 497 int 498 aac_rx_get_istatus(struct aac_softc *sc) 499 { 500 501 return (AAC_GETREG4(sc, AAC_RX_ODBR)); 502 } 503 504 /* 505 * Clear some interrupt reason bits 506 */ 507 void 508 aac_sa_clear_istatus(struct aac_softc *sc, int mask) 509 { 510 511 AAC_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); 512 } 513 514 void 515 aac_rx_clear_istatus(struct aac_softc *sc, int mask) 516 { 517 518 AAC_SETREG4(sc, AAC_RX_ODBR, mask); 519 } 520 521 /* 522 * Populate the mailbox and set the command word 523 */ 524 void 525 aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, 526 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 527 u_int32_t arg3) 528 { 529 530 AAC_SETREG4(sc, AAC_SA_MAILBOX, command); 531 AAC_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); 532 AAC_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); 533 AAC_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); 534 AAC_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); 535 } 536 537 void 538 aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, 539 u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, 540 u_int32_t arg3) 541 { 542 543 AAC_SETREG4(sc, AAC_RX_MAILBOX, command); 544 AAC_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); 545 AAC_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); 546 AAC_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); 547 AAC_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); 548 } 549 550 /* 551 * Fetch the immediate command status word 552 */ 553 int 554 aac_sa_get_mailboxstatus(struct aac_softc *sc) 555 { 556 557 return (AAC_GETREG4(sc, AAC_SA_MAILBOX)); 558 } 559 560 int 561 aac_rx_get_mailboxstatus(struct aac_softc *sc) 562 { 563 564 return (AAC_GETREG4(sc, AAC_RX_MAILBOX)); 565 } 566 567 /* 568 * Set/clear interrupt masks 569 */ 570 void 571 aac_sa_set_interrupts(struct aac_softc *sc, int enable) 572 { 573 574 if (enable) 575 AAC_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); 576 else 577 AAC_SETREG2((sc), AAC_SA_MASK0_SET, ~0); 578 } 579 580 void 581 aac_rx_set_interrupts(struct aac_softc *sc, int enable) 582 { 583 584 if (enable) 585 AAC_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); 586 else 587 AAC_SETREG4(sc, AAC_RX_OIMR, ~0); 588 } 589