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