1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * PCI-IDE bus nexus driver 29 */ 30 31 #include <sys/types.h> 32 #include <sys/cmn_err.h> 33 #include <sys/conf.h> 34 #include <sys/errno.h> 35 #include <sys/debug.h> 36 #include <sys/ddidmareq.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/dma_engine.h> 39 #include <sys/modctl.h> 40 #include <sys/ddi.h> 41 #include <sys/sunddi.h> 42 #include <sys/sunndi.h> 43 #include <sys/mach_intr.h> 44 #include <sys/kmem.h> 45 #include <sys/pci.h> 46 #include <sys/promif.h> 47 #include <sys/pci_intr_lib.h> 48 49 int pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 50 int pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 51 52 #define PCIIDE_NATIVE_MODE(dip) \ 53 (!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 54 "compatibility-mode")) 55 56 #define PCIIDE_PRE26(dip) \ 57 ddi_prop_exists(DDI_DEV_T_ANY, (dip), 0, "ignore-hardware-nodes") 58 59 #define PCI_IDE_IF_BM_CAP_MASK 0x80 60 61 #define PCIIDE_PDSIZE (sizeof (struct ddi_parent_private_data) + \ 62 sizeof (struct intrspec)) 63 64 #ifdef DEBUG 65 static int pci_ide_debug = 0; 66 #define PDBG(fmt) \ 67 if (pci_ide_debug) { \ 68 prom_printf fmt; \ 69 } 70 #else 71 #define PDBG(fmt) 72 #endif 73 74 #ifndef TRUE 75 #define TRUE 1 76 #endif 77 #ifndef FALSE 78 #define FALSE 0 79 #endif 80 81 /* 82 * bus_ops functions 83 */ 84 85 static int pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, 86 ddi_map_req_t *mp, off_t offset, off_t len, 87 caddr_t *vaddrp); 88 89 static int pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, 90 ddi_ctl_enum_t ctlop, void *arg, 91 void *result); 92 93 static int pciide_get_pri(dev_info_t *dip, dev_info_t *rdip, 94 ddi_intr_handle_impl_t *hdlp, int *pri); 95 96 static int pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, 97 ddi_intr_op_t intr_op, 98 ddi_intr_handle_impl_t *hdlp, void *result); 99 100 static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, 101 int inum); 102 103 /* 104 * Local Functions 105 */ 106 static int pciide_initchild(dev_info_t *mydip, dev_info_t *cdip); 107 108 static void pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, 109 int dev); 110 static int pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber); 111 static int pciide_map_rnumber(int canonical_rnumber, int pri_native, 112 int sec_native); 113 114 115 /* 116 * Config information 117 */ 118 119 struct bus_ops pciide_bus_ops = { 120 BUSO_REV, 121 pciide_bus_map, 122 0, 123 0, 124 0, 125 i_ddi_map_fault, 126 ddi_dma_map, 127 ddi_dma_allochdl, 128 ddi_dma_freehdl, 129 ddi_dma_bindhdl, 130 ddi_dma_unbindhdl, 131 ddi_dma_flush, 132 ddi_dma_win, 133 ddi_dma_mctl, 134 pciide_ddi_ctlops, 135 ddi_bus_prop_op, 136 0, /* (*bus_get_eventcookie)(); */ 137 0, /* (*bus_add_eventcall)(); */ 138 0, /* (*bus_remove_eventcall)(); */ 139 0, /* (*bus_post_event)(); */ 140 0, 141 0, 142 0, 143 0, 144 0, 145 0, 146 0, 147 0, 148 pciide_intr_ops 149 }; 150 151 struct dev_ops pciide_ops = { 152 DEVO_REV, /* devo_rev, */ 153 0, /* refcnt */ 154 ddi_no_info, /* info */ 155 nulldev, /* identify */ 156 nulldev, /* probe */ 157 pciide_attach, /* attach */ 158 pciide_detach, /* detach */ 159 nodev, /* reset */ 160 (struct cb_ops *)0, /* driver operations */ 161 &pciide_bus_ops, /* bus operations */ 162 NULL, /* power */ 163 ddi_quiesce_not_needed, /* quiesce */ 164 }; 165 166 /* 167 * Module linkage information for the kernel. 168 */ 169 170 static struct modldrv modldrv = { 171 &mod_driverops, /* Type of module. This is PCI-IDE bus driver */ 172 "pciide nexus driver for 'PCI-IDE' 1.26", 173 &pciide_ops, /* driver ops */ 174 }; 175 176 static struct modlinkage modlinkage = { 177 MODREV_1, 178 &modldrv, 179 NULL 180 }; 181 182 183 int 184 _init(void) 185 { 186 return (mod_install(&modlinkage)); 187 } 188 189 int 190 _fini(void) 191 { 192 return (mod_remove(&modlinkage)); 193 } 194 195 int 196 _info(struct modinfo *modinfop) 197 { 198 return (mod_info(&modlinkage, modinfop)); 199 } 200 201 int 202 pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 203 { 204 uint16_t cmdreg; 205 ddi_acc_handle_t conf_hdl = NULL; 206 int rc; 207 208 switch (cmd) { 209 case DDI_ATTACH: 210 /* 211 * Make sure bus-mastering is enabled, even if 212 * BIOS didn't. 213 */ 214 rc = pci_config_setup(dip, &conf_hdl); 215 216 /* 217 * In case of error, return SUCCESS. This is because 218 * bus-mastering could be already enabled by BIOS. 219 */ 220 if (rc != DDI_SUCCESS) 221 return (DDI_SUCCESS); 222 223 cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM); 224 if ((cmdreg & PCI_COMM_ME) == 0) { 225 pci_config_put16(conf_hdl, PCI_CONF_COMM, 226 cmdreg | PCI_COMM_ME); 227 } 228 pci_config_teardown(&conf_hdl); 229 return (DDI_SUCCESS); 230 231 case DDI_RESUME: 232 /* Restore our PCI configuration header */ 233 if (pci_restore_config_regs(dip) != DDI_SUCCESS) { 234 /* 235 * XXXX 236 * This is a pretty bad thing. However, for some 237 * reason it always happens. To further complicate 238 * things, it appears if we just ignore this, we 239 * properly resume. For now, all I want to do is 240 * to generate this message so that it doesn't get 241 * forgotten. 242 */ 243 cmn_err(CE_WARN, 244 "Couldn't restore PCI config regs for %s(%p)", 245 ddi_node_name(dip), (void *) dip); 246 } 247 #ifdef DEBUG 248 /* Bus mastering should still be enabled */ 249 if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS) 250 return (DDI_FAILURE); 251 cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM); 252 ASSERT((cmdreg & PCI_COMM_ME) != 0); 253 pci_config_teardown(&conf_hdl); 254 #endif 255 return (DDI_SUCCESS); 256 } 257 258 return (DDI_FAILURE); 259 } 260 261 /*ARGSUSED*/ 262 int 263 pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 264 { 265 switch (cmd) { 266 case DDI_DETACH: 267 return (DDI_SUCCESS); 268 case DDI_SUSPEND: 269 /* Save our PCI configuration header */ 270 if (pci_save_config_regs(dip) != DDI_SUCCESS) { 271 /* Don't suspend if we cannot save config regs */ 272 return (DDI_FAILURE); 273 } 274 return (DDI_SUCCESS); 275 } 276 return (DDI_FAILURE); 277 } 278 279 /*ARGSUSED*/ 280 static int 281 pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 282 void *arg, void *result) 283 { 284 dev_info_t *cdip; 285 int controller; 286 void *pdptr; 287 int rnumber; 288 off_t tmp; 289 int rc; 290 291 PDBG(("pciide_bus_ctl\n")); 292 293 switch (ctlop) { 294 case DDI_CTLOPS_INITCHILD: 295 cdip = (dev_info_t *)arg; 296 return (pciide_initchild(dip, cdip)); 297 298 case DDI_CTLOPS_UNINITCHILD: 299 cdip = (dev_info_t *)arg; 300 pdptr = ddi_get_parent_data(cdip); 301 ddi_set_parent_data(cdip, NULL); 302 ddi_set_name_addr(cdip, NULL); 303 kmem_free(pdptr, PCIIDE_PDSIZE); 304 return (DDI_SUCCESS); 305 306 case DDI_CTLOPS_NREGS: 307 *(int *)result = 3; 308 return (DDI_SUCCESS); 309 310 case DDI_CTLOPS_REGSIZE: 311 /* 312 * Adjust the rnumbers based on which controller instance 313 * is requested; adjust for the 2 tuples per controller. 314 */ 315 if (strcmp("0", ddi_get_name_addr(rdip)) == 0) 316 controller = 0; 317 else 318 controller = 1; 319 320 321 switch (rnumber = *(int *)arg) { 322 case 0: 323 case 1: 324 rnumber += (2 * controller); 325 break; 326 case 2: 327 rnumber = 4; 328 break; 329 default: 330 PDBG(("pciide_ctlops invalid rnumber\n")); 331 return (DDI_FAILURE); 332 } 333 334 335 if (PCIIDE_PRE26(dip)) { 336 int old_rnumber; 337 int new_rnumber; 338 339 old_rnumber = rnumber; 340 new_rnumber 341 = pciide_pre26_rnumber_map(dip, old_rnumber); 342 PDBG(("pciide rnumber old %d new %d\n", 343 old_rnumber, new_rnumber)); 344 rnumber = new_rnumber; 345 } 346 347 /* 348 * Add 1 to skip over the PCI config space tuple 349 */ 350 rnumber++; 351 352 /* 353 * If it's not tuple #2 pass the adjusted request to my parent 354 */ 355 if (*(int *)arg != 2) { 356 return (ddi_ctlops(dip, dip, ctlop, &rnumber, result)); 357 } 358 359 /* 360 * Handle my child's reg-tuple #2 here by splitting my 16 byte 361 * reg-tuple #4 into two 8 byte ranges based on the 362 * the child's controller #. 363 */ 364 365 tmp = 8; 366 rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp); 367 368 /* 369 * Allow for the possibility of less than 16 bytes by 370 * by checking what's actually returned for my reg-tuple #4. 371 */ 372 if (controller == 1) { 373 if (tmp < 8) 374 tmp = 0; 375 else 376 tmp -= 8; 377 } 378 if (tmp > 8) 379 tmp = 8; 380 *(off_t *)result = tmp; 381 382 return (rc); 383 384 case DDI_CTLOPS_ATTACH: 385 case DDI_CTLOPS_DETACH: 386 /* 387 * Don't pass child ide ATTACH/DETACH to parent 388 */ 389 return (DDI_SUCCESS); 390 391 default: 392 return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 393 } 394 } 395 396 /* 397 * IEEE 1275 Working Group Proposal #414 says that the Primary 398 * controller is "ata@0" and the Secondary controller "ata@1". 399 * 400 * By the time we get here, boot Bootconf (2.6+) has created devinfo 401 * nodes with the appropriate "reg", "assigned-addresses" and "interrupts" 402 * properites on the pci-ide node and both ide child nodes. 403 * 404 * In compatibility mode the "reg" and "assigned-addresses" properties 405 * of the pci-ide node are set up like this: 406 * 407 * 1. PCI-IDE Nexus 408 * 409 * interrupts=0 410 * (addr-hi addr-mid addr-low size-hi size-low) 411 * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000 412 * 81000000.00000000.000001f0.00000000.00000008 413 * 81000000.00000000.000003f4.00000000.00000004 414 * 81000000.00000000,00000170.00000000.00000008 415 * 81000000.00000000,00000374.00000000.00000004 416 * 01000020.00000000,-[BAR4]-.00000000.00000010 417 * 418 * In native PCI mode the "reg" and "assigned-addresses" properties 419 * would be set up like this: 420 * 421 * 2. PCI-IDE Nexus 422 * 423 * interrupts=0 424 * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000 425 * 01000010.00000000.-[BAR0]-.00000000.00000008 426 * 01000014,00000000.-[BAR1]-.00000000.00000004 427 * 01000018.00000000.-[BAR2]-.00000000.00000008 428 * 0100001c.00000000.-[BAR3]-.00000000.00000004 429 * 01000020.00000000.-[BAR4]-.00000000.00000010 430 * 431 * 432 * In both modes the child nodes simply have the following: 433 * 434 * 2. primary controller (compatibility mode) 435 * 436 * interrupts=14 437 * reg=00000000 438 * 439 * 3. secondary controller 440 * 441 * interrupts=15 442 * reg=00000001 443 * 444 * The pciide_bus_map() function is responsible for turning requests 445 * to map primary or secondary controller rnumbers into mapping requests 446 * of the appropriate regspec on the pci-ide node. 447 * 448 */ 449 450 static int 451 pciide_initchild(dev_info_t *mydip, dev_info_t *cdip) 452 { 453 struct ddi_parent_private_data *pdptr; 454 struct intrspec *ispecp; 455 int vec; 456 int *rp; 457 uint_t proplen; 458 char name[80]; 459 int dev; 460 461 PDBG(("pciide_initchild\n")); 462 463 /* 464 * Set the address portion of the node name based on 465 * the controller number (0 or 1) from the 'reg' property. 466 */ 467 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 468 "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) { 469 PDBG(("pciide_intchild prop error\n")); 470 return (DDI_NOT_WELL_FORMED); 471 } 472 473 /* 474 * copy the controller number and 475 * free the memory allocated by ddi_prop_lookup_int_array 476 */ 477 dev = *rp; 478 ddi_prop_free(rp); 479 480 /* 481 * I only support two controllers per device, determine 482 * which this one is and set its unit address. 483 */ 484 if (dev > 1) { 485 PDBG(("pciide_initchild bad dev\n")); 486 return (DDI_NOT_WELL_FORMED); 487 } 488 (void) sprintf(name, "%d", dev); 489 ddi_set_name_addr(cdip, name); 490 491 /* 492 * determine if this instance is running in native or compat mode 493 */ 494 pciide_compat_setup(mydip, cdip, dev); 495 496 /* interrupts property is required */ 497 if (PCIIDE_NATIVE_MODE(cdip)) { 498 vec = 1; 499 } else { 500 /* 501 * In compatibility mode, dev 0 should always be 502 * IRQ 14 and dev 1 is IRQ 15. If for some reason 503 * this needs to be changed, do it via the interrupts 504 * property in the ata.conf file. 505 */ 506 vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 507 "interrupts", -1); 508 if (vec == -1) { 509 /* setup compatibility mode interrupts */ 510 if (dev == 0) { 511 vec = 14; 512 } else if (dev == 1) { 513 vec = 15; 514 } else { 515 PDBG(("pciide_initchild bad intr\n")); 516 return (DDI_NOT_WELL_FORMED); 517 } 518 } 519 } 520 521 pdptr = kmem_zalloc(PCIIDE_PDSIZE, KM_SLEEP); 522 ispecp = (struct intrspec *)(pdptr + 1); 523 pdptr->par_nintr = 1; 524 pdptr->par_intr = ispecp; 525 ispecp->intrspec_vec = vec; 526 ddi_set_parent_data(cdip, pdptr); 527 528 PDBG(("pciide_initchild okay\n")); 529 return (DDI_SUCCESS); 530 } 531 532 static int 533 pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 534 off_t offset, off_t len, caddr_t *vaddrp) 535 { 536 dev_info_t *pdip; 537 int rnumber = mp->map_obj.rnumber; 538 int controller; 539 int rc; 540 541 PDBG(("pciide_bus_map\n")); 542 543 if (strcmp("0", ddi_get_name_addr(rdip)) == 0) 544 controller = 0; 545 else 546 controller = 1; 547 548 /* 549 * Adjust the rnumbers based on which controller instance 550 * is being mapped; adjust for the 2 tuples per controller. 551 */ 552 553 switch (rnumber) { 554 case 0: 555 case 1: 556 mp->map_obj.rnumber += (controller * 2); 557 break; 558 case 2: 559 /* 560 * split the 16 I/O ports into two 8 port ranges 561 */ 562 mp->map_obj.rnumber = 4; 563 if (offset + len > 8) { 564 PDBG(("pciide_bus_map offset\n")); 565 return (DDI_FAILURE); 566 } 567 if (len == 0) 568 len = 8 - offset; 569 offset += 8 * controller; 570 break; 571 default: 572 PDBG(("pciide_bus_map default\n")); 573 return (DDI_FAILURE); 574 } 575 576 if (PCIIDE_PRE26(dip)) { 577 int old_rnumber; 578 int new_rnumber; 579 580 old_rnumber = mp->map_obj.rnumber; 581 new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber); 582 PDBG(("pciide rnumber old %d new %d\n", 583 old_rnumber, new_rnumber)); 584 mp->map_obj.rnumber = new_rnumber; 585 } 586 587 /* 588 * Add 1 to skip over the PCI config space tuple 589 */ 590 mp->map_obj.rnumber++; 591 592 593 /* 594 * pass the adjusted request to my parent 595 */ 596 pdip = ddi_get_parent(dip); 597 rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)) 598 (pdip, dip, mp, offset, len, vaddrp)); 599 600 PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok")); 601 602 return (rc); 603 } 604 605 606 static struct intrspec * 607 pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber) 608 { 609 struct ddi_parent_private_data *ppdptr; 610 611 PDBG(("pciide_get_ispec\n")); 612 613 /* 614 * Native mode PCI-IDE controllers share the parent's 615 * PCI interrupt line. 616 * 617 * Compatibility mode PCI-IDE controllers have their 618 * own intrspec which specifies ISA IRQ 14 or 15. 619 * 620 */ 621 if (PCIIDE_NATIVE_MODE(rdip)) { 622 ddi_intrspec_t is; 623 624 is = pci_intx_get_ispec(dip, dip, inumber); 625 PDBG(("pciide_get_ispec okay\n")); 626 return ((struct intrspec *)is); 627 } 628 629 /* Else compatibility mode, use the ISA IRQ */ 630 if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) { 631 PDBG(("pciide_get_ispec null\n")); 632 return (NULL); 633 } 634 635 /* validate the interrupt number */ 636 if (inumber >= ppdptr->par_nintr) { 637 PDBG(("pciide_get_inum\n")); 638 return (NULL); 639 } 640 641 PDBG(("pciide_get_ispec ok\n")); 642 643 return ((struct intrspec *)&ppdptr->par_intr[inumber]); 644 } 645 646 static int 647 pciide_get_pri(dev_info_t *dip, dev_info_t *rdip, 648 ddi_intr_handle_impl_t *hdlp, int *pri) 649 { 650 struct intrspec *ispecp; 651 int *intpriorities; 652 uint_t num_intpriorities; 653 654 PDBG(("pciide_get_pri\n")); 655 656 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) { 657 PDBG(("pciide_get_pri null\n")); 658 return (DDI_FAILURE); 659 } 660 661 if (PCIIDE_NATIVE_MODE(rdip)) { 662 *pri = ispecp->intrspec_pri; 663 PDBG(("pciide_get_pri ok\n")); 664 return (DDI_SUCCESS); 665 } 666 667 /* check if the intrspec has been initialized */ 668 if (ispecp->intrspec_pri != 0) { 669 *pri = ispecp->intrspec_pri; 670 PDBG(("pciide_get_pri ok2\n")); 671 return (DDI_SUCCESS); 672 } 673 674 /* Use a default of level 5 */ 675 ispecp->intrspec_pri = 5; 676 677 /* 678 * If there's an interrupt-priorities property, use it to 679 * over-ride the default interrupt priority. 680 */ 681 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 682 "interrupt-priorities", &intpriorities, &num_intpriorities) == 683 DDI_PROP_SUCCESS) { 684 if (hdlp->ih_inum < num_intpriorities) 685 ispecp->intrspec_pri = intpriorities[hdlp->ih_inum]; 686 ddi_prop_free(intpriorities); 687 } 688 *pri = ispecp->intrspec_pri; 689 690 PDBG(("pciide_get_pri ok3\n")); 691 692 return (DDI_SUCCESS); 693 } 694 695 static int 696 pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 697 ddi_intr_handle_impl_t *hdlp, void *result) 698 { 699 struct intrspec *ispecp; 700 int rc; 701 int pri = 0; 702 703 PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n", 704 (void *)dip, (void *)rdip, intr_op, (void *)hdlp)); 705 706 switch (intr_op) { 707 case DDI_INTROP_SUPPORTED_TYPES: 708 *(int *)result = DDI_INTR_TYPE_FIXED; 709 break; 710 case DDI_INTROP_GETCAP: 711 *(int *)result = DDI_INTR_FLAG_LEVEL; 712 break; 713 case DDI_INTROP_NINTRS: 714 case DDI_INTROP_NAVAIL: 715 *(int *)result = (!PCIIDE_NATIVE_MODE(rdip)) ? 716 i_ddi_get_intx_nintrs(rdip) : 1; 717 break; 718 case DDI_INTROP_ALLOC: 719 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == 720 NULL) 721 return (DDI_FAILURE); 722 *(int *)result = hdlp->ih_scratch1; 723 break; 724 case DDI_INTROP_FREE: 725 break; 726 case DDI_INTROP_GETPRI: 727 if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) { 728 *(int *)result = 0; 729 return (DDI_FAILURE); 730 } 731 *(int *)result = pri; 732 break; 733 case DDI_INTROP_ADDISR: 734 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == 735 NULL) 736 return (DDI_FAILURE); 737 ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 738 ispecp->intrspec_func = hdlp->ih_cb_func; 739 break; 740 case DDI_INTROP_REMISR: 741 if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == 742 NULL) 743 return (DDI_FAILURE); 744 ispecp->intrspec_func = (uint_t (*)()) 0; 745 break; 746 case DDI_INTROP_ENABLE: 747 /* FALLTHRU */ 748 case DDI_INTROP_DISABLE: 749 if (PCIIDE_NATIVE_MODE(rdip)) { 750 rdip = dip; 751 dip = ddi_get_parent(dip); 752 } else { /* get ptr to the root node */ 753 dip = ddi_root_node(); 754 } 755 756 rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip, 757 rdip, intr_op, hdlp, result); 758 759 #ifdef DEBUG 760 if (intr_op == DDI_INTROP_ENABLE) { 761 PDBG(("pciide_enable rc=%d", rc)); 762 } else 763 PDBG(("pciide_disable rc=%d", rc)); 764 #endif /* DEBUG */ 765 return (rc); 766 default: 767 return (DDI_FAILURE); 768 } 769 770 return (DDI_SUCCESS); 771 } 772 773 /* 774 * This is one of the places where controller specific setup needs to be 775 * considered. 776 * At this point the controller was already pre-qualified as a known and 777 * supported pciide controller. 778 * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE 779 * programming interface code but rather PCI_MASS_OTHER sub-class code 780 * without any additional data. 781 * For those controllers IDE programming interface cannot be extracted 782 * from PCI class - we assume that they are pci-native type and we fix 783 * the programming interface used by other functions. 784 * The programming interface byte is set to indicate pci-native mode 785 * for both controllers and the Bus Master DMA capabilitiy of the controller. 786 */ 787 static void 788 pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev) 789 { 790 int class_code; 791 int rc = DDI_PROP_SUCCESS; 792 793 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, 794 DDI_PROP_DONTPASS, "class-code", 0); 795 796 if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) { 797 /* 798 * Controller provides PCI_MASS_IDE sub-class code first 799 * (implied IDE programming interface) 800 */ 801 if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) || 802 (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) { 803 rc = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, 804 "compatibility-mode", 1); 805 if (rc != DDI_PROP_SUCCESS) 806 cmn_err(CE_WARN, 807 "pciide prop error %d compat-mode", rc); 808 } 809 } else { 810 /* 811 * Pci-ide controllers not providing PCI_MASS_IDE sub-class are 812 * assumed to be of pci-native type and bus master DMA capable. 813 * Programming interface part of the class-code property is 814 * fixed here. 815 */ 816 class_code &= 0x00ffff00; 817 class_code |= PCI_IDE_IF_BM_CAP_MASK | 818 PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC; 819 rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip, 820 "class-code", class_code); 821 if (rc != DDI_PROP_SUCCESS) 822 cmn_err(CE_WARN, 823 "pciide prop error %d class-code", rc); 824 } 825 } 826 827 828 static int 829 pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber) 830 { 831 int pri_native; 832 int sec_native; 833 int class_code; 834 835 class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS, 836 "class-code", 0); 837 838 pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE; 839 sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE; 840 841 return (pciide_map_rnumber(rnumber, pri_native, sec_native)); 842 843 } 844 845 /* 846 * The canonical order of the reg property tuples for the 847 * Base Address Registers is supposed to be: 848 * 849 * primary controller (BAR 0) 850 * primary controller (BAR 1) 851 * secondary controller (BAR 2) 852 * secondary controller (BAR 3) 853 * bus mastering regs (BAR 4) 854 * 855 * For 2.6, bootconf has been fixed to always generate the 856 * reg property (and assigned-addresses property) tuples 857 * in the above order. 858 * 859 * But in releases prior to 2.6 the order varies depending 860 * on whether compatibility or native mode is being used for 861 * each controller. There ends up being four possible 862 * orders: 863 * 864 * BM, P0, P1, S0, S1 primary compatible, secondary compatible 865 * S0, S1, BM, P0, P1 primary compatible, secondary native 866 * P0, P1, BM, S0, S1 primary native, secondary compatible 867 * P0, P1, S0, S1, BM primary native, secondary native 868 * 869 * where: Px is the primary tuples, Sx the secondary tuples, and 870 * B the Bus Master tuple. 871 * 872 * Here's the results for each of the four states: 873 * 874 * 0, 1, 2, 3, 4 875 * 876 * CC 1, 2, 3, 4, 0 877 * CN 3, 4, 0, 1, 2 878 * NC 0, 1, 3, 4, 2 879 * NN 0, 1, 2, 3, 4 880 * 881 * C = compatible(!native) == 0 882 * N = native == 1 883 * 884 * Here's the transformation matrix: 885 */ 886 887 static int pciide_transform[2][2][5] = { 888 /* P S */ 889 /* [C][C] */ +1, +1, +1, +1, -4, 890 /* [C][N] */ +3, +3, -2, -2, -2, 891 /* [N][C] */ +0, +0, +1, +1, -2, 892 /* [N][N] */ +0, +0, +0, +0, +0 893 }; 894 895 896 static int 897 pciide_map_rnumber(int rnumber, int pri_native, int sec_native) 898 { 899 /* transform flags into indexes */ 900 pri_native = pri_native ? 1 : 0; 901 sec_native = sec_native ? 1 : 0; 902 903 rnumber += pciide_transform[pri_native][sec_native][rnumber]; 904 return (rnumber); 905 } 906