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*12825SJimmy.Vetayases@oracle.com * Copyright (c) 1997, 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>
4712683SJimmy.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);
11312683SJimmy.Vetayases@oracle.com static int pciide_alloc_intr(dev_info_t *, dev_info_t *,
11412683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *, void *);
11512683SJimmy.Vetayases@oracle.com static int pciide_free_intr(dev_info_t *, dev_info_t *,
11612683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *);
1170Sstevel@tonic-gate
11812683SJimmy.Vetayases@oracle.com extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
11912683SJimmy.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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
pciide_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
pciide_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
pciide_ddi_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)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
pciide_initchild(dev_info_t * mydip,dev_info_t * cdip)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
pciide_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)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 *
pciide_get_ispec(dev_info_t * dip,dev_info_t * rdip,int inumber)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
pciide_get_pri(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,int * pri)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
pciide_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)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:
72512683SJimmy.Vetayases@oracle.com return (pciide_alloc_intr(dip, rdip, hdlp, result));
7260Sstevel@tonic-gate case DDI_INTROP_FREE:
72712683SJimmy.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
77512683SJimmy.Vetayases@oracle.com int
pciide_alloc_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp,void * result)77612683SJimmy.Vetayases@oracle.com pciide_alloc_intr(dev_info_t *dip, dev_info_t *rdip,
77712683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp, void *result)
77812683SJimmy.Vetayases@oracle.com {
77912683SJimmy.Vetayases@oracle.com struct intrspec *ispec;
78012683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl;
78112683SJimmy.Vetayases@oracle.com int ret;
78212683SJimmy.Vetayases@oracle.com int free_phdl = 0;
78312683SJimmy.Vetayases@oracle.com apic_get_type_t type_info;
78412683SJimmy.Vetayases@oracle.com
78512683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL)
78612683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
78712683SJimmy.Vetayases@oracle.com
78812683SJimmy.Vetayases@oracle.com if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL)
78912683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
79012683SJimmy.Vetayases@oracle.com
79112683SJimmy.Vetayases@oracle.com /*
79212683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request for it
79312683SJimmy.Vetayases@oracle.com * to allocate the vector now.
79412683SJimmy.Vetayases@oracle.com */
79512683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
79612683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info;
79712683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
79812683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
79912683SJimmy.Vetayases@oracle.com if (hdlp->ih_private == NULL) { /* allocate phdl structure */
80012683SJimmy.Vetayases@oracle.com free_phdl = 1;
80112683SJimmy.Vetayases@oracle.com i_ddi_alloc_intr_phdl(hdlp);
80212683SJimmy.Vetayases@oracle.com }
80312683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
80412683SJimmy.Vetayases@oracle.com if (PCIIDE_NATIVE_MODE(rdip)) {
80512683SJimmy.Vetayases@oracle.com rdip = dip;
80612683SJimmy.Vetayases@oracle.com dip = ddi_get_parent(dip);
80712683SJimmy.Vetayases@oracle.com } else { /* get ptr to the root node */
80812683SJimmy.Vetayases@oracle.com dip = ddi_root_node();
80912683SJimmy.Vetayases@oracle.com }
81012683SJimmy.Vetayases@oracle.com ret = (*psm_intr_ops)(rdip, hdlp,
81112683SJimmy.Vetayases@oracle.com PSM_INTR_OP_ALLOC_VECTORS, result);
81212683SJimmy.Vetayases@oracle.com if (free_phdl) { /* free up the phdl structure */
81312683SJimmy.Vetayases@oracle.com free_phdl = 0;
81412683SJimmy.Vetayases@oracle.com i_ddi_free_intr_phdl(hdlp);
81512683SJimmy.Vetayases@oracle.com }
81612683SJimmy.Vetayases@oracle.com } else {
81712683SJimmy.Vetayases@oracle.com /*
81812683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where the
81912683SJimmy.Vetayases@oracle.com * interrupt vector is allocated during ddi_enable_intr() call.
82012683SJimmy.Vetayases@oracle.com */
82112683SJimmy.Vetayases@oracle.com *(int *)result = hdlp->ih_scratch1;
82212683SJimmy.Vetayases@oracle.com ret = DDI_SUCCESS;
82312683SJimmy.Vetayases@oracle.com }
82412683SJimmy.Vetayases@oracle.com
82512683SJimmy.Vetayases@oracle.com return (ret);
82612683SJimmy.Vetayases@oracle.com }
82712683SJimmy.Vetayases@oracle.com
82812683SJimmy.Vetayases@oracle.com int
pciide_free_intr(dev_info_t * dip,dev_info_t * rdip,ddi_intr_handle_impl_t * hdlp)82912683SJimmy.Vetayases@oracle.com pciide_free_intr(dev_info_t *dip, dev_info_t *rdip,
83012683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp)
83112683SJimmy.Vetayases@oracle.com {
83212683SJimmy.Vetayases@oracle.com struct intrspec *ispec;
83312683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t info_hdl;
83412683SJimmy.Vetayases@oracle.com apic_get_type_t type_info;
83512683SJimmy.Vetayases@oracle.com
83612683SJimmy.Vetayases@oracle.com if (psm_intr_ops == NULL)
83712683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
83812683SJimmy.Vetayases@oracle.com
83912683SJimmy.Vetayases@oracle.com /*
84012683SJimmy.Vetayases@oracle.com * If the PSM module is "APIX" then pass the request for it
84112683SJimmy.Vetayases@oracle.com * to free up the vector now.
84212683SJimmy.Vetayases@oracle.com */
84312683SJimmy.Vetayases@oracle.com bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
84412683SJimmy.Vetayases@oracle.com info_hdl.ih_private = &type_info;
84512683SJimmy.Vetayases@oracle.com if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
84612683SJimmy.Vetayases@oracle.com PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
84712683SJimmy.Vetayases@oracle.com if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
84812683SJimmy.Vetayases@oracle.com NULL)
84912683SJimmy.Vetayases@oracle.com return (DDI_FAILURE);
85012683SJimmy.Vetayases@oracle.com ((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
85112683SJimmy.Vetayases@oracle.com if (PCIIDE_NATIVE_MODE(rdip)) {
85212683SJimmy.Vetayases@oracle.com rdip = dip;
85312683SJimmy.Vetayases@oracle.com dip = ddi_get_parent(dip);
85412683SJimmy.Vetayases@oracle.com } else { /* get ptr to the root node */
85512683SJimmy.Vetayases@oracle.com dip = ddi_root_node();
85612683SJimmy.Vetayases@oracle.com }
85712683SJimmy.Vetayases@oracle.com return ((*psm_intr_ops)(rdip, hdlp,
85812683SJimmy.Vetayases@oracle.com PSM_INTR_OP_FREE_VECTORS, NULL));
85912683SJimmy.Vetayases@oracle.com }
86012683SJimmy.Vetayases@oracle.com
86112683SJimmy.Vetayases@oracle.com /*
86212683SJimmy.Vetayases@oracle.com * No APIX module; fall back to the old scheme where
86312683SJimmy.Vetayases@oracle.com * the interrupt vector was already freed during
86412683SJimmy.Vetayases@oracle.com * ddi_disable_intr() call.
86512683SJimmy.Vetayases@oracle.com */
86612683SJimmy.Vetayases@oracle.com return (DDI_SUCCESS);
86712683SJimmy.Vetayases@oracle.com }
86812683SJimmy.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
pciide_compat_setup(dev_info_t * mydip,dev_info_t * cdip,int dev)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
pciide_pre26_rnumber_map(dev_info_t * mydip,int rnumber)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
pciide_map_rnumber(int rnumber,int pri_native,int sec_native)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