xref: /onnv-gate/usr/src/uts/common/io/pci-ide/pci-ide.c (revision 8550:0cc93b5e7ddc)
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*8550SSeth.Goldberg@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  *	PCI-IDE bus nexus driver
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/cmn_err.h>
330Sstevel@tonic-gate #include <sys/conf.h>
340Sstevel@tonic-gate #include <sys/errno.h>
350Sstevel@tonic-gate #include <sys/debug.h>
360Sstevel@tonic-gate #include <sys/ddidmareq.h>
370Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
380Sstevel@tonic-gate #include <sys/dma_engine.h>
390Sstevel@tonic-gate #include <sys/modctl.h>
400Sstevel@tonic-gate #include <sys/ddi.h>
410Sstevel@tonic-gate #include <sys/sunddi.h>
428419SKerry.Shu@Sun.COM #include <sys/sunndi.h>
43916Sschwartz #include <sys/mach_intr.h>
440Sstevel@tonic-gate #include <sys/kmem.h>
450Sstevel@tonic-gate #include <sys/pci.h>
460Sstevel@tonic-gate #include <sys/promif.h>
470Sstevel@tonic-gate #include <sys/pci_intr_lib.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);
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate  * Config information
1170Sstevel@tonic-gate  */
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate struct bus_ops pciide_bus_ops = {
1200Sstevel@tonic-gate 	BUSO_REV,
1210Sstevel@tonic-gate 	pciide_bus_map,
1220Sstevel@tonic-gate 	0,
1230Sstevel@tonic-gate 	0,
1240Sstevel@tonic-gate 	0,
1250Sstevel@tonic-gate 	i_ddi_map_fault,
1260Sstevel@tonic-gate 	ddi_dma_map,
1270Sstevel@tonic-gate 	ddi_dma_allochdl,
1280Sstevel@tonic-gate 	ddi_dma_freehdl,
1290Sstevel@tonic-gate 	ddi_dma_bindhdl,
1300Sstevel@tonic-gate 	ddi_dma_unbindhdl,
1310Sstevel@tonic-gate 	ddi_dma_flush,
1320Sstevel@tonic-gate 	ddi_dma_win,
1330Sstevel@tonic-gate 	ddi_dma_mctl,
1340Sstevel@tonic-gate 	pciide_ddi_ctlops,
1350Sstevel@tonic-gate 	ddi_bus_prop_op,
1360Sstevel@tonic-gate 	0,	/* (*bus_get_eventcookie)();	*/
1370Sstevel@tonic-gate 	0,	/* (*bus_add_eventcall)();	*/
1380Sstevel@tonic-gate 	0,	/* (*bus_remove_eventcall)();	*/
1390Sstevel@tonic-gate 	0,	/* (*bus_post_event)();		*/
1400Sstevel@tonic-gate 	0,
1410Sstevel@tonic-gate 	0,
1420Sstevel@tonic-gate 	0,
1430Sstevel@tonic-gate 	0,
1440Sstevel@tonic-gate 	0,
1450Sstevel@tonic-gate 	0,
1460Sstevel@tonic-gate 	0,
1470Sstevel@tonic-gate 	0,
1480Sstevel@tonic-gate 	pciide_intr_ops
1490Sstevel@tonic-gate };
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate struct dev_ops pciide_ops = {
1520Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1530Sstevel@tonic-gate 	0,			/* refcnt  */
1540Sstevel@tonic-gate 	ddi_no_info,		/* info */
1550Sstevel@tonic-gate 	nulldev,		/* identify */
1560Sstevel@tonic-gate 	nulldev,		/* probe */
1570Sstevel@tonic-gate 	pciide_attach,		/* attach */
1585295Srandyf 	pciide_detach,		/* detach */
1590Sstevel@tonic-gate 	nodev,			/* reset */
1600Sstevel@tonic-gate 	(struct cb_ops *)0,	/* driver operations */
1617656SSherry.Moore@Sun.COM 	&pciide_bus_ops,	/* bus operations */
1627656SSherry.Moore@Sun.COM 	NULL,			/* power */
1637656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
1640Sstevel@tonic-gate };
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * Module linkage information for the kernel.
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate static struct modldrv modldrv = {
1710Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This is PCI-IDE bus driver */
1727656SSherry.Moore@Sun.COM 	"pciide nexus driver for 'PCI-IDE' 1.26",
1730Sstevel@tonic-gate 	&pciide_ops,	/* driver ops */
1740Sstevel@tonic-gate };
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate static struct modlinkage modlinkage = {
1770Sstevel@tonic-gate 	MODREV_1,
1780Sstevel@tonic-gate 	&modldrv,
1790Sstevel@tonic-gate 	NULL
1800Sstevel@tonic-gate };
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate int
1840Sstevel@tonic-gate _init(void)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate int
1900Sstevel@tonic-gate _fini(void)
1910Sstevel@tonic-gate {
1920Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate int
1960Sstevel@tonic-gate _info(struct modinfo *modinfop)
1970Sstevel@tonic-gate {
1980Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate int
2020Sstevel@tonic-gate pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate 	uint16_t cmdreg;
2050Sstevel@tonic-gate 	ddi_acc_handle_t conf_hdl = NULL;
2060Sstevel@tonic-gate 	int rc;
2070Sstevel@tonic-gate 
2085295Srandyf 	switch (cmd) {
2095295Srandyf 	case DDI_ATTACH:
2100Sstevel@tonic-gate 		/*
2110Sstevel@tonic-gate 		 * Make sure bus-mastering is enabled, even if
2120Sstevel@tonic-gate 		 * BIOS didn't.
2130Sstevel@tonic-gate 		 */
214466Smrj 		rc = pci_config_setup(dip, &conf_hdl);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 		/*
2170Sstevel@tonic-gate 		 * In case of error, return SUCCESS. This is because
2180Sstevel@tonic-gate 		 * bus-mastering could be already enabled by BIOS.
2190Sstevel@tonic-gate 		 */
2200Sstevel@tonic-gate 		if (rc != DDI_SUCCESS)
2210Sstevel@tonic-gate 			return (DDI_SUCCESS);
2220Sstevel@tonic-gate 
223466Smrj 		cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
2240Sstevel@tonic-gate 		if ((cmdreg & PCI_COMM_ME) == 0) {
225466Smrj 			pci_config_put16(conf_hdl, PCI_CONF_COMM,
2260Sstevel@tonic-gate 			    cmdreg | PCI_COMM_ME);
2270Sstevel@tonic-gate 		}
228466Smrj 		pci_config_teardown(&conf_hdl);
2290Sstevel@tonic-gate 		return (DDI_SUCCESS);
2305295Srandyf 
2315295Srandyf 	case DDI_RESUME:
2325295Srandyf 		/* Restore our PCI configuration header */
2335295Srandyf 		if (pci_restore_config_regs(dip) != DDI_SUCCESS) {
2345295Srandyf 			/*
2355295Srandyf 			 * XXXX
2365295Srandyf 			 * This is a pretty bad thing.  However, for some
2375295Srandyf 			 * reason it always happens.  To further complicate
2385295Srandyf 			 * things, it appears if we just ignore this, we
2395295Srandyf 			 * properly resume.  For now, all I want to do is
2405295Srandyf 			 * to generate this message so that it doesn't get
2415295Srandyf 			 * forgotten.
2425295Srandyf 			 */
2435295Srandyf 			cmn_err(CE_WARN,
2445295Srandyf 			    "Couldn't restore PCI config regs for %s(%p)",
2455295Srandyf 			    ddi_node_name(dip), (void *) dip);
2465295Srandyf 		}
2475295Srandyf #ifdef	DEBUG
2485295Srandyf 		/* Bus mastering should still be enabled */
2495295Srandyf 		if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS)
2505295Srandyf 			return (DDI_FAILURE);
2515295Srandyf 		cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
2525295Srandyf 		ASSERT((cmdreg & PCI_COMM_ME) != 0);
2535295Srandyf 		pci_config_teardown(&conf_hdl);
2545295Srandyf #endif
2555295Srandyf 		return (DDI_SUCCESS);
2560Sstevel@tonic-gate 	}
2575295Srandyf 
2585295Srandyf 	return (DDI_FAILURE);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2615295Srandyf /*ARGSUSED*/
2625295Srandyf int
2635295Srandyf pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2645295Srandyf {
2655295Srandyf 	switch (cmd) {
2665295Srandyf 	case DDI_DETACH:
2675295Srandyf 		return (DDI_SUCCESS);
2685295Srandyf 	case DDI_SUSPEND:
2695295Srandyf 		/* Save our PCI configuration header */
2705295Srandyf 		if (pci_save_config_regs(dip) != DDI_SUCCESS) {
2715295Srandyf 			/* Don't suspend if we cannot save config regs */
2725295Srandyf 			return (DDI_FAILURE);
2735295Srandyf 		}
2745295Srandyf 		return (DDI_SUCCESS);
2755295Srandyf 	}
2765295Srandyf 	return (DDI_FAILURE);
2775295Srandyf }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate /*ARGSUSED*/
2800Sstevel@tonic-gate static int
2810Sstevel@tonic-gate pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
2820Sstevel@tonic-gate     void *arg, void *result)
2830Sstevel@tonic-gate {
284430Smrj 	dev_info_t *cdip;
285430Smrj 	int controller;
286430Smrj 	void *pdptr;
287430Smrj 	int rnumber;
288430Smrj 	off_t tmp;
289430Smrj 	int rc;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 	PDBG(("pciide_bus_ctl\n"));
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	switch (ctlop) {
2940Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
295430Smrj 		cdip = (dev_info_t *)arg;
296430Smrj 		return (pciide_initchild(dip, cdip));
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
299430Smrj 		cdip = (dev_info_t *)arg;
300430Smrj 		pdptr = ddi_get_parent_data(cdip);
301430Smrj 		ddi_set_parent_data(cdip, NULL);
302430Smrj 		ddi_set_name_addr(cdip, NULL);
303430Smrj 		kmem_free(pdptr, PCIIDE_PDSIZE);
304430Smrj 		return (DDI_SUCCESS);
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
3070Sstevel@tonic-gate 		*(int *)result = 3;
3080Sstevel@tonic-gate 		return (DDI_SUCCESS);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
3110Sstevel@tonic-gate 		/*
3120Sstevel@tonic-gate 		 * Adjust the rnumbers based on which controller instance
3130Sstevel@tonic-gate 		 * is requested; adjust for the 2 tuples per controller.
3140Sstevel@tonic-gate 		 */
3150Sstevel@tonic-gate 		if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
3160Sstevel@tonic-gate 			controller = 0;
3170Sstevel@tonic-gate 		else
3180Sstevel@tonic-gate 			controller = 1;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		switch (rnumber = *(int *)arg) {
3220Sstevel@tonic-gate 		case 0:
3230Sstevel@tonic-gate 		case 1:
3240Sstevel@tonic-gate 			rnumber += (2 * controller);
3250Sstevel@tonic-gate 			break;
3260Sstevel@tonic-gate 		case 2:
3270Sstevel@tonic-gate 			rnumber = 4;
3280Sstevel@tonic-gate 			break;
3290Sstevel@tonic-gate 		default:
3300Sstevel@tonic-gate 			PDBG(("pciide_ctlops invalid rnumber\n"));
3310Sstevel@tonic-gate 			return (DDI_FAILURE);
3320Sstevel@tonic-gate 		}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 		if (PCIIDE_PRE26(dip)) {
3360Sstevel@tonic-gate 			int	old_rnumber;
3370Sstevel@tonic-gate 			int	new_rnumber;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 			old_rnumber = rnumber;
3400Sstevel@tonic-gate 			new_rnumber
3415295Srandyf 			    = pciide_pre26_rnumber_map(dip, old_rnumber);
3420Sstevel@tonic-gate 			PDBG(("pciide rnumber old %d new %d\n",
3435295Srandyf 			    old_rnumber, new_rnumber));
3440Sstevel@tonic-gate 			rnumber = new_rnumber;
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * Add 1 to skip over the PCI config space tuple
3490Sstevel@tonic-gate 		 */
3500Sstevel@tonic-gate 		rnumber++;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		/*
3530Sstevel@tonic-gate 		 * If it's not tuple #2 pass the adjusted request to my parent
3540Sstevel@tonic-gate 		 */
3550Sstevel@tonic-gate 		if (*(int *)arg != 2) {
3560Sstevel@tonic-gate 			return (ddi_ctlops(dip, dip, ctlop, &rnumber, result));
3570Sstevel@tonic-gate 		}
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		/*
3600Sstevel@tonic-gate 		 * Handle my child's reg-tuple #2 here by splitting my 16 byte
3610Sstevel@tonic-gate 		 * reg-tuple #4 into two 8 byte ranges based on the
3620Sstevel@tonic-gate 		 * the child's controller #.
3630Sstevel@tonic-gate 		 */
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 		tmp = 8;
3660Sstevel@tonic-gate 		rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		/*
3690Sstevel@tonic-gate 		 * Allow for the possibility of less than 16 bytes by
3700Sstevel@tonic-gate 		 * by checking what's actually returned for my reg-tuple #4.
3710Sstevel@tonic-gate 		 */
3720Sstevel@tonic-gate 		if (controller == 1) {
3730Sstevel@tonic-gate 			if (tmp < 8)
3740Sstevel@tonic-gate 				tmp = 0;
3750Sstevel@tonic-gate 			else
3760Sstevel@tonic-gate 				tmp -= 8;
3770Sstevel@tonic-gate 		}
3780Sstevel@tonic-gate 		if (tmp > 8)
3790Sstevel@tonic-gate 			tmp = 8;
3800Sstevel@tonic-gate 		*(off_t *)result = tmp;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 		return (rc);
3830Sstevel@tonic-gate 
384*8550SSeth.Goldberg@Sun.COM 	case DDI_CTLOPS_ATTACH:
385*8550SSeth.Goldberg@Sun.COM 	case DDI_CTLOPS_DETACH:
386*8550SSeth.Goldberg@Sun.COM 		/*
387*8550SSeth.Goldberg@Sun.COM 		 * Don't pass child ide ATTACH/DETACH to parent
388*8550SSeth.Goldberg@Sun.COM 		 */
389*8550SSeth.Goldberg@Sun.COM 		return (DDI_SUCCESS);
390*8550SSeth.Goldberg@Sun.COM 
3910Sstevel@tonic-gate 	default:
3920Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate /*
3970Sstevel@tonic-gate  * IEEE 1275 Working Group Proposal #414 says that the Primary
3980Sstevel@tonic-gate  * controller is "ata@0" and the Secondary controller "ata@1".
3990Sstevel@tonic-gate  *
4000Sstevel@tonic-gate  * By the time we get here, boot Bootconf (2.6+) has created devinfo
4010Sstevel@tonic-gate  * nodes with the appropriate "reg", "assigned-addresses" and "interrupts"
4020Sstevel@tonic-gate  * properites on the pci-ide node and both ide child nodes.
4030Sstevel@tonic-gate  *
4040Sstevel@tonic-gate  * In compatibility mode the "reg" and "assigned-addresses" properties
4050Sstevel@tonic-gate  * of the pci-ide node are set up like this:
4060Sstevel@tonic-gate  *
4070Sstevel@tonic-gate  *   1. PCI-IDE Nexus
4080Sstevel@tonic-gate  *
4090Sstevel@tonic-gate  *	interrupts=0
4100Sstevel@tonic-gate  *				(addr-hi addr-mid addr-low size-hi  size-low)
4110Sstevel@tonic-gate  *	reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
4120Sstevel@tonic-gate  *				81000000.00000000.000001f0.00000000.00000008
4130Sstevel@tonic-gate  *				81000000.00000000.000003f4.00000000.00000004
4140Sstevel@tonic-gate  *				81000000.00000000,00000170.00000000.00000008
4150Sstevel@tonic-gate  *				81000000.00000000,00000374.00000000.00000004
4160Sstevel@tonic-gate  *				01000020.00000000,-[BAR4]-.00000000.00000010
4170Sstevel@tonic-gate  *
4180Sstevel@tonic-gate  * In native PCI mode the "reg" and "assigned-addresses" properties
4190Sstevel@tonic-gate  * would be set up like this:
4200Sstevel@tonic-gate  *
4210Sstevel@tonic-gate  *   2. PCI-IDE Nexus
4220Sstevel@tonic-gate  *
4230Sstevel@tonic-gate  *	interrupts=0
4240Sstevel@tonic-gate  *	reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
4250Sstevel@tonic-gate  *				01000010.00000000.-[BAR0]-.00000000.00000008
4260Sstevel@tonic-gate  *				01000014,00000000.-[BAR1]-.00000000.00000004
4270Sstevel@tonic-gate  *				01000018.00000000.-[BAR2]-.00000000.00000008
4280Sstevel@tonic-gate  *				0100001c.00000000.-[BAR3]-.00000000.00000004
4290Sstevel@tonic-gate  *				01000020.00000000.-[BAR4]-.00000000.00000010
4300Sstevel@tonic-gate  *
4310Sstevel@tonic-gate  *
4320Sstevel@tonic-gate  * In both modes the child nodes simply have the following:
4330Sstevel@tonic-gate  *
4340Sstevel@tonic-gate  *   2. primary controller (compatibility mode)
4350Sstevel@tonic-gate  *
4360Sstevel@tonic-gate  *	interrupts=14
4370Sstevel@tonic-gate  *	reg=00000000
4380Sstevel@tonic-gate  *
4390Sstevel@tonic-gate  *   3. secondary controller
4400Sstevel@tonic-gate  *
4410Sstevel@tonic-gate  *	interrupts=15
4420Sstevel@tonic-gate  *	reg=00000001
4430Sstevel@tonic-gate  *
4440Sstevel@tonic-gate  * The pciide_bus_map() function is responsible for turning requests
4450Sstevel@tonic-gate  * to map primary or secondary controller rnumbers into mapping requests
4460Sstevel@tonic-gate  * of the appropriate regspec on the pci-ide node.
4470Sstevel@tonic-gate  *
4480Sstevel@tonic-gate  */
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate static int
4510Sstevel@tonic-gate pciide_initchild(dev_info_t *mydip, dev_info_t *cdip)
4520Sstevel@tonic-gate {
4530Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
4540Sstevel@tonic-gate 	struct intrspec	*ispecp;
4550Sstevel@tonic-gate 	int	vec;
4560Sstevel@tonic-gate 	int	*rp;
4570Sstevel@tonic-gate 	uint_t	proplen;
4580Sstevel@tonic-gate 	char	name[80];
4590Sstevel@tonic-gate 	int	dev;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	PDBG(("pciide_initchild\n"));
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	/*
4640Sstevel@tonic-gate 	 * Set the address portion of the node name based on
4650Sstevel@tonic-gate 	 * the controller number (0 or 1) from the 'reg' property.
4660Sstevel@tonic-gate 	 */
4670Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
4680Sstevel@tonic-gate 	    "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) {
4690Sstevel@tonic-gate 		PDBG(("pciide_intchild prop error\n"));
4700Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	/*
4740Sstevel@tonic-gate 	 * copy the controller number and
4750Sstevel@tonic-gate 	 * free the memory allocated by ddi_prop_lookup_int_array
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	dev = *rp;
4780Sstevel@tonic-gate 	ddi_prop_free(rp);
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	/*
4810Sstevel@tonic-gate 	 * I only support two controllers per device, determine
4820Sstevel@tonic-gate 	 * which this one is and set its unit address.
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	if (dev > 1) {
4850Sstevel@tonic-gate 		PDBG(("pciide_initchild bad dev\n"));
4860Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
4870Sstevel@tonic-gate 	}
4880Sstevel@tonic-gate 	(void) sprintf(name, "%d", dev);
4890Sstevel@tonic-gate 	ddi_set_name_addr(cdip, name);
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * determine if this instance is running in native or compat mode
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 	pciide_compat_setup(mydip, cdip, dev);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	/* interrupts property is required */
4970Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(cdip)) {
4980Sstevel@tonic-gate 		vec = 1;
4990Sstevel@tonic-gate 	} else {
5000Sstevel@tonic-gate 		/*
5010Sstevel@tonic-gate 		 * In compatibility mode, dev 0 should always be
5020Sstevel@tonic-gate 		 * IRQ 14 and dev 1 is IRQ 15. If for some reason
5030Sstevel@tonic-gate 		 * this needs to be changed, do it via the interrupts
5040Sstevel@tonic-gate 		 * property in the ata.conf file.
5050Sstevel@tonic-gate 		 */
5060Sstevel@tonic-gate 		vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
5075295Srandyf 		    "interrupts", -1);
5080Sstevel@tonic-gate 		if (vec == -1) {
5090Sstevel@tonic-gate 			/* setup compatibility mode interrupts */
5100Sstevel@tonic-gate 			if (dev == 0) {
5110Sstevel@tonic-gate 				vec = 14;
5120Sstevel@tonic-gate 			} else if (dev == 1) {
5130Sstevel@tonic-gate 				vec = 15;
5140Sstevel@tonic-gate 			} else {
5150Sstevel@tonic-gate 				PDBG(("pciide_initchild bad intr\n"));
5160Sstevel@tonic-gate 				return (DDI_NOT_WELL_FORMED);
5170Sstevel@tonic-gate 			}
5180Sstevel@tonic-gate 		}
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
521430Smrj 	pdptr = kmem_zalloc(PCIIDE_PDSIZE, KM_SLEEP);
5220Sstevel@tonic-gate 	ispecp = (struct intrspec *)(pdptr + 1);
5230Sstevel@tonic-gate 	pdptr->par_nintr = 1;
5240Sstevel@tonic-gate 	pdptr->par_intr = ispecp;
5250Sstevel@tonic-gate 	ispecp->intrspec_vec = vec;
5260Sstevel@tonic-gate 	ddi_set_parent_data(cdip, pdptr);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	PDBG(("pciide_initchild okay\n"));
5290Sstevel@tonic-gate 	return (DDI_SUCCESS);
5300Sstevel@tonic-gate }
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate static int
5330Sstevel@tonic-gate pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
5340Sstevel@tonic-gate     off_t offset, off_t len, caddr_t *vaddrp)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	dev_info_t *pdip;
5370Sstevel@tonic-gate 	int	    rnumber = mp->map_obj.rnumber;
5380Sstevel@tonic-gate 	int	    controller;
5390Sstevel@tonic-gate 	int	    rc;
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	PDBG(("pciide_bus_map\n"));
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
5440Sstevel@tonic-gate 		controller = 0;
5450Sstevel@tonic-gate 	else
5460Sstevel@tonic-gate 		controller = 1;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	/*
5490Sstevel@tonic-gate 	 * Adjust the rnumbers based on which controller instance
5500Sstevel@tonic-gate 	 * is being mapped; adjust for the 2 tuples per controller.
5510Sstevel@tonic-gate 	 */
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	switch (rnumber) {
5540Sstevel@tonic-gate 	case 0:
5550Sstevel@tonic-gate 	case 1:
5560Sstevel@tonic-gate 		mp->map_obj.rnumber += (controller * 2);
5570Sstevel@tonic-gate 		break;
5580Sstevel@tonic-gate 	case 2:
5590Sstevel@tonic-gate 		/*
5600Sstevel@tonic-gate 		 * split the 16 I/O ports into two 8 port ranges
5610Sstevel@tonic-gate 		 */
5620Sstevel@tonic-gate 		mp->map_obj.rnumber = 4;
5630Sstevel@tonic-gate 		if (offset + len > 8) {
5640Sstevel@tonic-gate 			PDBG(("pciide_bus_map offset\n"));
5650Sstevel@tonic-gate 			return (DDI_FAILURE);
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 		if (len == 0)
5680Sstevel@tonic-gate 			len = 8 - offset;
5690Sstevel@tonic-gate 		offset += 8 * controller;
5700Sstevel@tonic-gate 		break;
5710Sstevel@tonic-gate 	default:
5720Sstevel@tonic-gate 		PDBG(("pciide_bus_map default\n"));
5730Sstevel@tonic-gate 		return (DDI_FAILURE);
5740Sstevel@tonic-gate 	}
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (PCIIDE_PRE26(dip)) {
5770Sstevel@tonic-gate 		int	old_rnumber;
5780Sstevel@tonic-gate 		int	new_rnumber;
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 		old_rnumber = mp->map_obj.rnumber;
5810Sstevel@tonic-gate 		new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber);
5820Sstevel@tonic-gate 		PDBG(("pciide rnumber old %d new %d\n",
5835295Srandyf 		    old_rnumber, new_rnumber));
5840Sstevel@tonic-gate 		mp->map_obj.rnumber = new_rnumber;
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/*
5880Sstevel@tonic-gate 	 * Add 1 to skip over the PCI config space tuple
5890Sstevel@tonic-gate 	 */
5900Sstevel@tonic-gate 	mp->map_obj.rnumber++;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	/*
5940Sstevel@tonic-gate 	 * pass the adjusted request to my parent
5950Sstevel@tonic-gate 	 */
5960Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
5970Sstevel@tonic-gate 	rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map))
5985295Srandyf 	    (pdip, dip, mp, offset, len, vaddrp));
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok"));
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	return (rc);
6030Sstevel@tonic-gate }
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate static struct intrspec *
6070Sstevel@tonic-gate pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate 	struct ddi_parent_private_data *ppdptr;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	PDBG(("pciide_get_ispec\n"));
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	/*
6140Sstevel@tonic-gate 	 * Native mode PCI-IDE controllers share the parent's
6150Sstevel@tonic-gate 	 * PCI interrupt line.
6160Sstevel@tonic-gate 	 *
6170Sstevel@tonic-gate 	 * Compatibility mode PCI-IDE controllers have their
6180Sstevel@tonic-gate 	 * own intrspec which specifies ISA IRQ 14 or 15.
6190Sstevel@tonic-gate 	 *
6200Sstevel@tonic-gate 	 */
6210Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(rdip)) {
6220Sstevel@tonic-gate 		ddi_intrspec_t is;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 		is = pci_intx_get_ispec(dip, dip, inumber);
6250Sstevel@tonic-gate 		PDBG(("pciide_get_ispec okay\n"));
6260Sstevel@tonic-gate 		return ((struct intrspec *)is);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/* Else compatibility mode, use the ISA IRQ */
6300Sstevel@tonic-gate 	if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) {
6310Sstevel@tonic-gate 		PDBG(("pciide_get_ispec null\n"));
6320Sstevel@tonic-gate 		return (NULL);
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	/* validate the interrupt number  */
6360Sstevel@tonic-gate 	if (inumber >= ppdptr->par_nintr) {
6370Sstevel@tonic-gate 		PDBG(("pciide_get_inum\n"));
6380Sstevel@tonic-gate 		return (NULL);
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	PDBG(("pciide_get_ispec ok\n"));
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	return ((struct intrspec *)&ppdptr->par_intr[inumber]);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate static	int
6470Sstevel@tonic-gate pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
6480Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, int *pri)
6490Sstevel@tonic-gate {
6500Sstevel@tonic-gate 	struct intrspec	*ispecp;
6510Sstevel@tonic-gate 	int		*intpriorities;
6520Sstevel@tonic-gate 	uint_t		 num_intpriorities;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	PDBG(("pciide_get_pri\n"));
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) {
6570Sstevel@tonic-gate 		PDBG(("pciide_get_pri null\n"));
6580Sstevel@tonic-gate 		return (DDI_FAILURE);
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(rdip)) {
6620Sstevel@tonic-gate 		*pri = ispecp->intrspec_pri;
6630Sstevel@tonic-gate 		PDBG(("pciide_get_pri ok\n"));
6640Sstevel@tonic-gate 		return (DDI_SUCCESS);
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	/* check if the intrspec has been initialized */
6680Sstevel@tonic-gate 	if (ispecp->intrspec_pri != 0) {
6690Sstevel@tonic-gate 		*pri = ispecp->intrspec_pri;
6700Sstevel@tonic-gate 		PDBG(("pciide_get_pri ok2\n"));
6710Sstevel@tonic-gate 		return (DDI_SUCCESS);
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/* Use a default of level 5  */
6750Sstevel@tonic-gate 	ispecp->intrspec_pri = 5;
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * If there's an interrupt-priorities property, use it to
6790Sstevel@tonic-gate 	 * over-ride the default interrupt priority.
6800Sstevel@tonic-gate 	 */
6810Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
6820Sstevel@tonic-gate 	    "interrupt-priorities", &intpriorities, &num_intpriorities) ==
6830Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
6840Sstevel@tonic-gate 		if (hdlp->ih_inum < num_intpriorities)
6850Sstevel@tonic-gate 			ispecp->intrspec_pri = intpriorities[hdlp->ih_inum];
6860Sstevel@tonic-gate 		ddi_prop_free(intpriorities);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 	*pri = ispecp->intrspec_pri;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	PDBG(("pciide_get_pri ok3\n"));
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	return (DDI_SUCCESS);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate static int
6960Sstevel@tonic-gate pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
6970Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
6980Sstevel@tonic-gate {
6990Sstevel@tonic-gate 	struct intrspec	*ispecp;
7000Sstevel@tonic-gate 	int		rc;
7010Sstevel@tonic-gate 	int		pri = 0;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n",
7040Sstevel@tonic-gate 	    (void *)dip, (void *)rdip, intr_op, (void *)hdlp));
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	switch (intr_op) {
7070Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
7080Sstevel@tonic-gate 		*(int *)result = DDI_INTR_TYPE_FIXED;
7090Sstevel@tonic-gate 		break;
7100Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
7111290Sanish 		*(int *)result = DDI_INTR_FLAG_LEVEL;
7120Sstevel@tonic-gate 		break;
7130Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
7142580Sanish 	case DDI_INTROP_NAVAIL:
7152580Sanish 		*(int *)result = (!PCIIDE_NATIVE_MODE(rdip)) ?
7162580Sanish 		    i_ddi_get_intx_nintrs(rdip) : 1;
7170Sstevel@tonic-gate 		break;
7180Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
7190Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
7200Sstevel@tonic-gate 		    NULL)
7210Sstevel@tonic-gate 			return (DDI_FAILURE);
7220Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
7230Sstevel@tonic-gate 		break;
7240Sstevel@tonic-gate 	case DDI_INTROP_FREE:
7250Sstevel@tonic-gate 		break;
7260Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
7270Sstevel@tonic-gate 		if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) {
7280Sstevel@tonic-gate 			*(int *)result = 0;
7290Sstevel@tonic-gate 			return (DDI_FAILURE);
7300Sstevel@tonic-gate 		}
7310Sstevel@tonic-gate 		*(int *)result = pri;
7320Sstevel@tonic-gate 		break;
7330Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
7340Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
7350Sstevel@tonic-gate 		    NULL)
7360Sstevel@tonic-gate 			return (DDI_FAILURE);
737916Sschwartz 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
7380Sstevel@tonic-gate 		ispecp->intrspec_func = hdlp->ih_cb_func;
7390Sstevel@tonic-gate 		break;
7400Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
7410Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
7420Sstevel@tonic-gate 		    NULL)
7430Sstevel@tonic-gate 			return (DDI_FAILURE);
7440Sstevel@tonic-gate 		ispecp->intrspec_func = (uint_t (*)()) 0;
7450Sstevel@tonic-gate 		break;
7460Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
7470Sstevel@tonic-gate 	/* FALLTHRU */
7480Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
7490Sstevel@tonic-gate 		if (PCIIDE_NATIVE_MODE(rdip)) {
7500Sstevel@tonic-gate 			rdip = dip;
7510Sstevel@tonic-gate 			dip = ddi_get_parent(dip);
7520Sstevel@tonic-gate 		} else {	/* get ptr to the root node */
7530Sstevel@tonic-gate 			dip = ddi_root_node();
7540Sstevel@tonic-gate 		}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 		rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip,
7570Sstevel@tonic-gate 		    rdip, intr_op, hdlp, result);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate #ifdef	DEBUG
7600Sstevel@tonic-gate 		if (intr_op == DDI_INTROP_ENABLE) {
7610Sstevel@tonic-gate 			PDBG(("pciide_enable rc=%d", rc));
7620Sstevel@tonic-gate 		} else
7630Sstevel@tonic-gate 			PDBG(("pciide_disable rc=%d", rc));
7640Sstevel@tonic-gate #endif	/* DEBUG */
7650Sstevel@tonic-gate 		return (rc);
7660Sstevel@tonic-gate 	default:
7670Sstevel@tonic-gate 		return (DDI_FAILURE);
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	return (DDI_SUCCESS);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /*
7740Sstevel@tonic-gate  * This is one of the places where controller specific setup needs to be
7750Sstevel@tonic-gate  * considered.
7760Sstevel@tonic-gate  * At this point the controller was already pre-qualified as a known and
7770Sstevel@tonic-gate  * supported pciide controller.
7780Sstevel@tonic-gate  * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE
7790Sstevel@tonic-gate  * programming interface code but rather PCI_MASS_OTHER sub-class code
7800Sstevel@tonic-gate  * without any additional data.
7810Sstevel@tonic-gate  * For those controllers IDE programming interface cannot be extracted
7820Sstevel@tonic-gate  * from PCI class - we assume that they are pci-native type and we fix
7830Sstevel@tonic-gate  * the programming interface used by other functions.
7840Sstevel@tonic-gate  * The programming interface byte is set to indicate pci-native mode
7850Sstevel@tonic-gate  * for both controllers and the Bus Master DMA capabilitiy of the controller.
7860Sstevel@tonic-gate  */
7870Sstevel@tonic-gate static void
7880Sstevel@tonic-gate pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate 	int	class_code;
7910Sstevel@tonic-gate 	int	rc = DDI_PROP_SUCCESS;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip,
7940Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "class-code", 0);
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) {
7970Sstevel@tonic-gate 		/*
7980Sstevel@tonic-gate 		 * Controller provides PCI_MASS_IDE sub-class code first
7990Sstevel@tonic-gate 		 * (implied IDE programming interface)
8000Sstevel@tonic-gate 		 */
8010Sstevel@tonic-gate 		if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) ||
8020Sstevel@tonic-gate 		    (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) {
8038419SKerry.Shu@Sun.COM 			rc = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
8045295Srandyf 			    "compatibility-mode", 1);
8050Sstevel@tonic-gate 			if (rc != DDI_PROP_SUCCESS)
8060Sstevel@tonic-gate 				cmn_err(CE_WARN,
8070Sstevel@tonic-gate 				    "pciide prop error %d compat-mode", rc);
8080Sstevel@tonic-gate 		}
8090Sstevel@tonic-gate 	} else {
8100Sstevel@tonic-gate 		/*
8110Sstevel@tonic-gate 		 * Pci-ide controllers not providing PCI_MASS_IDE sub-class are
8120Sstevel@tonic-gate 		 * assumed to be of pci-native type and bus master DMA capable.
8130Sstevel@tonic-gate 		 * Programming interface part of the class-code property is
8140Sstevel@tonic-gate 		 * fixed here.
8150Sstevel@tonic-gate 		 */
8160Sstevel@tonic-gate 		class_code &= 0x00ffff00;
8170Sstevel@tonic-gate 		class_code |= PCI_IDE_IF_BM_CAP_MASK |
8185295Srandyf 		    PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC;
8190Sstevel@tonic-gate 		rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip,
8205295Srandyf 		    "class-code", class_code);
8210Sstevel@tonic-gate 		if (rc != DDI_PROP_SUCCESS)
8220Sstevel@tonic-gate 			cmn_err(CE_WARN,
8230Sstevel@tonic-gate 			    "pciide prop error %d class-code", rc);
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate static int
8290Sstevel@tonic-gate pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber)
8300Sstevel@tonic-gate {
8310Sstevel@tonic-gate 	int	pri_native;
8320Sstevel@tonic-gate 	int	sec_native;
8330Sstevel@tonic-gate 	int	class_code;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS,
8365295Srandyf 	    "class-code", 0);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE;
8390Sstevel@tonic-gate 	sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	return (pciide_map_rnumber(rnumber, pri_native, sec_native));
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate /*
8460Sstevel@tonic-gate  *	The canonical order of the reg property tuples for the
8470Sstevel@tonic-gate  *	Base Address Registers is supposed to be:
8480Sstevel@tonic-gate  *
8490Sstevel@tonic-gate  *	primary controller (BAR 0)
8500Sstevel@tonic-gate  *	primary controller (BAR 1)
8510Sstevel@tonic-gate  *	secondary controller (BAR 2)
8520Sstevel@tonic-gate  *	secondary controller (BAR 3)
8530Sstevel@tonic-gate  *	bus mastering regs (BAR 4)
8540Sstevel@tonic-gate  *
8550Sstevel@tonic-gate  *	For 2.6, bootconf has been fixed to always generate the
8560Sstevel@tonic-gate  *	reg property (and assigned-addresses property) tuples
8570Sstevel@tonic-gate  *	in the above order.
8580Sstevel@tonic-gate  *
8590Sstevel@tonic-gate  *	But in releases prior to 2.6 the order varies depending
8600Sstevel@tonic-gate  *	on whether compatibility or native mode is being used for
8610Sstevel@tonic-gate  *	each controller. There ends up being four possible
8620Sstevel@tonic-gate  *	orders:
8630Sstevel@tonic-gate  *
8640Sstevel@tonic-gate  *	BM, P0, P1, S0, S1	primary compatible, secondary compatible
8650Sstevel@tonic-gate  *	S0, S1, BM, P0, P1	primary compatible, secondary native
8660Sstevel@tonic-gate  *	P0, P1, BM, S0, S1	primary native, secondary compatible
8670Sstevel@tonic-gate  *	P0, P1, S0, S1, BM	primary native, secondary native
8680Sstevel@tonic-gate  *
8690Sstevel@tonic-gate  *	where: Px is the primary tuples, Sx the secondary tuples, and
8700Sstevel@tonic-gate  *	B the Bus Master tuple.
8710Sstevel@tonic-gate  *
8720Sstevel@tonic-gate  *	Here's the results for each of the four states:
8730Sstevel@tonic-gate  *
8740Sstevel@tonic-gate  *		0, 1, 2, 3, 4
8750Sstevel@tonic-gate  *
8760Sstevel@tonic-gate  *	CC	1, 2, 3, 4, 0
8770Sstevel@tonic-gate  *	CN	3, 4, 0, 1, 2
8780Sstevel@tonic-gate  *	NC	0, 1, 3, 4, 2
8790Sstevel@tonic-gate  *	NN	0, 1, 2, 3, 4
8800Sstevel@tonic-gate  *
8810Sstevel@tonic-gate  *	C = compatible(!native) == 0
8820Sstevel@tonic-gate  *	N = native == 1
8830Sstevel@tonic-gate  *
8840Sstevel@tonic-gate  *	Here's the transformation matrix:
8850Sstevel@tonic-gate  */
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate static	int	pciide_transform[2][2][5] = {
8880Sstevel@tonic-gate /*  P  S  */
8890Sstevel@tonic-gate /* [C][C] */	+1, +1, +1, +1, -4,
8900Sstevel@tonic-gate /* [C][N] */	+3, +3, -2, -2, -2,
8910Sstevel@tonic-gate /* [N][C] */	+0, +0, +1, +1, -2,
8920Sstevel@tonic-gate /* [N][N] */	+0, +0, +0, +0, +0
8930Sstevel@tonic-gate };
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate static int
8970Sstevel@tonic-gate pciide_map_rnumber(int rnumber, int pri_native, int sec_native)
8980Sstevel@tonic-gate {
8990Sstevel@tonic-gate 	/* transform flags into indexes */
9000Sstevel@tonic-gate 	pri_native = pri_native ? 1 : 0;
9010Sstevel@tonic-gate 	sec_native = sec_native ? 1 : 0;
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	rnumber += pciide_transform[pri_native][sec_native][rnumber];
9040Sstevel@tonic-gate 	return (rnumber);
9050Sstevel@tonic-gate }
906