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