xref: /titanic_52/usr/src/uts/common/io/pci-ide/pci-ide.c (revision cd21e7c548ae2a3b5e522244bf798f2a6b4ba02d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a54f81fbSanish  * Common Development and Distribution License (the "License").
6a54f81fbSanish  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
225cd376e8SJimmy Vetayases  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
24*cd21e7c5SGarrett D'Amore /*
25*cd21e7c5SGarrett D'Amore  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
26*cd21e7c5SGarrett D'Amore  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  *	PCI-IDE bus nexus driver
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/errno.h>
367c478bd9Sstevel@tonic-gate #include <sys/debug.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddidmareq.h>
387c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
397c478bd9Sstevel@tonic-gate #include <sys/dma_engine.h>
407c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
4342f87ea2SGuoli Shu #include <sys/sunndi.h>
447a364d25Sschwartz #include <sys/mach_intr.h>
457c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
467c478bd9Sstevel@tonic-gate #include <sys/pci.h>
477c478bd9Sstevel@tonic-gate #include <sys/promif.h>
487c478bd9Sstevel@tonic-gate #include <sys/pci_intr_lib.h>
497ff178cdSJimmy Vetayases #include <sys/apic.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate int	pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
522df1fe9cSrandyf int	pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	PCIIDE_NATIVE_MODE(dip)						\
557c478bd9Sstevel@tonic-gate 	(!ddi_prop_exists(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, 	\
567c478bd9Sstevel@tonic-gate 	"compatibility-mode"))
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	PCIIDE_PRE26(dip)	\
597c478bd9Sstevel@tonic-gate 	ddi_prop_exists(DDI_DEV_T_ANY, (dip), 0, "ignore-hardware-nodes")
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	PCI_IDE_IF_BM_CAP_MASK	0x80
627c478bd9Sstevel@tonic-gate 
63192f7333Smrj #define	PCIIDE_PDSIZE	(sizeof (struct ddi_parent_private_data) + \
64192f7333Smrj 	sizeof (struct intrspec))
65192f7333Smrj 
667c478bd9Sstevel@tonic-gate #ifdef DEBUG
677c478bd9Sstevel@tonic-gate static int pci_ide_debug = 0;
687c478bd9Sstevel@tonic-gate #define	PDBG(fmt)				\
697c478bd9Sstevel@tonic-gate 		if (pci_ide_debug) {		\
707c478bd9Sstevel@tonic-gate 			prom_printf fmt;	\
717c478bd9Sstevel@tonic-gate 		}
727c478bd9Sstevel@tonic-gate #else
737c478bd9Sstevel@tonic-gate #define	PDBG(fmt)
747c478bd9Sstevel@tonic-gate #endif
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #ifndef	TRUE
777c478bd9Sstevel@tonic-gate #define	TRUE	1
787c478bd9Sstevel@tonic-gate #endif
797c478bd9Sstevel@tonic-gate #ifndef	FALSE
807c478bd9Sstevel@tonic-gate #define	FALSE	0
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /*
847c478bd9Sstevel@tonic-gate  * bus_ops functions
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static int		pciide_bus_map(dev_info_t *dip, dev_info_t *rdip,
887c478bd9Sstevel@tonic-gate 				ddi_map_req_t *mp, off_t offset, off_t len,
897c478bd9Sstevel@tonic-gate 				caddr_t *vaddrp);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static	int		pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip,
927c478bd9Sstevel@tonic-gate 				ddi_ctl_enum_t ctlop, void *arg,
937c478bd9Sstevel@tonic-gate 				void *result);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate static	int		pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
967c478bd9Sstevel@tonic-gate 				ddi_intr_handle_impl_t *hdlp, int *pri);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static	int		pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip,
997c478bd9Sstevel@tonic-gate 				ddi_intr_op_t intr_op,
1007c478bd9Sstevel@tonic-gate 				ddi_intr_handle_impl_t *hdlp, void *result);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static struct intrspec *pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip,
1037c478bd9Sstevel@tonic-gate 				int inum);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Local Functions
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate static	int	pciide_initchild(dev_info_t *mydip, dev_info_t *cdip);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static	void	pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip,
1117c478bd9Sstevel@tonic-gate 				    int dev);
1127c478bd9Sstevel@tonic-gate static	int	pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber);
1137c478bd9Sstevel@tonic-gate static	int	pciide_map_rnumber(int canonical_rnumber, int pri_native,
1147c478bd9Sstevel@tonic-gate 				    int sec_native);
1157ff178cdSJimmy Vetayases static int pciide_alloc_intr(dev_info_t *, dev_info_t *,
1167ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *, void *);
1177ff178cdSJimmy Vetayases static int pciide_free_intr(dev_info_t *, dev_info_t *,
1187ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *);
1197c478bd9Sstevel@tonic-gate 
1207ff178cdSJimmy Vetayases extern int (*psm_intr_ops)(dev_info_t *, ddi_intr_handle_impl_t *,
1217ff178cdSJimmy Vetayases     psm_intr_op_t, int *);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /*
1247c478bd9Sstevel@tonic-gate  * Config information
1257c478bd9Sstevel@tonic-gate  */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate struct bus_ops pciide_bus_ops = {
1287c478bd9Sstevel@tonic-gate 	BUSO_REV,
1297c478bd9Sstevel@tonic-gate 	pciide_bus_map,
1307c478bd9Sstevel@tonic-gate 	0,
1317c478bd9Sstevel@tonic-gate 	0,
1327c478bd9Sstevel@tonic-gate 	0,
1337c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,
134*cd21e7c5SGarrett D'Amore 	0,
1357c478bd9Sstevel@tonic-gate 	ddi_dma_allochdl,
1367c478bd9Sstevel@tonic-gate 	ddi_dma_freehdl,
1377c478bd9Sstevel@tonic-gate 	ddi_dma_bindhdl,
1387c478bd9Sstevel@tonic-gate 	ddi_dma_unbindhdl,
1397c478bd9Sstevel@tonic-gate 	ddi_dma_flush,
1407c478bd9Sstevel@tonic-gate 	ddi_dma_win,
1417c478bd9Sstevel@tonic-gate 	ddi_dma_mctl,
1427c478bd9Sstevel@tonic-gate 	pciide_ddi_ctlops,
1437c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
1447c478bd9Sstevel@tonic-gate 	0,	/* (*bus_get_eventcookie)();	*/
1457c478bd9Sstevel@tonic-gate 	0,	/* (*bus_add_eventcall)();	*/
1467c478bd9Sstevel@tonic-gate 	0,	/* (*bus_remove_eventcall)();	*/
1477c478bd9Sstevel@tonic-gate 	0,	/* (*bus_post_event)();		*/
1487c478bd9Sstevel@tonic-gate 	0,
1497c478bd9Sstevel@tonic-gate 	0,
1507c478bd9Sstevel@tonic-gate 	0,
1517c478bd9Sstevel@tonic-gate 	0,
1527c478bd9Sstevel@tonic-gate 	0,
1537c478bd9Sstevel@tonic-gate 	0,
1547c478bd9Sstevel@tonic-gate 	0,
1557c478bd9Sstevel@tonic-gate 	0,
1567c478bd9Sstevel@tonic-gate 	pciide_intr_ops
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate struct dev_ops pciide_ops = {
1607c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1617c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
1627c478bd9Sstevel@tonic-gate 	ddi_no_info,		/* info */
1637c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
1647c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
1657c478bd9Sstevel@tonic-gate 	pciide_attach,		/* attach */
1662df1fe9cSrandyf 	pciide_detach,		/* detach */
1677c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
1687c478bd9Sstevel@tonic-gate 	(struct cb_ops *)0,	/* driver operations */
16919397407SSherry Moore 	&pciide_bus_ops,	/* bus operations */
17019397407SSherry Moore 	NULL,			/* power */
17119397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
1727c478bd9Sstevel@tonic-gate };
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1797c478bd9Sstevel@tonic-gate 	&mod_driverops, /* Type of module.  This is PCI-IDE bus driver */
18019397407SSherry Moore 	"pciide nexus driver for 'PCI-IDE' 1.26",
1817c478bd9Sstevel@tonic-gate 	&pciide_ops,	/* driver ops */
1827c478bd9Sstevel@tonic-gate };
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1857c478bd9Sstevel@tonic-gate 	MODREV_1,
1867c478bd9Sstevel@tonic-gate 	&modldrv,
1877c478bd9Sstevel@tonic-gate 	NULL
1887c478bd9Sstevel@tonic-gate };
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate int
1927c478bd9Sstevel@tonic-gate _init(void)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate int
1987c478bd9Sstevel@tonic-gate _fini(void)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate int
2047c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2077c478bd9Sstevel@tonic-gate }
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate int
2107c478bd9Sstevel@tonic-gate pciide_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2117c478bd9Sstevel@tonic-gate {
2127c478bd9Sstevel@tonic-gate 	uint16_t cmdreg;
2137c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t conf_hdl = NULL;
2147c478bd9Sstevel@tonic-gate 	int rc;
2157c478bd9Sstevel@tonic-gate 
2162df1fe9cSrandyf 	switch (cmd) {
2172df1fe9cSrandyf 	case DDI_ATTACH:
2187c478bd9Sstevel@tonic-gate 		/*
2197c478bd9Sstevel@tonic-gate 		 * Make sure bus-mastering is enabled, even if
2207c478bd9Sstevel@tonic-gate 		 * BIOS didn't.
2217c478bd9Sstevel@tonic-gate 		 */
222ae0b9099Smrj 		rc = pci_config_setup(dip, &conf_hdl);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 		/*
2257c478bd9Sstevel@tonic-gate 		 * In case of error, return SUCCESS. This is because
2267c478bd9Sstevel@tonic-gate 		 * bus-mastering could be already enabled by BIOS.
2277c478bd9Sstevel@tonic-gate 		 */
2287c478bd9Sstevel@tonic-gate 		if (rc != DDI_SUCCESS)
2297c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
2307c478bd9Sstevel@tonic-gate 
231ae0b9099Smrj 		cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
2327c478bd9Sstevel@tonic-gate 		if ((cmdreg & PCI_COMM_ME) == 0) {
233ae0b9099Smrj 			pci_config_put16(conf_hdl, PCI_CONF_COMM,
2347c478bd9Sstevel@tonic-gate 			    cmdreg | PCI_COMM_ME);
2357c478bd9Sstevel@tonic-gate 		}
236ae0b9099Smrj 		pci_config_teardown(&conf_hdl);
2377c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2382df1fe9cSrandyf 
2392df1fe9cSrandyf 	case DDI_RESUME:
2402df1fe9cSrandyf 		/* Restore our PCI configuration header */
2412df1fe9cSrandyf 		if (pci_restore_config_regs(dip) != DDI_SUCCESS) {
2422df1fe9cSrandyf 			/*
2432df1fe9cSrandyf 			 * XXXX
2442df1fe9cSrandyf 			 * This is a pretty bad thing.  However, for some
2452df1fe9cSrandyf 			 * reason it always happens.  To further complicate
2462df1fe9cSrandyf 			 * things, it appears if we just ignore this, we
2472df1fe9cSrandyf 			 * properly resume.  For now, all I want to do is
2482df1fe9cSrandyf 			 * to generate this message so that it doesn't get
2492df1fe9cSrandyf 			 * forgotten.
2502df1fe9cSrandyf 			 */
2512df1fe9cSrandyf 			cmn_err(CE_WARN,
2522df1fe9cSrandyf 			    "Couldn't restore PCI config regs for %s(%p)",
2532df1fe9cSrandyf 			    ddi_node_name(dip), (void *) dip);
2542df1fe9cSrandyf 		}
2552df1fe9cSrandyf #ifdef	DEBUG
2562df1fe9cSrandyf 		/* Bus mastering should still be enabled */
2572df1fe9cSrandyf 		if (pci_config_setup(dip, &conf_hdl) != DDI_SUCCESS)
2582df1fe9cSrandyf 			return (DDI_FAILURE);
2592df1fe9cSrandyf 		cmdreg = pci_config_get16(conf_hdl, PCI_CONF_COMM);
2602df1fe9cSrandyf 		ASSERT((cmdreg & PCI_COMM_ME) != 0);
2612df1fe9cSrandyf 		pci_config_teardown(&conf_hdl);
2622df1fe9cSrandyf #endif
2632df1fe9cSrandyf 		return (DDI_SUCCESS);
2642df1fe9cSrandyf 	}
2652df1fe9cSrandyf 
2667c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2692df1fe9cSrandyf /*ARGSUSED*/
2702df1fe9cSrandyf int
2712df1fe9cSrandyf pciide_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2722df1fe9cSrandyf {
2732df1fe9cSrandyf 	switch (cmd) {
2742df1fe9cSrandyf 	case DDI_DETACH:
2752df1fe9cSrandyf 		return (DDI_SUCCESS);
2762df1fe9cSrandyf 	case DDI_SUSPEND:
2772df1fe9cSrandyf 		/* Save our PCI configuration header */
2782df1fe9cSrandyf 		if (pci_save_config_regs(dip) != DDI_SUCCESS) {
2792df1fe9cSrandyf 			/* Don't suspend if we cannot save config regs */
2802df1fe9cSrandyf 			return (DDI_FAILURE);
2812df1fe9cSrandyf 		}
2822df1fe9cSrandyf 		return (DDI_SUCCESS);
2832df1fe9cSrandyf 	}
2842df1fe9cSrandyf 	return (DDI_FAILURE);
2852df1fe9cSrandyf }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2887c478bd9Sstevel@tonic-gate static int
2897c478bd9Sstevel@tonic-gate pciide_ddi_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
2907c478bd9Sstevel@tonic-gate     void *arg, void *result)
2917c478bd9Sstevel@tonic-gate {
292192f7333Smrj 	dev_info_t *cdip;
293192f7333Smrj 	int controller;
294192f7333Smrj 	void *pdptr;
295192f7333Smrj 	int rnumber;
2967c478bd9Sstevel@tonic-gate 	off_t tmp;
297192f7333Smrj 	int rc;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	PDBG(("pciide_bus_ctl\n"));
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	switch (ctlop) {
3027c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
303192f7333Smrj 		cdip = (dev_info_t *)arg;
304192f7333Smrj 		return (pciide_initchild(dip, cdip));
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
307192f7333Smrj 		cdip = (dev_info_t *)arg;
308192f7333Smrj 		pdptr = ddi_get_parent_data(cdip);
309192f7333Smrj 		ddi_set_parent_data(cdip, NULL);
310192f7333Smrj 		ddi_set_name_addr(cdip, NULL);
311192f7333Smrj 		kmem_free(pdptr, PCIIDE_PDSIZE);
312192f7333Smrj 		return (DDI_SUCCESS);
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
3157c478bd9Sstevel@tonic-gate 		*(int *)result = 3;
3167c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
3197c478bd9Sstevel@tonic-gate 		/*
3207c478bd9Sstevel@tonic-gate 		 * Adjust the rnumbers based on which controller instance
3217c478bd9Sstevel@tonic-gate 		 * is requested; adjust for the 2 tuples per controller.
3227c478bd9Sstevel@tonic-gate 		 */
3237c478bd9Sstevel@tonic-gate 		if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
3247c478bd9Sstevel@tonic-gate 			controller = 0;
3257c478bd9Sstevel@tonic-gate 		else
3267c478bd9Sstevel@tonic-gate 			controller = 1;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		switch (rnumber = *(int *)arg) {
3307c478bd9Sstevel@tonic-gate 		case 0:
3317c478bd9Sstevel@tonic-gate 		case 1:
3327c478bd9Sstevel@tonic-gate 			rnumber += (2 * controller);
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		case 2:
3357c478bd9Sstevel@tonic-gate 			rnumber = 4;
3367c478bd9Sstevel@tonic-gate 			break;
3377c478bd9Sstevel@tonic-gate 		default:
3387c478bd9Sstevel@tonic-gate 			PDBG(("pciide_ctlops invalid rnumber\n"));
3397c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 		if (PCIIDE_PRE26(dip)) {
3447c478bd9Sstevel@tonic-gate 			int	old_rnumber;
3457c478bd9Sstevel@tonic-gate 			int	new_rnumber;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 			old_rnumber = rnumber;
3487c478bd9Sstevel@tonic-gate 			new_rnumber
3497c478bd9Sstevel@tonic-gate 			    = pciide_pre26_rnumber_map(dip, old_rnumber);
3507c478bd9Sstevel@tonic-gate 			PDBG(("pciide rnumber old %d new %d\n",
3517c478bd9Sstevel@tonic-gate 			    old_rnumber, new_rnumber));
3527c478bd9Sstevel@tonic-gate 			rnumber = new_rnumber;
3537c478bd9Sstevel@tonic-gate 		}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		/*
3567c478bd9Sstevel@tonic-gate 		 * Add 1 to skip over the PCI config space tuple
3577c478bd9Sstevel@tonic-gate 		 */
3587c478bd9Sstevel@tonic-gate 		rnumber++;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		/*
3617c478bd9Sstevel@tonic-gate 		 * If it's not tuple #2 pass the adjusted request to my parent
3627c478bd9Sstevel@tonic-gate 		 */
3637c478bd9Sstevel@tonic-gate 		if (*(int *)arg != 2) {
3647c478bd9Sstevel@tonic-gate 			return (ddi_ctlops(dip, dip, ctlop, &rnumber, result));
3657c478bd9Sstevel@tonic-gate 		}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 		/*
3687c478bd9Sstevel@tonic-gate 		 * Handle my child's reg-tuple #2 here by splitting my 16 byte
3697c478bd9Sstevel@tonic-gate 		 * reg-tuple #4 into two 8 byte ranges based on the
3707c478bd9Sstevel@tonic-gate 		 * the child's controller #.
3717c478bd9Sstevel@tonic-gate 		 */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		tmp = 8;
3747c478bd9Sstevel@tonic-gate 		rc = ddi_ctlops(dip, dip, ctlop, &rnumber, &tmp);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/*
3777c478bd9Sstevel@tonic-gate 		 * Allow for the possibility of less than 16 bytes by
3787c478bd9Sstevel@tonic-gate 		 * by checking what's actually returned for my reg-tuple #4.
3797c478bd9Sstevel@tonic-gate 		 */
3807c478bd9Sstevel@tonic-gate 		if (controller == 1) {
3817c478bd9Sstevel@tonic-gate 			if (tmp < 8)
3827c478bd9Sstevel@tonic-gate 				tmp = 0;
3837c478bd9Sstevel@tonic-gate 			else
3847c478bd9Sstevel@tonic-gate 				tmp -= 8;
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 		if (tmp > 8)
3877c478bd9Sstevel@tonic-gate 			tmp = 8;
3887c478bd9Sstevel@tonic-gate 		*(off_t *)result = tmp;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		return (rc);
3917c478bd9Sstevel@tonic-gate 
3920f1b305eSSeth Goldberg 	case DDI_CTLOPS_ATTACH:
3930f1b305eSSeth Goldberg 	case DDI_CTLOPS_DETACH:
3940f1b305eSSeth Goldberg 		/*
3950f1b305eSSeth Goldberg 		 * Don't pass child ide ATTACH/DETACH to parent
3960f1b305eSSeth Goldberg 		 */
3970f1b305eSSeth Goldberg 		return (DDI_SUCCESS);
3980f1b305eSSeth Goldberg 
3997c478bd9Sstevel@tonic-gate 	default:
4007c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate  * IEEE 1275 Working Group Proposal #414 says that the Primary
4067c478bd9Sstevel@tonic-gate  * controller is "ata@0" and the Secondary controller "ata@1".
4077c478bd9Sstevel@tonic-gate  *
4087c478bd9Sstevel@tonic-gate  * By the time we get here, boot Bootconf (2.6+) has created devinfo
4097c478bd9Sstevel@tonic-gate  * nodes with the appropriate "reg", "assigned-addresses" and "interrupts"
4107c478bd9Sstevel@tonic-gate  * properites on the pci-ide node and both ide child nodes.
4117c478bd9Sstevel@tonic-gate  *
4127c478bd9Sstevel@tonic-gate  * In compatibility mode the "reg" and "assigned-addresses" properties
4137c478bd9Sstevel@tonic-gate  * of the pci-ide node are set up like this:
4147c478bd9Sstevel@tonic-gate  *
4157c478bd9Sstevel@tonic-gate  *   1. PCI-IDE Nexus
4167c478bd9Sstevel@tonic-gate  *
4177c478bd9Sstevel@tonic-gate  *	interrupts=0
4187c478bd9Sstevel@tonic-gate  *				(addr-hi addr-mid addr-low size-hi  size-low)
4197c478bd9Sstevel@tonic-gate  *	reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
4207c478bd9Sstevel@tonic-gate  *				81000000.00000000.000001f0.00000000.00000008
4217c478bd9Sstevel@tonic-gate  *				81000000.00000000.000003f4.00000000.00000004
4227c478bd9Sstevel@tonic-gate  *				81000000.00000000,00000170.00000000.00000008
4237c478bd9Sstevel@tonic-gate  *				81000000.00000000,00000374.00000000.00000004
4247c478bd9Sstevel@tonic-gate  *				01000020.00000000,-[BAR4]-.00000000.00000010
4257c478bd9Sstevel@tonic-gate  *
4267c478bd9Sstevel@tonic-gate  * In native PCI mode the "reg" and "assigned-addresses" properties
4277c478bd9Sstevel@tonic-gate  * would be set up like this:
4287c478bd9Sstevel@tonic-gate  *
4297c478bd9Sstevel@tonic-gate  *   2. PCI-IDE Nexus
4307c478bd9Sstevel@tonic-gate  *
4317c478bd9Sstevel@tonic-gate  *	interrupts=0
4327c478bd9Sstevel@tonic-gate  *	reg= assigned-addresses=00000000.00000000.00000000.00000000.00000000
4337c478bd9Sstevel@tonic-gate  *				01000010.00000000.-[BAR0]-.00000000.00000008
4347c478bd9Sstevel@tonic-gate  *				01000014,00000000.-[BAR1]-.00000000.00000004
4357c478bd9Sstevel@tonic-gate  *				01000018.00000000.-[BAR2]-.00000000.00000008
4367c478bd9Sstevel@tonic-gate  *				0100001c.00000000.-[BAR3]-.00000000.00000004
4377c478bd9Sstevel@tonic-gate  *				01000020.00000000.-[BAR4]-.00000000.00000010
4387c478bd9Sstevel@tonic-gate  *
4397c478bd9Sstevel@tonic-gate  *
4407c478bd9Sstevel@tonic-gate  * In both modes the child nodes simply have the following:
4417c478bd9Sstevel@tonic-gate  *
4427c478bd9Sstevel@tonic-gate  *   2. primary controller (compatibility mode)
4437c478bd9Sstevel@tonic-gate  *
4447c478bd9Sstevel@tonic-gate  *	interrupts=14
4457c478bd9Sstevel@tonic-gate  *	reg=00000000
4467c478bd9Sstevel@tonic-gate  *
4477c478bd9Sstevel@tonic-gate  *   3. secondary controller
4487c478bd9Sstevel@tonic-gate  *
4497c478bd9Sstevel@tonic-gate  *	interrupts=15
4507c478bd9Sstevel@tonic-gate  *	reg=00000001
4517c478bd9Sstevel@tonic-gate  *
4527c478bd9Sstevel@tonic-gate  * The pciide_bus_map() function is responsible for turning requests
4537c478bd9Sstevel@tonic-gate  * to map primary or secondary controller rnumbers into mapping requests
4547c478bd9Sstevel@tonic-gate  * of the appropriate regspec on the pci-ide node.
4557c478bd9Sstevel@tonic-gate  *
4567c478bd9Sstevel@tonic-gate  */
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate static int
4597c478bd9Sstevel@tonic-gate pciide_initchild(dev_info_t *mydip, dev_info_t *cdip)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *pdptr;
4627c478bd9Sstevel@tonic-gate 	struct intrspec	*ispecp;
4637c478bd9Sstevel@tonic-gate 	int	vec;
4647c478bd9Sstevel@tonic-gate 	int	*rp;
4657c478bd9Sstevel@tonic-gate 	uint_t	proplen;
4667c478bd9Sstevel@tonic-gate 	char	name[80];
4677c478bd9Sstevel@tonic-gate 	int	dev;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	PDBG(("pciide_initchild\n"));
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/*
4727c478bd9Sstevel@tonic-gate 	 * Set the address portion of the node name based on
4737c478bd9Sstevel@tonic-gate 	 * the controller number (0 or 1) from the 'reg' property.
4747c478bd9Sstevel@tonic-gate 	 */
4757c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
4767c478bd9Sstevel@tonic-gate 	    "reg", &rp, (uint_t *)&proplen) != DDI_PROP_SUCCESS) {
4777c478bd9Sstevel@tonic-gate 		PDBG(("pciide_intchild prop error\n"));
4787c478bd9Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	/*
4827c478bd9Sstevel@tonic-gate 	 * copy the controller number and
4837c478bd9Sstevel@tonic-gate 	 * free the memory allocated by ddi_prop_lookup_int_array
4847c478bd9Sstevel@tonic-gate 	 */
4857c478bd9Sstevel@tonic-gate 	dev = *rp;
4867c478bd9Sstevel@tonic-gate 	ddi_prop_free(rp);
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	/*
4897c478bd9Sstevel@tonic-gate 	 * I only support two controllers per device, determine
4907c478bd9Sstevel@tonic-gate 	 * which this one is and set its unit address.
4917c478bd9Sstevel@tonic-gate 	 */
4927c478bd9Sstevel@tonic-gate 	if (dev > 1) {
4937c478bd9Sstevel@tonic-gate 		PDBG(("pciide_initchild bad dev\n"));
4947c478bd9Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%d", dev);
4977c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(cdip, name);
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/*
5007c478bd9Sstevel@tonic-gate 	 * determine if this instance is running in native or compat mode
5017c478bd9Sstevel@tonic-gate 	 */
5027c478bd9Sstevel@tonic-gate 	pciide_compat_setup(mydip, cdip, dev);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	/* interrupts property is required */
5057c478bd9Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(cdip)) {
5067c478bd9Sstevel@tonic-gate 		vec = 1;
5077c478bd9Sstevel@tonic-gate 	} else {
5087c478bd9Sstevel@tonic-gate 		/*
5097c478bd9Sstevel@tonic-gate 		 * In compatibility mode, dev 0 should always be
5107c478bd9Sstevel@tonic-gate 		 * IRQ 14 and dev 1 is IRQ 15. If for some reason
5117c478bd9Sstevel@tonic-gate 		 * this needs to be changed, do it via the interrupts
5127c478bd9Sstevel@tonic-gate 		 * property in the ata.conf file.
5137c478bd9Sstevel@tonic-gate 		 */
5147c478bd9Sstevel@tonic-gate 		vec = ddi_prop_get_int(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
5157c478bd9Sstevel@tonic-gate 		    "interrupts", -1);
5167c478bd9Sstevel@tonic-gate 		if (vec == -1) {
5177c478bd9Sstevel@tonic-gate 			/* setup compatibility mode interrupts */
5187c478bd9Sstevel@tonic-gate 			if (dev == 0) {
5197c478bd9Sstevel@tonic-gate 				vec = 14;
5207c478bd9Sstevel@tonic-gate 			} else if (dev == 1) {
5217c478bd9Sstevel@tonic-gate 				vec = 15;
5227c478bd9Sstevel@tonic-gate 			} else {
5237c478bd9Sstevel@tonic-gate 				PDBG(("pciide_initchild bad intr\n"));
5247c478bd9Sstevel@tonic-gate 				return (DDI_NOT_WELL_FORMED);
5257c478bd9Sstevel@tonic-gate 			}
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
529192f7333Smrj 	pdptr = kmem_zalloc(PCIIDE_PDSIZE, KM_SLEEP);
5307c478bd9Sstevel@tonic-gate 	ispecp = (struct intrspec *)(pdptr + 1);
5317c478bd9Sstevel@tonic-gate 	pdptr->par_nintr = 1;
5327c478bd9Sstevel@tonic-gate 	pdptr->par_intr = ispecp;
5337c478bd9Sstevel@tonic-gate 	ispecp->intrspec_vec = vec;
5347c478bd9Sstevel@tonic-gate 	ddi_set_parent_data(cdip, pdptr);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	PDBG(("pciide_initchild okay\n"));
5377c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate static int
5417c478bd9Sstevel@tonic-gate pciide_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
5427c478bd9Sstevel@tonic-gate     off_t offset, off_t len, caddr_t *vaddrp)
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
5457c478bd9Sstevel@tonic-gate 	int	    rnumber = mp->map_obj.rnumber;
5467c478bd9Sstevel@tonic-gate 	int	    controller;
5477c478bd9Sstevel@tonic-gate 	int	    rc;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	PDBG(("pciide_bus_map\n"));
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (strcmp("0", ddi_get_name_addr(rdip)) == 0)
5527c478bd9Sstevel@tonic-gate 		controller = 0;
5537c478bd9Sstevel@tonic-gate 	else
5547c478bd9Sstevel@tonic-gate 		controller = 1;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	/*
5577c478bd9Sstevel@tonic-gate 	 * Adjust the rnumbers based on which controller instance
5587c478bd9Sstevel@tonic-gate 	 * is being mapped; adjust for the 2 tuples per controller.
5597c478bd9Sstevel@tonic-gate 	 */
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	switch (rnumber) {
5627c478bd9Sstevel@tonic-gate 	case 0:
5637c478bd9Sstevel@tonic-gate 	case 1:
5647c478bd9Sstevel@tonic-gate 		mp->map_obj.rnumber += (controller * 2);
5657c478bd9Sstevel@tonic-gate 		break;
5667c478bd9Sstevel@tonic-gate 	case 2:
5677c478bd9Sstevel@tonic-gate 		/*
5687c478bd9Sstevel@tonic-gate 		 * split the 16 I/O ports into two 8 port ranges
5697c478bd9Sstevel@tonic-gate 		 */
5707c478bd9Sstevel@tonic-gate 		mp->map_obj.rnumber = 4;
5717c478bd9Sstevel@tonic-gate 		if (offset + len > 8) {
5727c478bd9Sstevel@tonic-gate 			PDBG(("pciide_bus_map offset\n"));
5737c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5747c478bd9Sstevel@tonic-gate 		}
5757c478bd9Sstevel@tonic-gate 		if (len == 0)
5767c478bd9Sstevel@tonic-gate 			len = 8 - offset;
5777c478bd9Sstevel@tonic-gate 		offset += 8 * controller;
5787c478bd9Sstevel@tonic-gate 		break;
5797c478bd9Sstevel@tonic-gate 	default:
5807c478bd9Sstevel@tonic-gate 		PDBG(("pciide_bus_map default\n"));
5817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (PCIIDE_PRE26(dip)) {
5857c478bd9Sstevel@tonic-gate 		int	old_rnumber;
5867c478bd9Sstevel@tonic-gate 		int	new_rnumber;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		old_rnumber = mp->map_obj.rnumber;
5897c478bd9Sstevel@tonic-gate 		new_rnumber = pciide_pre26_rnumber_map(dip, old_rnumber);
5907c478bd9Sstevel@tonic-gate 		PDBG(("pciide rnumber old %d new %d\n",
5917c478bd9Sstevel@tonic-gate 		    old_rnumber, new_rnumber));
5927c478bd9Sstevel@tonic-gate 		mp->map_obj.rnumber = new_rnumber;
5937c478bd9Sstevel@tonic-gate 	}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/*
5967c478bd9Sstevel@tonic-gate 	 * Add 1 to skip over the PCI config space tuple
5977c478bd9Sstevel@tonic-gate 	 */
5987c478bd9Sstevel@tonic-gate 	mp->map_obj.rnumber++;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/*
6027c478bd9Sstevel@tonic-gate 	 * pass the adjusted request to my parent
6037c478bd9Sstevel@tonic-gate 	 */
6047c478bd9Sstevel@tonic-gate 	pdip = ddi_get_parent(dip);
6057c478bd9Sstevel@tonic-gate 	rc = ((*(DEVI(pdip)->devi_ops->devo_bus_ops->bus_map))
6067c478bd9Sstevel@tonic-gate 	    (pdip, dip, mp, offset, len, vaddrp));
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	PDBG(("pciide_bus_map %s\n", rc == DDI_SUCCESS ? "okay" : "!ok"));
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	return (rc);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate static struct intrspec *
6157c478bd9Sstevel@tonic-gate pciide_get_ispec(dev_info_t *dip, dev_info_t *rdip, int inumber)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	struct ddi_parent_private_data *ppdptr;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	PDBG(("pciide_get_ispec\n"));
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/*
6227c478bd9Sstevel@tonic-gate 	 * Native mode PCI-IDE controllers share the parent's
6237c478bd9Sstevel@tonic-gate 	 * PCI interrupt line.
6247c478bd9Sstevel@tonic-gate 	 *
6257c478bd9Sstevel@tonic-gate 	 * Compatibility mode PCI-IDE controllers have their
6267c478bd9Sstevel@tonic-gate 	 * own intrspec which specifies ISA IRQ 14 or 15.
6277c478bd9Sstevel@tonic-gate 	 *
6287c478bd9Sstevel@tonic-gate 	 */
6297c478bd9Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(rdip)) {
6307c478bd9Sstevel@tonic-gate 		ddi_intrspec_t is;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 		is = pci_intx_get_ispec(dip, dip, inumber);
6337c478bd9Sstevel@tonic-gate 		PDBG(("pciide_get_ispec okay\n"));
6347c478bd9Sstevel@tonic-gate 		return ((struct intrspec *)is);
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/* Else compatibility mode, use the ISA IRQ */
6387c478bd9Sstevel@tonic-gate 	if ((ppdptr = ddi_get_parent_data(rdip)) == NULL) {
6397c478bd9Sstevel@tonic-gate 		PDBG(("pciide_get_ispec null\n"));
6407c478bd9Sstevel@tonic-gate 		return (NULL);
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/* validate the interrupt number  */
6447c478bd9Sstevel@tonic-gate 	if (inumber >= ppdptr->par_nintr) {
6457c478bd9Sstevel@tonic-gate 		PDBG(("pciide_get_inum\n"));
6467c478bd9Sstevel@tonic-gate 		return (NULL);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	PDBG(("pciide_get_ispec ok\n"));
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	return ((struct intrspec *)&ppdptr->par_intr[inumber]);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate static	int
6557c478bd9Sstevel@tonic-gate pciide_get_pri(dev_info_t *dip, dev_info_t *rdip,
6567c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, int *pri)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate 	struct intrspec	*ispecp;
6597c478bd9Sstevel@tonic-gate 	int		*intpriorities;
6607c478bd9Sstevel@tonic-gate 	uint_t		 num_intpriorities;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	PDBG(("pciide_get_pri\n"));
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL) {
6657c478bd9Sstevel@tonic-gate 		PDBG(("pciide_get_pri null\n"));
6667c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	if (PCIIDE_NATIVE_MODE(rdip)) {
6707c478bd9Sstevel@tonic-gate 		*pri = ispecp->intrspec_pri;
6717c478bd9Sstevel@tonic-gate 		PDBG(("pciide_get_pri ok\n"));
6727c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	/* check if the intrspec has been initialized */
6767c478bd9Sstevel@tonic-gate 	if (ispecp->intrspec_pri != 0) {
6777c478bd9Sstevel@tonic-gate 		*pri = ispecp->intrspec_pri;
6787c478bd9Sstevel@tonic-gate 		PDBG(("pciide_get_pri ok2\n"));
6797c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	/* Use a default of level 5  */
6837c478bd9Sstevel@tonic-gate 	ispecp->intrspec_pri = 5;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	/*
6867c478bd9Sstevel@tonic-gate 	 * If there's an interrupt-priorities property, use it to
6877c478bd9Sstevel@tonic-gate 	 * over-ride the default interrupt priority.
6887c478bd9Sstevel@tonic-gate 	 */
6897c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
6907c478bd9Sstevel@tonic-gate 	    "interrupt-priorities", &intpriorities, &num_intpriorities) ==
6917c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
6927c478bd9Sstevel@tonic-gate 		if (hdlp->ih_inum < num_intpriorities)
6937c478bd9Sstevel@tonic-gate 			ispecp->intrspec_pri = intpriorities[hdlp->ih_inum];
6947c478bd9Sstevel@tonic-gate 		ddi_prop_free(intpriorities);
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 	*pri = ispecp->intrspec_pri;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	PDBG(("pciide_get_pri ok3\n"));
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate static int
7047c478bd9Sstevel@tonic-gate pciide_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7057c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
7067c478bd9Sstevel@tonic-gate {
7077c478bd9Sstevel@tonic-gate 	struct intrspec	*ispecp;
7087c478bd9Sstevel@tonic-gate 	int		rc;
7097c478bd9Sstevel@tonic-gate 	int		pri = 0;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	PDBG(("pciide_intr_ops: dip %p rdip %p op %x hdlp %p\n",
7127c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)rdip, intr_op, (void *)hdlp));
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	switch (intr_op) {
7157c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
7167c478bd9Sstevel@tonic-gate 		*(int *)result = DDI_INTR_TYPE_FIXED;
7177c478bd9Sstevel@tonic-gate 		break;
7187c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
7190dc36b40Sanish 		*(int *)result = DDI_INTR_FLAG_LEVEL;
7207c478bd9Sstevel@tonic-gate 		break;
7217c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
722a54f81fbSanish 	case DDI_INTROP_NAVAIL:
723a54f81fbSanish 		*(int *)result = (!PCIIDE_NATIVE_MODE(rdip)) ?
724a54f81fbSanish 		    i_ddi_get_intx_nintrs(rdip) : 1;
7257c478bd9Sstevel@tonic-gate 		break;
7267c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
7277ff178cdSJimmy Vetayases 		return (pciide_alloc_intr(dip, rdip, hdlp, result));
7287c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
7297ff178cdSJimmy Vetayases 		return (pciide_free_intr(dip, rdip, hdlp));
7307c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
7317c478bd9Sstevel@tonic-gate 		if (pciide_get_pri(dip, rdip, hdlp, &pri) != DDI_SUCCESS) {
7327c478bd9Sstevel@tonic-gate 			*(int *)result = 0;
7337c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 		*(int *)result = pri;
7367c478bd9Sstevel@tonic-gate 		break;
7377c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
7387c478bd9Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
7397c478bd9Sstevel@tonic-gate 		    NULL)
7407c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7417a364d25Sschwartz 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispecp;
7427c478bd9Sstevel@tonic-gate 		ispecp->intrspec_func = hdlp->ih_cb_func;
7437c478bd9Sstevel@tonic-gate 		break;
7447c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
7457c478bd9Sstevel@tonic-gate 		if ((ispecp = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
7467c478bd9Sstevel@tonic-gate 		    NULL)
7477c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7487c478bd9Sstevel@tonic-gate 		ispecp->intrspec_func = (uint_t (*)()) 0;
7497c478bd9Sstevel@tonic-gate 		break;
7507c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
7517c478bd9Sstevel@tonic-gate 	/* FALLTHRU */
7527c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
7537c478bd9Sstevel@tonic-gate 		if (PCIIDE_NATIVE_MODE(rdip)) {
7547c478bd9Sstevel@tonic-gate 			rdip = dip;
7557c478bd9Sstevel@tonic-gate 			dip = ddi_get_parent(dip);
7567c478bd9Sstevel@tonic-gate 		} else {	/* get ptr to the root node */
7577c478bd9Sstevel@tonic-gate 			dip = ddi_root_node();
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		rc = (*(DEVI(dip)->devi_ops->devo_bus_ops->bus_intr_op))(dip,
7617c478bd9Sstevel@tonic-gate 		    rdip, intr_op, hdlp, result);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate #ifdef	DEBUG
7647c478bd9Sstevel@tonic-gate 		if (intr_op == DDI_INTROP_ENABLE) {
7657c478bd9Sstevel@tonic-gate 			PDBG(("pciide_enable rc=%d", rc));
7667c478bd9Sstevel@tonic-gate 		} else
7677c478bd9Sstevel@tonic-gate 			PDBG(("pciide_disable rc=%d", rc));
7687c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
7697c478bd9Sstevel@tonic-gate 		return (rc);
7707c478bd9Sstevel@tonic-gate 	default:
7717c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777ff178cdSJimmy Vetayases int
7787ff178cdSJimmy Vetayases pciide_alloc_intr(dev_info_t *dip, dev_info_t *rdip,
7797ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *hdlp, void *result)
7807ff178cdSJimmy Vetayases {
7817ff178cdSJimmy Vetayases 	struct intrspec		*ispec;
7827ff178cdSJimmy Vetayases 	ddi_intr_handle_impl_t	info_hdl;
7837ff178cdSJimmy Vetayases 	int			ret;
7847ff178cdSJimmy Vetayases 	int			free_phdl = 0;
7857ff178cdSJimmy Vetayases 	apic_get_type_t		type_info;
7867ff178cdSJimmy Vetayases 
7877ff178cdSJimmy Vetayases 	if (psm_intr_ops == NULL)
7887ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
7897ff178cdSJimmy Vetayases 
7907ff178cdSJimmy Vetayases 	if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) == NULL)
7917ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
7927ff178cdSJimmy Vetayases 
7937ff178cdSJimmy Vetayases 	/*
7947ff178cdSJimmy Vetayases 	 * If the PSM module is "APIX" then pass the request for it
7957ff178cdSJimmy Vetayases 	 * to allocate the vector now.
7967ff178cdSJimmy Vetayases 	 */
7977ff178cdSJimmy Vetayases 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
7987ff178cdSJimmy Vetayases 	info_hdl.ih_private = &type_info;
7997ff178cdSJimmy Vetayases 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
8007ff178cdSJimmy Vetayases 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
8017ff178cdSJimmy Vetayases 		if (hdlp->ih_private == NULL) { /* allocate phdl structure */
8027ff178cdSJimmy Vetayases 			free_phdl = 1;
8037ff178cdSJimmy Vetayases 			i_ddi_alloc_intr_phdl(hdlp);
8047ff178cdSJimmy Vetayases 		}
8057ff178cdSJimmy Vetayases 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
8067ff178cdSJimmy Vetayases 		if (PCIIDE_NATIVE_MODE(rdip)) {
8077ff178cdSJimmy Vetayases 			rdip = dip;
8087ff178cdSJimmy Vetayases 			dip = ddi_get_parent(dip);
8097ff178cdSJimmy Vetayases 		} else {	/* get ptr to the root node */
8107ff178cdSJimmy Vetayases 			dip = ddi_root_node();
8117ff178cdSJimmy Vetayases 		}
8127ff178cdSJimmy Vetayases 		ret = (*psm_intr_ops)(rdip, hdlp,
8137ff178cdSJimmy Vetayases 		    PSM_INTR_OP_ALLOC_VECTORS, result);
8147ff178cdSJimmy Vetayases 		if (free_phdl) { /* free up the phdl structure */
8157ff178cdSJimmy Vetayases 			free_phdl = 0;
8167ff178cdSJimmy Vetayases 			i_ddi_free_intr_phdl(hdlp);
8177ff178cdSJimmy Vetayases 		}
8187ff178cdSJimmy Vetayases 	} else {
8197ff178cdSJimmy Vetayases 		/*
8207ff178cdSJimmy Vetayases 		 * No APIX module; fall back to the old scheme where the
8217ff178cdSJimmy Vetayases 		 * interrupt vector is allocated during ddi_enable_intr() call.
8227ff178cdSJimmy Vetayases 		 */
8237ff178cdSJimmy Vetayases 		*(int *)result = hdlp->ih_scratch1;
8247ff178cdSJimmy Vetayases 		ret = DDI_SUCCESS;
8257ff178cdSJimmy Vetayases 	}
8267ff178cdSJimmy Vetayases 
8277ff178cdSJimmy Vetayases 	return (ret);
8287ff178cdSJimmy Vetayases }
8297ff178cdSJimmy Vetayases 
8307ff178cdSJimmy Vetayases int
8317ff178cdSJimmy Vetayases pciide_free_intr(dev_info_t *dip, dev_info_t *rdip,
8327ff178cdSJimmy Vetayases     ddi_intr_handle_impl_t *hdlp)
8337ff178cdSJimmy Vetayases {
8347ff178cdSJimmy Vetayases 	struct intrspec			*ispec;
8357ff178cdSJimmy Vetayases 	ddi_intr_handle_impl_t		info_hdl;
8367ff178cdSJimmy Vetayases 	apic_get_type_t			type_info;
8377ff178cdSJimmy Vetayases 
8387ff178cdSJimmy Vetayases 	if (psm_intr_ops == NULL)
8397ff178cdSJimmy Vetayases 		return (DDI_FAILURE);
8407ff178cdSJimmy Vetayases 
8417ff178cdSJimmy Vetayases 	/*
8427ff178cdSJimmy Vetayases 	 * If the PSM module is "APIX" then pass the request for it
8437ff178cdSJimmy Vetayases 	 * to free up the vector now.
8447ff178cdSJimmy Vetayases 	 */
8457ff178cdSJimmy Vetayases 	bzero(&info_hdl, sizeof (ddi_intr_handle_impl_t));
8467ff178cdSJimmy Vetayases 	info_hdl.ih_private = &type_info;
8477ff178cdSJimmy Vetayases 	if ((*psm_intr_ops)(NULL, &info_hdl, PSM_INTR_OP_APIC_TYPE, NULL) ==
8487ff178cdSJimmy Vetayases 	    PSM_SUCCESS && strcmp(type_info.avgi_type, APIC_APIX_NAME) == 0) {
8497ff178cdSJimmy Vetayases 		if ((ispec = pciide_get_ispec(dip, rdip, hdlp->ih_inum)) ==
8507ff178cdSJimmy Vetayases 		    NULL)
8517ff178cdSJimmy Vetayases 			return (DDI_FAILURE);
8527ff178cdSJimmy Vetayases 		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
8537ff178cdSJimmy Vetayases 		if (PCIIDE_NATIVE_MODE(rdip)) {
8547ff178cdSJimmy Vetayases 			rdip = dip;
8557ff178cdSJimmy Vetayases 			dip = ddi_get_parent(dip);
8567ff178cdSJimmy Vetayases 		} else {	/* get ptr to the root node */
8577ff178cdSJimmy Vetayases 			dip = ddi_root_node();
8587ff178cdSJimmy Vetayases 		}
8597ff178cdSJimmy Vetayases 		return ((*psm_intr_ops)(rdip, hdlp,
8607ff178cdSJimmy Vetayases 		    PSM_INTR_OP_FREE_VECTORS, NULL));
8617ff178cdSJimmy Vetayases 	}
8627ff178cdSJimmy Vetayases 
8637ff178cdSJimmy Vetayases 	/*
8647ff178cdSJimmy Vetayases 	 * No APIX module; fall back to the old scheme where
8657ff178cdSJimmy Vetayases 	 * the interrupt vector was already freed during
8667ff178cdSJimmy Vetayases 	 * ddi_disable_intr() call.
8677ff178cdSJimmy Vetayases 	 */
8687ff178cdSJimmy Vetayases 	return (DDI_SUCCESS);
8697ff178cdSJimmy Vetayases }
8707ff178cdSJimmy Vetayases 
8717c478bd9Sstevel@tonic-gate /*
8727c478bd9Sstevel@tonic-gate  * This is one of the places where controller specific setup needs to be
8737c478bd9Sstevel@tonic-gate  * considered.
8747c478bd9Sstevel@tonic-gate  * At this point the controller was already pre-qualified as a known and
8757c478bd9Sstevel@tonic-gate  * supported pciide controller.
8767c478bd9Sstevel@tonic-gate  * Some controllers do not provide PCI_MASS_IDE sub-class code and IDE
8777c478bd9Sstevel@tonic-gate  * programming interface code but rather PCI_MASS_OTHER sub-class code
8787c478bd9Sstevel@tonic-gate  * without any additional data.
8797c478bd9Sstevel@tonic-gate  * For those controllers IDE programming interface cannot be extracted
8807c478bd9Sstevel@tonic-gate  * from PCI class - we assume that they are pci-native type and we fix
8817c478bd9Sstevel@tonic-gate  * the programming interface used by other functions.
8827c478bd9Sstevel@tonic-gate  * The programming interface byte is set to indicate pci-native mode
8837c478bd9Sstevel@tonic-gate  * for both controllers and the Bus Master DMA capabilitiy of the controller.
8847c478bd9Sstevel@tonic-gate  */
8857c478bd9Sstevel@tonic-gate static void
8867c478bd9Sstevel@tonic-gate pciide_compat_setup(dev_info_t *mydip, dev_info_t *cdip, int dev)
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate 	int	class_code;
8897c478bd9Sstevel@tonic-gate 	int	rc = DDI_PROP_SUCCESS;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip,
8927c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "class-code", 0);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if (((class_code & 0x00FF00) >> 8) == PCI_MASS_IDE) {
8957c478bd9Sstevel@tonic-gate 		/*
8967c478bd9Sstevel@tonic-gate 		 * Controller provides PCI_MASS_IDE sub-class code first
8977c478bd9Sstevel@tonic-gate 		 * (implied IDE programming interface)
8987c478bd9Sstevel@tonic-gate 		 */
8997c478bd9Sstevel@tonic-gate 		if ((dev == 0 && !(class_code & PCI_IDE_IF_NATIVE_PRI)) ||
9007c478bd9Sstevel@tonic-gate 		    (dev == 1 && !(class_code & PCI_IDE_IF_NATIVE_SEC))) {
90142f87ea2SGuoli Shu 			rc = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
9027c478bd9Sstevel@tonic-gate 			    "compatibility-mode", 1);
9037c478bd9Sstevel@tonic-gate 			if (rc != DDI_PROP_SUCCESS)
9047c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
9057c478bd9Sstevel@tonic-gate 				    "pciide prop error %d compat-mode", rc);
9067c478bd9Sstevel@tonic-gate 		}
9077c478bd9Sstevel@tonic-gate 	} else {
9087c478bd9Sstevel@tonic-gate 		/*
9097c478bd9Sstevel@tonic-gate 		 * Pci-ide controllers not providing PCI_MASS_IDE sub-class are
9107c478bd9Sstevel@tonic-gate 		 * assumed to be of pci-native type and bus master DMA capable.
9117c478bd9Sstevel@tonic-gate 		 * Programming interface part of the class-code property is
9127c478bd9Sstevel@tonic-gate 		 * fixed here.
9137c478bd9Sstevel@tonic-gate 		 */
9147c478bd9Sstevel@tonic-gate 		class_code &= 0x00ffff00;
9157c478bd9Sstevel@tonic-gate 		class_code |= PCI_IDE_IF_BM_CAP_MASK |
9167c478bd9Sstevel@tonic-gate 		    PCI_IDE_IF_NATIVE_PRI | PCI_IDE_IF_NATIVE_SEC;
9177c478bd9Sstevel@tonic-gate 		rc = ddi_prop_update_int(DDI_DEV_T_NONE, mydip,
9187c478bd9Sstevel@tonic-gate 		    "class-code", class_code);
9197c478bd9Sstevel@tonic-gate 		if (rc != DDI_PROP_SUCCESS)
9207c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
9217c478bd9Sstevel@tonic-gate 			    "pciide prop error %d class-code", rc);
9227c478bd9Sstevel@tonic-gate 	}
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate static int
9277c478bd9Sstevel@tonic-gate pciide_pre26_rnumber_map(dev_info_t *mydip, int rnumber)
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate 	int	pri_native;
9307c478bd9Sstevel@tonic-gate 	int	sec_native;
9317c478bd9Sstevel@tonic-gate 	int	class_code;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	class_code = ddi_prop_get_int(DDI_DEV_T_ANY, mydip, DDI_PROP_DONTPASS,
9347c478bd9Sstevel@tonic-gate 	    "class-code", 0);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	pri_native = (class_code & PCI_IDE_IF_NATIVE_PRI) ? TRUE : FALSE;
9377c478bd9Sstevel@tonic-gate 	sec_native = (class_code & PCI_IDE_IF_NATIVE_SEC) ? TRUE : FALSE;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	return (pciide_map_rnumber(rnumber, pri_native, sec_native));
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate /*
9447c478bd9Sstevel@tonic-gate  *	The canonical order of the reg property tuples for the
9457c478bd9Sstevel@tonic-gate  *	Base Address Registers is supposed to be:
9467c478bd9Sstevel@tonic-gate  *
9477c478bd9Sstevel@tonic-gate  *	primary controller (BAR 0)
9487c478bd9Sstevel@tonic-gate  *	primary controller (BAR 1)
9497c478bd9Sstevel@tonic-gate  *	secondary controller (BAR 2)
9507c478bd9Sstevel@tonic-gate  *	secondary controller (BAR 3)
9517c478bd9Sstevel@tonic-gate  *	bus mastering regs (BAR 4)
9527c478bd9Sstevel@tonic-gate  *
9537c478bd9Sstevel@tonic-gate  *	For 2.6, bootconf has been fixed to always generate the
9547c478bd9Sstevel@tonic-gate  *	reg property (and assigned-addresses property) tuples
9557c478bd9Sstevel@tonic-gate  *	in the above order.
9567c478bd9Sstevel@tonic-gate  *
9577c478bd9Sstevel@tonic-gate  *	But in releases prior to 2.6 the order varies depending
9587c478bd9Sstevel@tonic-gate  *	on whether compatibility or native mode is being used for
9597c478bd9Sstevel@tonic-gate  *	each controller. There ends up being four possible
9607c478bd9Sstevel@tonic-gate  *	orders:
9617c478bd9Sstevel@tonic-gate  *
9627c478bd9Sstevel@tonic-gate  *	BM, P0, P1, S0, S1	primary compatible, secondary compatible
9637c478bd9Sstevel@tonic-gate  *	S0, S1, BM, P0, P1	primary compatible, secondary native
9647c478bd9Sstevel@tonic-gate  *	P0, P1, BM, S0, S1	primary native, secondary compatible
9657c478bd9Sstevel@tonic-gate  *	P0, P1, S0, S1, BM	primary native, secondary native
9667c478bd9Sstevel@tonic-gate  *
9677c478bd9Sstevel@tonic-gate  *	where: Px is the primary tuples, Sx the secondary tuples, and
9687c478bd9Sstevel@tonic-gate  *	B the Bus Master tuple.
9697c478bd9Sstevel@tonic-gate  *
9707c478bd9Sstevel@tonic-gate  *	Here's the results for each of the four states:
9717c478bd9Sstevel@tonic-gate  *
9727c478bd9Sstevel@tonic-gate  *		0, 1, 2, 3, 4
9737c478bd9Sstevel@tonic-gate  *
9747c478bd9Sstevel@tonic-gate  *	CC	1, 2, 3, 4, 0
9757c478bd9Sstevel@tonic-gate  *	CN	3, 4, 0, 1, 2
9767c478bd9Sstevel@tonic-gate  *	NC	0, 1, 3, 4, 2
9777c478bd9Sstevel@tonic-gate  *	NN	0, 1, 2, 3, 4
9787c478bd9Sstevel@tonic-gate  *
9797c478bd9Sstevel@tonic-gate  *	C = compatible(!native) == 0
9807c478bd9Sstevel@tonic-gate  *	N = native == 1
9817c478bd9Sstevel@tonic-gate  *
9827c478bd9Sstevel@tonic-gate  *	Here's the transformation matrix:
9837c478bd9Sstevel@tonic-gate  */
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate static	int	pciide_transform[2][2][5] = {
9867c478bd9Sstevel@tonic-gate /*  P  S  */
9877c478bd9Sstevel@tonic-gate /* [C][C] */	+1, +1, +1, +1, -4,
9887c478bd9Sstevel@tonic-gate /* [C][N] */	+3, +3, -2, -2, -2,
9897c478bd9Sstevel@tonic-gate /* [N][C] */	+0, +0, +1, +1, -2,
9907c478bd9Sstevel@tonic-gate /* [N][N] */	+0, +0, +0, +0, +0
9917c478bd9Sstevel@tonic-gate };
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate static int
9957c478bd9Sstevel@tonic-gate pciide_map_rnumber(int rnumber, int pri_native, int sec_native)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate 	/* transform flags into indexes */
9987c478bd9Sstevel@tonic-gate 	pri_native = pri_native ? 1 : 0;
9997c478bd9Sstevel@tonic-gate 	sec_native = sec_native ? 1 : 0;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	rnumber += pciide_transform[pri_native][sec_native][rnumber];
10027c478bd9Sstevel@tonic-gate 	return (rnumber);
10037c478bd9Sstevel@tonic-gate }
1004