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