10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52580Sanish * Common Development and Distribution License (the "License"). 62580Sanish * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*12683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * PCI-IDE bus nexus driver 280Sstevel@tonic-gate */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/types.h> 310Sstevel@tonic-gate #include <sys/cmn_err.h> 320Sstevel@tonic-gate #include <sys/conf.h> 330Sstevel@tonic-gate #include <sys/errno.h> 340Sstevel@tonic-gate #include <sys/debug.h> 350Sstevel@tonic-gate #include <sys/ddidmareq.h> 360Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 370Sstevel@tonic-gate #include <sys/dma_engine.h> 380Sstevel@tonic-gate #include <sys/modctl.h> 390Sstevel@tonic-gate #include <sys/ddi.h> 400Sstevel@tonic-gate #include <sys/sunddi.h> 418419SKerry.Shu@Sun.COM #include <sys/sunndi.h> 42916Sschwartz #include <sys/mach_intr.h> 430Sstevel@tonic-gate #include <sys/kmem.h> 440Sstevel@tonic-gate #include <sys/pci.h> 450Sstevel@tonic-gate #include <sys/promif.h> 460Sstevel@tonic-gate #include <sys/pci_intr_lib.h> 47*12683SJimmy.Vetayases@oracle.com #include <sys/apic.h> 480Sstevel@tonic-gate 490Sstevel@tonic-gate int pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 505295Srandyf int pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 510Sstevel@tonic-gate 520Sstevel@tonic-gate #define PCIIDE_NATIVE_MODE(dip) \ 530Sstevel@tonic-gate (!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \ 540Sstevel@tonic-gate "compatibility-mode")) 550Sstevel@tonic-gate 560Sstevel@tonic-gate #define PCIIDE_PRE26(dip) \ 570Sstevel@tonic-gate ddi_prop_exists(DDI_DEV_T_ANY, (dip), 0, "ignore-hardware-nodes") 580Sstevel@tonic-gate 590Sstevel@tonic-gate #define PCI_IDE_IF_BM_CAP_MASK 0x80 600Sstevel@tonic-gate 61430Smrj #define PCIIDE_PDSIZE (sizeof (struct ddi_parent_private_data) + \ 62430Smrj sizeof (struct intrspec)) 63430Smrj 640Sstevel@tonic-gate #ifdef DEBUG 650Sstevel@tonic-gate static int pci_ide_debug = 0; 660Sstevel@tonic-gate #define PDBG(fmt) \ 670Sstevel@tonic-gate if (pci_ide_debug) { \ 680Sstevel@tonic-gate prom_printf fmt; \ 690Sstevel@tonic-gate } 700Sstevel@tonic-gate #else 710Sstevel@tonic-gate #define PDBG(fmt) 720Sstevel@tonic-gate #endif 730Sstevel@tonic-gate 740Sstevel@tonic-gate #ifndef TRUE 750Sstevel@tonic-gate #define TRUE 1 760Sstevel@tonic-gate #endif 770Sstevel@tonic-gate #ifndef FALSE 780Sstevel@tonic-gate #define FALSE 0 790Sstevel@tonic-gate #endif 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * bus_ops functions 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate static int pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, 860Sstevel@tonic-gate ddi_map_req_t *mp, off_t offset, off_t len, 870Sstevel@tonic-gate caddr_t *vaddrp); 880Sstevel@tonic-gate 890Sstevel@tonic-gate static int pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, 900Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, 910Sstevel@tonic-gate void *result); 920Sstevel@tonic-gate 930Sstevel@tonic-gate static int pciide_get_pri(dev_info_t *dip, dev_info_t *rdip, 940Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, int *pri); 950Sstevel@tonic-gate 960Sstevel@tonic-gate static int pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, 970Sstevel@tonic-gate ddi_intr_op_t intr_op, 980Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result); 990Sstevel@tonic-gate 1000Sstevel@tonic-gate static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, 1010Sstevel@tonic-gate int inum); 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * Local Functions 1050Sstevel@tonic-gate */ 1060Sstevel@tonic-gate static int pciide_initchild(dev_info_t *mydip, dev_info_t *cdip); 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static void pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, 1090Sstevel@tonic-gate int dev); 1100Sstevel@tonic-gate static int pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber); 1110Sstevel@tonic-gate static int pciide_map_rnumber(int canonical_rnumber, int pri_native, 1120Sstevel@tonic-gate int sec_native); 113*12683SJimmy.Vetayases@oracle.com static int pciide_alloc_intr(dev_info_t *, dev_info_t *, 114*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *, void *); 115*12683SJimmy.Vetayases@oracle.com static int pciide_free_intr(dev_info_t *, dev_info_t *, 116*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *); 1170Sstevel@tonic-gate 118*12683SJimmy.Vetayases@oracle.com extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *, 119*12683SJimmy.Vetayases@oracle.com psm_intr_op_t, int *); 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * Config information 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate struct bus_ops pciide_bus_ops = { 1260Sstevel@tonic-gate BUSO_REV, 1270Sstevel@tonic-gate pciide_bus_map, 1280Sstevel@tonic-gate 0, 1290Sstevel@tonic-gate 0, 1300Sstevel@tonic-gate 0, 1310Sstevel@tonic-gate i_ddi_map_fault, 1320Sstevel@tonic-gate ddi_dma_map, 1330Sstevel@tonic-gate ddi_dma_allochdl, 1340Sstevel@tonic-gate ddi_dma_freehdl, 1350Sstevel@tonic-gate ddi_dma_bindhdl, 1360Sstevel@tonic-gate ddi_dma_unbindhdl, 1370Sstevel@tonic-gate ddi_dma_flush, 1380Sstevel@tonic-gate ddi_dma_win, 1390Sstevel@tonic-gate ddi_dma_mctl, 1400Sstevel@tonic-gate pciide_ddi_ctlops, 1410Sstevel@tonic-gate ddi_bus_prop_op, 1420Sstevel@tonic-gate 0, /* (*bus_get_eventcookie)(); */ 1430Sstevel@tonic-gate 0, /* (*bus_add_eventcall)(); */ 1440Sstevel@tonic-gate 0, /* (*bus_remove_eventcall)(); */ 1450Sstevel@tonic-gate 0, /* (*bus_post_event)(); */ 1460Sstevel@tonic-gate 0, 1470Sstevel@tonic-gate 0, 1480Sstevel@tonic-gate 0, 1490Sstevel@tonic-gate 0, 1500Sstevel@tonic-gate 0, 1510Sstevel@tonic-gate 0, 1520Sstevel@tonic-gate 0, 1530Sstevel@tonic-gate 0, 1540Sstevel@tonic-gate pciide_intr_ops 1550Sstevel@tonic-gate }; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate struct dev_ops pciide_ops = { 1580Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 1590Sstevel@tonic-gate 0, /* refcnt */ 1600Sstevel@tonic-gate ddi_no_info, /* info */ 1610Sstevel@tonic-gate nulldev, /* identify */ 1620Sstevel@tonic-gate nulldev, /* probe */ 1630Sstevel@tonic-gate pciide_attach, /* attach */ 1645295Srandyf pciide_detach, /* detach */ 1650Sstevel@tonic-gate nodev, /* reset */ 1660Sstevel@tonic-gate (struct cb_ops *)0, /* driver operations */ 1677656SSherry.Moore@Sun.COM &pciide_bus_ops, /* bus operations */ 1687656SSherry.Moore@Sun.COM NULL, /* power */ 1697656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */ 1700Sstevel@tonic-gate }; 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate /* 1730Sstevel@tonic-gate * Module linkage information for the kernel. 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate static struct modldrv modldrv = { 1770Sstevel@tonic-gate &mod_driverops, /* Type of module. This is PCI-IDE bus driver */ 1787656SSherry.Moore@Sun.COM "pciide nexus driver for 'PCI-IDE' 1.26", 1790Sstevel@tonic-gate &pciide_ops, /* driver ops */ 1800Sstevel@tonic-gate }; 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate static struct modlinkage modlinkage = { 1830Sstevel@tonic-gate MODREV_1, 1840Sstevel@tonic-gate &modldrv, 1850Sstevel@tonic-gate NULL 1860Sstevel@tonic-gate }; 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate int 1900Sstevel@tonic-gate _init(void) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate return (mod_install(&modlinkage)); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate int 1960Sstevel@tonic-gate _fini(void) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate return (mod_remove(&modlinkage)); 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate int 2020Sstevel@tonic-gate _info(struct modinfo *modinfop) 2030Sstevel@tonic-gate { 2040Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate int 2080Sstevel@tonic-gate pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate uint16_t cmdreg; 2110Sstevel@tonic-gate ddi_acc_handle_t conf_hdl = NULL; 2120Sstevel@tonic-gate int rc; 2130Sstevel@tonic-gate 2145295Srandyf switch (cmd) { 2155295Srandyf case DDI_ATTACH: 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * Make sure bus-mastering is enabled, even if 2180Sstevel@tonic-gate * BIOS didn't. 2190Sstevel@tonic-gate */ 220466Smrj rc = pci_config_setup(dip, &conf_hdl); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* 2230Sstevel@tonic-gate * In case of error, return SUCCESS. This is because 2240Sstevel@tonic-gate * bus-mastering could be already enabled by BIOS. 2250Sstevel@tonic-gate */ 2260Sstevel@tonic-gate if (rc != DDI_SUCCESS) 2270Sstevel@tonic-gate return (DDI_SUCCESS); 2280Sstevel@tonic-gate 229466Smrj cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM); 2300Sstevel@tonic-gate if ((cmdreg & PCI_COMM_ME) == 0) { 231466Smrj pci_config_put16(conf_hdl, PCI_CONF_COMM, 2320Sstevel@tonic-gate cmdreg | PCI_COMM_ME); 2330Sstevel@tonic-gate } 234466Smrj pci_config_teardown(&conf_hdl); 2350Sstevel@tonic-gate return (DDI_SUCCESS); 2365295Srandyf 2375295Srandyf case DDI_RESUME: 2385295Srandyf /* Restore our PCI configuration header */ 2395295Srandyf if (pci_restore_config_regs(dip) != DDI_SUCCESS) { 2405295Srandyf /* 2415295Srandyf * XXXX 2425295Srandyf * This is a pretty bad thing. However, for some 2435295Srandyf * reason it always happens. To further complicate 2445295Srandyf * things, it appears if we just ignore this, we 2455295Srandyf * properly resume. For now, all I want to do is 2465295Srandyf * to generate this message so that it doesn't get 2475295Srandyf * forgotten. 2485295Srandyf */ 2495295Srandyf cmn_err(CE_WARN, 2505295Srandyf "Couldn't restore PCI config regs for %s(%p)", 2515295Srandyf ddi_node_name(dip), (void *) dip); 2525295Srandyf } 2535295Srandyf #ifdef DEBUG 2545295Srandyf /* Bus mastering should still be enabled */ 2555295Srandyf if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS) 2565295Srandyf return (DDI_FAILURE); 2575295Srandyf cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM); 2585295Srandyf ASSERT((cmdreg & PCI_COMM_ME) != 0); 2595295Srandyf pci_config_teardown(&conf_hdl); 2605295Srandyf #endif 2615295Srandyf return (DDI_SUCCESS); 2620Sstevel@tonic-gate } 2635295Srandyf 2645295Srandyf return (DDI_FAILURE); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2675295Srandyf /*ARGSUSED*/ 2685295Srandyf int 2695295Srandyf pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2705295Srandyf { 2715295Srandyf switch (cmd) { 2725295Srandyf case DDI_DETACH: 2735295Srandyf return (DDI_SUCCESS); 2745295Srandyf case DDI_SUSPEND: 2755295Srandyf /* Save our PCI configuration header */ 2765295Srandyf if (pci_save_config_regs(dip) != DDI_SUCCESS) { 2775295Srandyf /* Don't suspend if we cannot save config regs */ 2785295Srandyf return (DDI_FAILURE); 2795295Srandyf } 2805295Srandyf return (DDI_SUCCESS); 2815295Srandyf } 2825295Srandyf return (DDI_FAILURE); 2835295Srandyf } 2840Sstevel@tonic-gate 2850Sstevel@tonic-gate /*ARGSUSED*/ 2860Sstevel@tonic-gate static int 2870Sstevel@tonic-gate pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, 2880Sstevel@tonic-gate void *arg, void *result) 2890Sstevel@tonic-gate { 290430Smrj dev_info_t *cdip; 291430Smrj int controller; 292430Smrj void *pdptr; 293430Smrj int rnumber; 294430Smrj off_t tmp; 295430Smrj int rc; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate PDBG(("pciide_bus_ctl\n")); 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate switch (ctlop) { 3000Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 301430Smrj cdip = (dev_info_t *)arg; 302430Smrj return (pciide_initchild(dip, cdip)); 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 305430Smrj cdip = (dev_info_t *)arg; 306430Smrj pdptr = ddi_get_parent_data(cdip); 307430Smrj ddi_set_parent_data(cdip, NULL); 308430Smrj ddi_set_name_addr(cdip, NULL); 309430Smrj kmem_free(pdptr, PCIIDE_PDSIZE); 310430Smrj return (DDI_SUCCESS); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 3130Sstevel@tonic-gate *(int *)result = 3; 3140Sstevel@tonic-gate return (DDI_SUCCESS); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * Adjust the rnumbers based on which controller instance 3190Sstevel@tonic-gate * is requested; adjust for the 2 tuples per controller. 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate if (strcmp("0", ddi_get_name_addr(rdip)) == 0) 3220Sstevel@tonic-gate controller = 0; 3230Sstevel@tonic-gate else 3240Sstevel@tonic-gate controller = 1; 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate switch (rnumber = *(int *)arg) { 3280Sstevel@tonic-gate case 0: 3290Sstevel@tonic-gate case 1: 3300Sstevel@tonic-gate rnumber += (2 * controller); 3310Sstevel@tonic-gate break; 3320Sstevel@tonic-gate case 2: 3330Sstevel@tonic-gate rnumber = 4; 3340Sstevel@tonic-gate break; 3350Sstevel@tonic-gate default: 3360Sstevel@tonic-gate PDBG(("pciide_ctlops invalid rnumber\n")); 3370Sstevel@tonic-gate return (DDI_FAILURE); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate if (PCIIDE_PRE26(dip)) { 3420Sstevel@tonic-gate int old_rnumber; 3430Sstevel@tonic-gate int new_rnumber; 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate old_rnumber = rnumber; 3460Sstevel@tonic-gate new_rnumber 3475295Srandyf = pciide_pre26_rnumber_map(dip, old_rnumber); 3480Sstevel@tonic-gate PDBG(("pciide rnumber old %d new %d\n", 3495295Srandyf old_rnumber, new_rnumber)); 3500Sstevel@tonic-gate rnumber = new_rnumber; 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * Add 1 to skip over the PCI config space tuple 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate rnumber++; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * If it's not tuple #2 pass the adjusted request to my parent 3600Sstevel@tonic-gate */ 3610Sstevel@tonic-gate if (*(int *)arg != 2) { 3620Sstevel@tonic-gate return (ddi_ctlops(dip, dip, ctlop, &rnumber, result)); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* 3660Sstevel@tonic-gate * Handle my child's reg-tuple #2 here by splitting my 16 byte 3670Sstevel@tonic-gate * reg-tuple #4 into two 8 byte ranges based on the 3680Sstevel@tonic-gate * the child's controller #. 3690Sstevel@tonic-gate */ 3700Sstevel@tonic-gate 3710Sstevel@tonic-gate tmp = 8; 3720Sstevel@tonic-gate rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp); 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate /* 3750Sstevel@tonic-gate * Allow for the possibility of less than 16 bytes by 3760Sstevel@tonic-gate * by checking what's actually returned for my reg-tuple #4. 3770Sstevel@tonic-gate */ 3780Sstevel@tonic-gate if (controller == 1) { 3790Sstevel@tonic-gate if (tmp < 8) 3800Sstevel@tonic-gate tmp = 0; 3810Sstevel@tonic-gate else 3820Sstevel@tonic-gate tmp -= 8; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate if (tmp > 8) 3850Sstevel@tonic-gate tmp = 8; 3860Sstevel@tonic-gate *(off_t *)result = tmp; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate return (rc); 3890Sstevel@tonic-gate 3908550SSeth.Goldberg@Sun.COM case DDI_CTLOPS_ATTACH: 3918550SSeth.Goldberg@Sun.COM case DDI_CTLOPS_DETACH: 3928550SSeth.Goldberg@Sun.COM /* 3938550SSeth.Goldberg@Sun.COM * Don't pass child ide ATTACH/DETACH to parent 3948550SSeth.Goldberg@Sun.COM */ 3958550SSeth.Goldberg@Sun.COM return (DDI_SUCCESS); 3968550SSeth.Goldberg@Sun.COM 3970Sstevel@tonic-gate default: 3980Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 3990Sstevel@tonic-gate } 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* 4030Sstevel@tonic-gate * IEEE 1275 Working Group Proposal #414 says that the Primary 4040Sstevel@tonic-gate * controller is "ata@0" and the Secondary controller "ata@1". 4050Sstevel@tonic-gate * 4060Sstevel@tonic-gate * By the time we get here, boot Bootconf (2.6+) has created devinfo 4070Sstevel@tonic-gate * nodes with the appropriate "reg", "assigned-addresses" and "interrupts" 4080Sstevel@tonic-gate * properites on the pci-ide node and both ide child nodes. 4090Sstevel@tonic-gate * 4100Sstevel@tonic-gate * In compatibility mode the "reg" and "assigned-addresses" properties 4110Sstevel@tonic-gate * of the pci-ide node are set up like this: 4120Sstevel@tonic-gate * 4130Sstevel@tonic-gate * 1. PCI-IDE Nexus 4140Sstevel@tonic-gate * 4150Sstevel@tonic-gate * interrupts=0 4160Sstevel@tonic-gate * (addr-hi addr-mid addr-low size-hi size-low) 4170Sstevel@tonic-gate * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000 4180Sstevel@tonic-gate * 81000000.00000000.000001f0.00000000.00000008 4190Sstevel@tonic-gate * 81000000.00000000.000003f4.00000000.00000004 4200Sstevel@tonic-gate * 81000000.00000000,00000170.00000000.00000008 4210Sstevel@tonic-gate * 81000000.00000000,00000374.00000000.00000004 4220Sstevel@tonic-gate * 01000020.00000000,-[BAR4]-.00000000.00000010 4230Sstevel@tonic-gate * 4240Sstevel@tonic-gate * In native PCI mode the "reg" and "assigned-addresses" properties 4250Sstevel@tonic-gate * would be set up like this: 4260Sstevel@tonic-gate * 4270Sstevel@tonic-gate * 2. PCI-IDE Nexus 4280Sstevel@tonic-gate * 4290Sstevel@tonic-gate * interrupts=0 4300Sstevel@tonic-gate * reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000 4310Sstevel@tonic-gate * 01000010.00000000.-[BAR0]-.00000000.00000008 4320Sstevel@tonic-gate * 01000014,00000000.-[BAR1]-.00000000.00000004 4330Sstevel@tonic-gate * 01000018.00000000.-[BAR2]-.00000000.00000008 4340Sstevel@tonic-gate * 0100001c.00000000.-[BAR3]-.00000000.00000004 4350Sstevel@tonic-gate * 01000020.00000000.-[BAR4]-.00000000.00000010 4360Sstevel@tonic-gate * 4370Sstevel@tonic-gate * 4380Sstevel@tonic-gate * In both modes the child nodes simply have the following: 4390Sstevel@tonic-gate * 4400Sstevel@tonic-gate * 2. primary controller (compatibility mode) 4410Sstevel@tonic-gate * 4420Sstevel@tonic-gate * interrupts=14 4430Sstevel@tonic-gate * reg=00000000 4440Sstevel@tonic-gate * 4450Sstevel@tonic-gate * 3. secondary controller 4460Sstevel@tonic-gate * 4470Sstevel@tonic-gate * interrupts=15 4480Sstevel@tonic-gate * reg=00000001 4490Sstevel@tonic-gate * 4500Sstevel@tonic-gate * The pciide_bus_map() function is responsible for turning requests 4510Sstevel@tonic-gate * to map primary or secondary controller rnumbers into mapping requests 4520Sstevel@tonic-gate * of the appropriate regspec on the pci-ide node. 4530Sstevel@tonic-gate * 4540Sstevel@tonic-gate */ 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate static int 4570Sstevel@tonic-gate pciide_initchild(dev_info_t *mydip, dev_info_t *cdip) 4580Sstevel@tonic-gate { 4590Sstevel@tonic-gate struct ddi_parent_private_data *pdptr; 4600Sstevel@tonic-gate struct intrspec *ispecp; 4610Sstevel@tonic-gate int vec; 4620Sstevel@tonic-gate int *rp; 4630Sstevel@tonic-gate uint_t proplen; 4640Sstevel@tonic-gate char name[80]; 4650Sstevel@tonic-gate int dev; 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate PDBG(("pciide_initchild\n")); 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate /* 4700Sstevel@tonic-gate * Set the address portion of the node name based on 4710Sstevel@tonic-gate * the controller number (0 or 1) from the 'reg' property. 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 4740Sstevel@tonic-gate "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) { 4750Sstevel@tonic-gate PDBG(("pciide_intchild prop error\n")); 4760Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate /* 4800Sstevel@tonic-gate * copy the controller number and 4810Sstevel@tonic-gate * free the memory allocated by ddi_prop_lookup_int_array 4820Sstevel@tonic-gate */ 4830Sstevel@tonic-gate dev = *rp; 4840Sstevel@tonic-gate ddi_prop_free(rp); 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * I only support two controllers per device, determine 4880Sstevel@tonic-gate * which this one is and set its unit address. 4890Sstevel@tonic-gate */ 4900Sstevel@tonic-gate if (dev > 1) { 4910Sstevel@tonic-gate PDBG(("pciide_initchild bad dev\n")); 4920Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate (void) sprintf(name, "%d", dev); 4950Sstevel@tonic-gate ddi_set_name_addr(cdip, name); 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate /* 4980Sstevel@tonic-gate * determine if this instance is running in native or compat mode 4990Sstevel@tonic-gate */ 5000Sstevel@tonic-gate pciide_compat_setup(mydip, cdip, dev); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* interrupts property is required */ 5030Sstevel@tonic-gate if (PCIIDE_NATIVE_MODE(cdip)) { 5040Sstevel@tonic-gate vec = 1; 5050Sstevel@tonic-gate } else { 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * In compatibility mode, dev 0 should always be 5080Sstevel@tonic-gate * IRQ 14 and dev 1 is IRQ 15. If for some reason 5090Sstevel@tonic-gate * this needs to be changed, do it via the interrupts 5100Sstevel@tonic-gate * property in the ata.conf file. 5110Sstevel@tonic-gate */ 5120Sstevel@tonic-gate vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, 5135295Srandyf "interrupts", -1); 5140Sstevel@tonic-gate if (vec == -1) { 5150Sstevel@tonic-gate /* setup compatibility mode interrupts */ 5160Sstevel@tonic-gate if (dev == 0) { 5170Sstevel@tonic-gate vec = 14; 5180Sstevel@tonic-gate } else if (dev == 1) { 5190Sstevel@tonic-gate vec = 15; 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate PDBG(("pciide_initchild bad intr\n")); 5220Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate 527430Smrj pdptr = kmem_zalloc(PCIIDE_PDSIZE, KM_SLEEP); 5280Sstevel@tonic-gate ispecp = (struct intrspec *)(pdptr + 1); 5290Sstevel@tonic-gate pdptr->par_nintr = 1; 5300Sstevel@tonic-gate pdptr->par_intr = ispecp; 5310Sstevel@tonic-gate ispecp->intrspec_vec = vec; 5320Sstevel@tonic-gate ddi_set_parent_data(cdip, pdptr); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate PDBG(("pciide_initchild okay\n")); 5350Sstevel@tonic-gate return (DDI_SUCCESS); 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate static int 5390Sstevel@tonic-gate pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 5400Sstevel@tonic-gate off_t offset, off_t len, caddr_t *vaddrp) 5410Sstevel@tonic-gate { 5420Sstevel@tonic-gate dev_info_t *pdip; 5430Sstevel@tonic-gate int rnumber = mp->map_obj.rnumber; 5440Sstevel@tonic-gate int controller; 5450Sstevel@tonic-gate int rc; 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate PDBG(("pciide_bus_map\n")); 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate if (strcmp("0", ddi_get_name_addr(rdip)) == 0) 5500Sstevel@tonic-gate controller = 0; 5510Sstevel@tonic-gate else 5520Sstevel@tonic-gate controller = 1; 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * Adjust the rnumbers based on which controller instance 5560Sstevel@tonic-gate * is being mapped; adjust for the 2 tuples per controller. 5570Sstevel@tonic-gate */ 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate switch (rnumber) { 5600Sstevel@tonic-gate case 0: 5610Sstevel@tonic-gate case 1: 5620Sstevel@tonic-gate mp->map_obj.rnumber += (controller * 2); 5630Sstevel@tonic-gate break; 5640Sstevel@tonic-gate case 2: 5650Sstevel@tonic-gate /* 5660Sstevel@tonic-gate * split the 16 I/O ports into two 8 port ranges 5670Sstevel@tonic-gate */ 5680Sstevel@tonic-gate mp->map_obj.rnumber = 4; 5690Sstevel@tonic-gate if (offset + len > 8) { 5700Sstevel@tonic-gate PDBG(("pciide_bus_map offset\n")); 5710Sstevel@tonic-gate return (DDI_FAILURE); 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate if (len == 0) 5740Sstevel@tonic-gate len = 8 - offset; 5750Sstevel@tonic-gate offset += 8 * controller; 5760Sstevel@tonic-gate break; 5770Sstevel@tonic-gate default: 5780Sstevel@tonic-gate PDBG(("pciide_bus_map default\n")); 5790Sstevel@tonic-gate return (DDI_FAILURE); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate if (PCIIDE_PRE26(dip)) { 5830Sstevel@tonic-gate int old_rnumber; 5840Sstevel@tonic-gate int new_rnumber; 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate old_rnumber = mp->map_obj.rnumber; 5870Sstevel@tonic-gate new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber); 5880Sstevel@tonic-gate PDBG(("pciide rnumber old %d new %d\n", 5895295Srandyf old_rnumber, new_rnumber)); 5900Sstevel@tonic-gate mp->map_obj.rnumber = new_rnumber; 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate /* 5940Sstevel@tonic-gate * Add 1 to skip over the PCI config space tuple 5950Sstevel@tonic-gate */ 5960Sstevel@tonic-gate mp->map_obj.rnumber++; 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate /* 6000Sstevel@tonic-gate * pass the adjusted request to my parent 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate pdip = ddi_get_parent(dip); 6030Sstevel@tonic-gate rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)) 6045295Srandyf (pdip, dip, mp, offset, len, vaddrp)); 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok")); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate return (rc); 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate static struct intrspec * 6130Sstevel@tonic-gate pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber) 6140Sstevel@tonic-gate { 6150Sstevel@tonic-gate struct ddi_parent_private_data *ppdptr; 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate PDBG(("pciide_get_ispec\n")); 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate /* 6200Sstevel@tonic-gate * Native mode PCI-IDE controllers share the parent's 6210Sstevel@tonic-gate * PCI interrupt line. 6220Sstevel@tonic-gate * 6230Sstevel@tonic-gate * Compatibility mode PCI-IDE controllers have their 6240Sstevel@tonic-gate * own intrspec which specifies ISA IRQ 14 or 15. 6250Sstevel@tonic-gate * 6260Sstevel@tonic-gate */ 6270Sstevel@tonic-gate if (PCIIDE_NATIVE_MODE(rdip)) { 6280Sstevel@tonic-gate ddi_intrspec_t is; 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate is = pci_intx_get_ispec(dip, dip, inumber); 6310Sstevel@tonic-gate PDBG(("pciide_get_ispec okay\n")); 6320Sstevel@tonic-gate return ((struct intrspec *)is); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* Else compatibility mode, use the ISA IRQ */ 6360Sstevel@tonic-gate if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) { 6370Sstevel@tonic-gate PDBG(("pciide_get_ispec null\n")); 6380Sstevel@tonic-gate return (NULL); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate /* validate the interrupt number */ 6420Sstevel@tonic-gate if (inumber >= ppdptr->par_nintr) { 6430Sstevel@tonic-gate PDBG(("pciide_get_inum\n")); 6440Sstevel@tonic-gate return (NULL); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate PDBG(("pciide_get_ispec ok\n")); 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate return ((struct intrspec *)&ppdptr->par_intr[inumber]); 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate static int 6530Sstevel@tonic-gate pciide_get_pri(dev_info_t *dip, dev_info_t *rdip, 6540Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, int *pri) 6550Sstevel@tonic-gate { 6560Sstevel@tonic-gate struct intrspec *ispecp; 6570Sstevel@tonic-gate int *intpriorities; 6580Sstevel@tonic-gate uint_t num_intpriorities; 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate PDBG(("pciide_get_pri\n")); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) { 6630Sstevel@tonic-gate PDBG(("pciide_get_pri null\n")); 6640Sstevel@tonic-gate return (DDI_FAILURE); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if (PCIIDE_NATIVE_MODE(rdip)) { 6680Sstevel@tonic-gate *pri = ispecp->intrspec_pri; 6690Sstevel@tonic-gate PDBG(("pciide_get_pri ok\n")); 6700Sstevel@tonic-gate return (DDI_SUCCESS); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* check if the intrspec has been initialized */ 6740Sstevel@tonic-gate if (ispecp->intrspec_pri != 0) { 6750Sstevel@tonic-gate *pri = ispecp->intrspec_pri; 6760Sstevel@tonic-gate PDBG(("pciide_get_pri ok2\n")); 6770Sstevel@tonic-gate return (DDI_SUCCESS); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate /* Use a default of level 5 */ 6810Sstevel@tonic-gate ispecp->intrspec_pri = 5; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate /* 6840Sstevel@tonic-gate * If there's an interrupt-priorities property, use it to 6850Sstevel@tonic-gate * over-ride the default interrupt priority. 6860Sstevel@tonic-gate */ 6870Sstevel@tonic-gate if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, 6880Sstevel@tonic-gate "interrupt-priorities", &intpriorities, &num_intpriorities) == 6890Sstevel@tonic-gate DDI_PROP_SUCCESS) { 6900Sstevel@tonic-gate if (hdlp->ih_inum < num_intpriorities) 6910Sstevel@tonic-gate ispecp->intrspec_pri = intpriorities[hdlp->ih_inum]; 6920Sstevel@tonic-gate ddi_prop_free(intpriorities); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate *pri = ispecp->intrspec_pri; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate PDBG(("pciide_get_pri ok3\n")); 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate return (DDI_SUCCESS); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate static int 7020Sstevel@tonic-gate pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 7030Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 7040Sstevel@tonic-gate { 7050Sstevel@tonic-gate struct intrspec *ispecp; 7060Sstevel@tonic-gate int rc; 7070Sstevel@tonic-gate int pri = 0; 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n", 7100Sstevel@tonic-gate (void *)dip, (void *)rdip, intr_op, (void *)hdlp)); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate switch (intr_op) { 7130Sstevel@tonic-gate case DDI_INTROP_SUPPORTED_TYPES: 7140Sstevel@tonic-gate *(int *)result = DDI_INTR_TYPE_FIXED; 7150Sstevel@tonic-gate break; 7160Sstevel@tonic-gate case DDI_INTROP_GETCAP: 7171290Sanish *(int *)result = DDI_INTR_FLAG_LEVEL; 7180Sstevel@tonic-gate break; 7190Sstevel@tonic-gate case DDI_INTROP_NINTRS: 7202580Sanish case DDI_INTROP_NAVAIL: 7212580Sanish *(int *)result = (!PCIIDE_NATIVE_MODE(rdip)) ? 7222580Sanish i_ddi_get_intx_nintrs(rdip) : 1; 7230Sstevel@tonic-gate break; 7240Sstevel@tonic-gate case DDI_INTROP_ALLOC: 725*12683SJimmy.Vetayases@oracle.com return (pciide_alloc_intr(dip, rdip, hdlp, result)); 7260Sstevel@tonic-gate case DDI_INTROP_FREE: 727*12683SJimmy.Vetayases@oracle.com return (pciide_free_intr(dip, rdip, hdlp)); 7280Sstevel@tonic-gate case DDI_INTROP_GETPRI: 7290Sstevel@tonic-gate if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) { 7300Sstevel@tonic-gate *(int *)result = 0; 7310Sstevel@tonic-gate return (DDI_FAILURE); 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate *(int *)result = pri; 7340Sstevel@tonic-gate break; 7350Sstevel@tonic-gate case DDI_INTROP_ADDISR: 7360Sstevel@tonic-gate if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == 7370Sstevel@tonic-gate NULL) 7380Sstevel@tonic-gate return (DDI_FAILURE); 739916Sschwartz ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp; 7400Sstevel@tonic-gate ispecp->intrspec_func = hdlp->ih_cb_func; 7410Sstevel@tonic-gate break; 7420Sstevel@tonic-gate case DDI_INTROP_REMISR: 7430Sstevel@tonic-gate if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == 7440Sstevel@tonic-gate NULL) 7450Sstevel@tonic-gate return (DDI_FAILURE); 7460Sstevel@tonic-gate ispecp->intrspec_func = (uint_t (*)()) 0; 7470Sstevel@tonic-gate break; 7480Sstevel@tonic-gate case DDI_INTROP_ENABLE: 7490Sstevel@tonic-gate /* FALLTHRU */ 7500Sstevel@tonic-gate case DDI_INTROP_DISABLE: 7510Sstevel@tonic-gate if (PCIIDE_NATIVE_MODE(rdip)) { 7520Sstevel@tonic-gate rdip = dip; 7530Sstevel@tonic-gate dip = ddi_get_parent(dip); 7540Sstevel@tonic-gate } else { /* get ptr to the root node */ 7550Sstevel@tonic-gate dip = ddi_root_node(); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip, 7590Sstevel@tonic-gate rdip, intr_op, hdlp, result); 7600Sstevel@tonic-gate 7610Sstevel@tonic-gate #ifdef DEBUG 7620Sstevel@tonic-gate if (intr_op == DDI_INTROP_ENABLE) { 7630Sstevel@tonic-gate PDBG(("pciide_enable rc=%d", rc)); 7640Sstevel@tonic-gate } else 7650Sstevel@tonic-gate PDBG(("pciide_disable rc=%d", rc)); 7660Sstevel@tonic-gate #endif /* DEBUG */ 7670Sstevel@tonic-gate return (rc); 7680Sstevel@tonic-gate default: 7690Sstevel@tonic-gate return (DDI_FAILURE); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate return (DDI_SUCCESS); 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate 775*12683SJimmy.Vetayases@oracle.com int 776*12683SJimmy.Vetayases@oracle.com pciide_alloc_intr(dev_info_t *dip, dev_info_t *rdip, 777*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp, void *result) 778*12683SJimmy.Vetayases@oracle.com { 779*12683SJimmy.Vetayases@oracle.com struct intrspec *ispec; 780*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl; 781*12683SJimmy.Vetayases@oracle.com int ret; 782*12683SJimmy.Vetayases@oracle.com int free_phdl = 0; 783*12683SJimmy.Vetayases@oracle.com apic_get_type_t type_info; 784*12683SJimmy.Vetayases@oracle.com 785*12683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL) 786*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 787*12683SJimmy.Vetayases@oracle.com 788*12683SJimmy.Vetayases@oracle.com if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) 789*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 790*12683SJimmy.Vetayases@oracle.com 791*12683SJimmy.Vetayases@oracle.com /* 792*12683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request for it 793*12683SJimmy.Vetayases@oracle.com * to allocate the vector now. 794*12683SJimmy.Vetayases@oracle.com */ 795*12683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 796*12683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info; 797*12683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) == 798*12683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) { 799*12683SJimmy.Vetayases@oracle.com if (hdlp->ih_private == NULL) { /* allocate phdl structure */ 800*12683SJimmy.Vetayases@oracle.com free_phdl = 1; 801*12683SJimmy.Vetayases@oracle.com i_ddi_alloc_intr_phdl(hdlp); 802*12683SJimmy.Vetayases@oracle.com } 803*12683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 804*12683SJimmy.Vetayases@oracle.com if (PCIIDE_NATIVE_MODE(rdip)) { 805*12683SJimmy.Vetayases@oracle.com rdip = dip; 806*12683SJimmy.Vetayases@oracle.com dip = ddi_get_parent(dip); 807*12683SJimmy.Vetayases@oracle.com } else { /* get ptr to the root node */ 808*12683SJimmy.Vetayases@oracle.com dip = ddi_root_node(); 809*12683SJimmy.Vetayases@oracle.com } 810*12683SJimmy.Vetayases@oracle.com ret = (*psm_intr_ops)(rdip, hdlp, 811*12683SJimmy.Vetayases@oracle.com PSM_INTR_OP_ALLOC_VECTORS, result); 812*12683SJimmy.Vetayases@oracle.com if (free_phdl) { /* free up the phdl structure */ 813*12683SJimmy.Vetayases@oracle.com free_phdl = 0; 814*12683SJimmy.Vetayases@oracle.com i_ddi_free_intr_phdl(hdlp); 815*12683SJimmy.Vetayases@oracle.com } 816*12683SJimmy.Vetayases@oracle.com } else { 817*12683SJimmy.Vetayases@oracle.com /* 818*12683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where the 819*12683SJimmy.Vetayases@oracle.com * interrupt vector is allocated during ddi_enable_intr() call. 820*12683SJimmy.Vetayases@oracle.com */ 821*12683SJimmy.Vetayases@oracle.com *(int *)result = hdlp->ih_scratch1; 822*12683SJimmy.Vetayases@oracle.com ret = DDI_SUCCESS; 823*12683SJimmy.Vetayases@oracle.com } 824*12683SJimmy.Vetayases@oracle.com 825*12683SJimmy.Vetayases@oracle.com return (ret); 826*12683SJimmy.Vetayases@oracle.com } 827*12683SJimmy.Vetayases@oracle.com 828*12683SJimmy.Vetayases@oracle.com int 829*12683SJimmy.Vetayases@oracle.com pciide_free_intr(dev_info_t *dip, dev_info_t *rdip, 830*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp) 831*12683SJimmy.Vetayases@oracle.com { 832*12683SJimmy.Vetayases@oracle.com struct intrspec *ispec; 833*12683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl; 834*12683SJimmy.Vetayases@oracle.com apic_get_type_t type_info; 835*12683SJimmy.Vetayases@oracle.com 836*12683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL) 837*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 838*12683SJimmy.Vetayases@oracle.com 839*12683SJimmy.Vetayases@oracle.com /* 840*12683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request for it 841*12683SJimmy.Vetayases@oracle.com * to free up the vector now. 842*12683SJimmy.Vetayases@oracle.com */ 843*12683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t)); 844*12683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info; 845*12683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) == 846*12683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) { 847*12683SJimmy.Vetayases@oracle.com if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == 848*12683SJimmy.Vetayases@oracle.com NULL) 849*12683SJimmy.Vetayases@oracle.com return (DDI_FAILURE); 850*12683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec; 851*12683SJimmy.Vetayases@oracle.com if (PCIIDE_NATIVE_MODE(rdip)) { 852*12683SJimmy.Vetayases@oracle.com rdip = dip; 853*12683SJimmy.Vetayases@oracle.com dip = ddi_get_parent(dip); 854*12683SJimmy.Vetayases@oracle.com } else { /* get ptr to the root node */ 855*12683SJimmy.Vetayases@oracle.com dip = ddi_root_node(); 856*12683SJimmy.Vetayases@oracle.com } 857*12683SJimmy.Vetayases@oracle.com return ((*psm_intr_ops)(rdip, hdlp, 858*12683SJimmy.Vetayases@oracle.com PSM_INTR_OP_FREE_VECTORS, NULL)); 859*12683SJimmy.Vetayases@oracle.com } 860*12683SJimmy.Vetayases@oracle.com 861*12683SJimmy.Vetayases@oracle.com /* 862*12683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where 863*12683SJimmy.Vetayases@oracle.com * the interrupt vector was already freed during 864*12683SJimmy.Vetayases@oracle.com * ddi_disable_intr() call. 865*12683SJimmy.Vetayases@oracle.com */ 866*12683SJimmy.Vetayases@oracle.com return (DDI_SUCCESS); 867*12683SJimmy.Vetayases@oracle.com } 868*12683SJimmy.Vetayases@oracle.com 8690Sstevel@tonic-gate /* 8700Sstevel@tonic-gate * This is one of the places where controller specific setup needs to be 8710Sstevel@tonic-gate * considered. 8720Sstevel@tonic-gate * At this point the controller was already pre-qualified as a known and 8730Sstevel@tonic-gate * supported pciide controller. 8740Sstevel@tonic-gate * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE 8750Sstevel@tonic-gate * programming interface code but rather PCI_MASS_OTHER sub-class code 8760Sstevel@tonic-gate * without any additional data. 8770Sstevel@tonic-gate * For those controllers IDE programming interface cannot be extracted 8780Sstevel@tonic-gate * from PCI class - we assume that they are pci-native type and we fix 8790Sstevel@tonic-gate * the programming interface used by other functions. 8800Sstevel@tonic-gate * The programming interface byte is set to indicate pci-native mode 8810Sstevel@tonic-gate * for both controllers and the Bus Master DMA capabilitiy of the controller. 8820Sstevel@tonic-gate */ 8830Sstevel@tonic-gate static void 8840Sstevel@tonic-gate pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev) 8850Sstevel@tonic-gate { 8860Sstevel@tonic-gate int class_code; 8870Sstevel@tonic-gate int rc = DDI_PROP_SUCCESS; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, 8900Sstevel@tonic-gate DDI_PROP_DONTPASS, "class-code", 0); 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) { 8930Sstevel@tonic-gate /* 8940Sstevel@tonic-gate * Controller provides PCI_MASS_IDE sub-class code first 8950Sstevel@tonic-gate * (implied IDE programming interface) 8960Sstevel@tonic-gate */ 8970Sstevel@tonic-gate if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) || 8980Sstevel@tonic-gate (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) { 8998419SKerry.Shu@Sun.COM rc = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, 9005295Srandyf "compatibility-mode", 1); 9010Sstevel@tonic-gate if (rc != DDI_PROP_SUCCESS) 9020Sstevel@tonic-gate cmn_err(CE_WARN, 9030Sstevel@tonic-gate "pciide prop error %d compat-mode", rc); 9040Sstevel@tonic-gate } 9050Sstevel@tonic-gate } else { 9060Sstevel@tonic-gate /* 9070Sstevel@tonic-gate * Pci-ide controllers not providing PCI_MASS_IDE sub-class are 9080Sstevel@tonic-gate * assumed to be of pci-native type and bus master DMA capable. 9090Sstevel@tonic-gate * Programming interface part of the class-code property is 9100Sstevel@tonic-gate * fixed here. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate class_code &= 0x00ffff00; 9130Sstevel@tonic-gate class_code |= PCI_IDE_IF_BM_CAP_MASK | 9145295Srandyf PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC; 9150Sstevel@tonic-gate rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip, 9165295Srandyf "class-code", class_code); 9170Sstevel@tonic-gate if (rc != DDI_PROP_SUCCESS) 9180Sstevel@tonic-gate cmn_err(CE_WARN, 9190Sstevel@tonic-gate "pciide prop error %d class-code", rc); 9200Sstevel@tonic-gate } 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate static int 9250Sstevel@tonic-gate pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber) 9260Sstevel@tonic-gate { 9270Sstevel@tonic-gate int pri_native; 9280Sstevel@tonic-gate int sec_native; 9290Sstevel@tonic-gate int class_code; 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS, 9325295Srandyf "class-code", 0); 9330Sstevel@tonic-gate 9340Sstevel@tonic-gate pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE; 9350Sstevel@tonic-gate sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE; 9360Sstevel@tonic-gate 9370Sstevel@tonic-gate return (pciide_map_rnumber(rnumber, pri_native, sec_native)); 9380Sstevel@tonic-gate 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* 9420Sstevel@tonic-gate * The canonical order of the reg property tuples for the 9430Sstevel@tonic-gate * Base Address Registers is supposed to be: 9440Sstevel@tonic-gate * 9450Sstevel@tonic-gate * primary controller (BAR 0) 9460Sstevel@tonic-gate * primary controller (BAR 1) 9470Sstevel@tonic-gate * secondary controller (BAR 2) 9480Sstevel@tonic-gate * secondary controller (BAR 3) 9490Sstevel@tonic-gate * bus mastering regs (BAR 4) 9500Sstevel@tonic-gate * 9510Sstevel@tonic-gate * For 2.6, bootconf has been fixed to always generate the 9520Sstevel@tonic-gate * reg property (and assigned-addresses property) tuples 9530Sstevel@tonic-gate * in the above order. 9540Sstevel@tonic-gate * 9550Sstevel@tonic-gate * But in releases prior to 2.6 the order varies depending 9560Sstevel@tonic-gate * on whether compatibility or native mode is being used for 9570Sstevel@tonic-gate * each controller. There ends up being four possible 9580Sstevel@tonic-gate * orders: 9590Sstevel@tonic-gate * 9600Sstevel@tonic-gate * BM, P0, P1, S0, S1 primary compatible, secondary compatible 9610Sstevel@tonic-gate * S0, S1, BM, P0, P1 primary compatible, secondary native 9620Sstevel@tonic-gate * P0, P1, BM, S0, S1 primary native, secondary compatible 9630Sstevel@tonic-gate * P0, P1, S0, S1, BM primary native, secondary native 9640Sstevel@tonic-gate * 9650Sstevel@tonic-gate * where: Px is the primary tuples, Sx the secondary tuples, and 9660Sstevel@tonic-gate * B the Bus Master tuple. 9670Sstevel@tonic-gate * 9680Sstevel@tonic-gate * Here's the results for each of the four states: 9690Sstevel@tonic-gate * 9700Sstevel@tonic-gate * 0, 1, 2, 3, 4 9710Sstevel@tonic-gate * 9720Sstevel@tonic-gate * CC 1, 2, 3, 4, 0 9730Sstevel@tonic-gate * CN 3, 4, 0, 1, 2 9740Sstevel@tonic-gate * NC 0, 1, 3, 4, 2 9750Sstevel@tonic-gate * NN 0, 1, 2, 3, 4 9760Sstevel@tonic-gate * 9770Sstevel@tonic-gate * C = compatible(!native) == 0 9780Sstevel@tonic-gate * N = native == 1 9790Sstevel@tonic-gate * 9800Sstevel@tonic-gate * Here's the transformation matrix: 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate static int pciide_transform[2][2][5] = { 9840Sstevel@tonic-gate /* P S */ 9850Sstevel@tonic-gate /* [C][C] */ +1, +1, +1, +1, -4, 9860Sstevel@tonic-gate /* [C][N] */ +3, +3, -2, -2, -2, 9870Sstevel@tonic-gate /* [N][C] */ +0, +0, +1, +1, -2, 9880Sstevel@tonic-gate /* [N][N] */ +0, +0, +0, +0, +0 9890Sstevel@tonic-gate }; 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate 9920Sstevel@tonic-gate static int 9930Sstevel@tonic-gate pciide_map_rnumber(int rnumber, int pri_native, int sec_native) 9940Sstevel@tonic-gate { 9950Sstevel@tonic-gate /* transform flags into indexes */ 9960Sstevel@tonic-gate pri_native = pri_native ? 1 : 0; 9970Sstevel@tonic-gate sec_native = sec_native ? 1 : 0; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate rnumber += pciide_transform[pri_native][sec_native][rnumber]; 10000Sstevel@tonic-gate return (rnumber); 10010Sstevel@tonic-gate } 1002