xref: /titanic_51/usr/src/uts/sun4/io/ebus.c (revision a3282898e99eb4fd1912bf791254452bfd913d4b)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/conf.h>
317c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
357c478bd9Sstevel@tonic-gate #include <sys/pci.h>
367c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
387c478bd9Sstevel@tonic-gate #include <sys/errno.h>
397c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
407c478bd9Sstevel@tonic-gate #include <sys/debug.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <sys/ebus.h>
437c478bd9Sstevel@tonic-gate #include <sys/open.h>
447c478bd9Sstevel@tonic-gate #include <sys/stat.h>
457c478bd9Sstevel@tonic-gate #include <sys/file.h>
467c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #ifdef DEBUG
497c478bd9Sstevel@tonic-gate uint64_t ebus_debug_flags = 0;
507c478bd9Sstevel@tonic-gate #endif
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * The values of the following variables are used to initialize
547c478bd9Sstevel@tonic-gate  * the cache line size and latency timer registers in the ebus
557c478bd9Sstevel@tonic-gate  * configuration header.  Variables are used instead of constants
567c478bd9Sstevel@tonic-gate  * to allow tuning from the /etc/system file.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate static uint8_t ebus_cache_line_size = 0x10;	/* 64 bytes */
597c478bd9Sstevel@tonic-gate static uint8_t ebus_latency_timer = 0x40;	/* 64 PCI cycles */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * function prototypes for bus ops routines:
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate static int
657c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
667c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *addrp);
677c478bd9Sstevel@tonic-gate static int
687c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
697c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result);
707c478bd9Sstevel@tonic-gate static int
717c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
727c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result);
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate  * function prototypes for dev ops routines:
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate static int ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
787c478bd9Sstevel@tonic-gate static int ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
797c478bd9Sstevel@tonic-gate static int ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
807c478bd9Sstevel@tonic-gate 	void *arg, void **result);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate  * general function prototypes:
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate static int ebus_config(ebus_devstate_t *ebus_p);
867c478bd9Sstevel@tonic-gate static int ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
877c478bd9Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, pci_regspec_t *rp);
887c478bd9Sstevel@tonic-gate static int febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
897c478bd9Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, struct regspec *rp);
907c478bd9Sstevel@tonic-gate int get_ranges_prop(ebus_devstate_t *ebus_p);
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define	getprop(dip, name, addr, intp)		\
93*a3282898Scth 		ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
947c478bd9Sstevel@tonic-gate 				(name), (caddr_t)(addr), (intp))
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate static int ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp);
977c478bd9Sstevel@tonic-gate static int ebus_close(dev_t dev, int flags, int otyp, cred_t *credp);
987c478bd9Sstevel@tonic-gate static int ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
997c478bd9Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
1007c478bd9Sstevel@tonic-gate struct cb_ops ebus_cb_ops = {
1017c478bd9Sstevel@tonic-gate 	ebus_open,			/* open */
1027c478bd9Sstevel@tonic-gate 	ebus_close,			/* close */
1037c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
1047c478bd9Sstevel@tonic-gate 	nodev,				/* print */
1057c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
1067c478bd9Sstevel@tonic-gate 	nodev,				/* read */
1077c478bd9Sstevel@tonic-gate 	nodev,				/* write */
1087c478bd9Sstevel@tonic-gate 	ebus_ioctl,			/* ioctl */
1097c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
1107c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
1117c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
1127c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
1137c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
1147c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
1157c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
1167c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
1177c478bd9Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
1187c478bd9Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * bus ops and dev ops structures:
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static struct bus_ops ebus_bus_ops = {
1257c478bd9Sstevel@tonic-gate 	BUSO_REV,
1267c478bd9Sstevel@tonic-gate 	ebus_map,
1277c478bd9Sstevel@tonic-gate 	NULL,
1287c478bd9Sstevel@tonic-gate 	NULL,
1297c478bd9Sstevel@tonic-gate 	NULL,
1307c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,
1317c478bd9Sstevel@tonic-gate 	ddi_dma_map,
1327c478bd9Sstevel@tonic-gate 	ddi_dma_allochdl,
1337c478bd9Sstevel@tonic-gate 	ddi_dma_freehdl,
1347c478bd9Sstevel@tonic-gate 	ddi_dma_bindhdl,
1357c478bd9Sstevel@tonic-gate 	ddi_dma_unbindhdl,
1367c478bd9Sstevel@tonic-gate 	ddi_dma_flush,
1377c478bd9Sstevel@tonic-gate 	ddi_dma_win,
1387c478bd9Sstevel@tonic-gate 	ddi_dma_mctl,
1397c478bd9Sstevel@tonic-gate 	ebus_ctlops,
1407c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
1417c478bd9Sstevel@tonic-gate 	ndi_busop_get_eventcookie,
1427c478bd9Sstevel@tonic-gate 	ndi_busop_add_eventcall,
1437c478bd9Sstevel@tonic-gate 	ndi_busop_remove_eventcall,
1447c478bd9Sstevel@tonic-gate 	ndi_post_event,
1457c478bd9Sstevel@tonic-gate 	0,
1467c478bd9Sstevel@tonic-gate 	0,
1477c478bd9Sstevel@tonic-gate 	0,
1487c478bd9Sstevel@tonic-gate 	0,
1497c478bd9Sstevel@tonic-gate 	0,
1507c478bd9Sstevel@tonic-gate 	0,
1517c478bd9Sstevel@tonic-gate 	0,
1527c478bd9Sstevel@tonic-gate 	0,
1537c478bd9Sstevel@tonic-gate 	ebus_intr_ops
1547c478bd9Sstevel@tonic-gate };
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static struct dev_ops ebus_ops = {
1577c478bd9Sstevel@tonic-gate 	DEVO_REV,
1587c478bd9Sstevel@tonic-gate 	0,
1597c478bd9Sstevel@tonic-gate 	ebus_info,
1607c478bd9Sstevel@tonic-gate 	nulldev,
1617c478bd9Sstevel@tonic-gate 	nulldev,
1627c478bd9Sstevel@tonic-gate 	ebus_attach,
1637c478bd9Sstevel@tonic-gate 	ebus_detach,
1647c478bd9Sstevel@tonic-gate 	nodev,
1657c478bd9Sstevel@tonic-gate 	&ebus_cb_ops,
1667c478bd9Sstevel@tonic-gate 	&ebus_bus_ops
1677c478bd9Sstevel@tonic-gate };
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * module definitions:
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
1737c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
1767c478bd9Sstevel@tonic-gate 	&mod_driverops, 	/* Type of module.  This one is a driver */
1777c478bd9Sstevel@tonic-gate 	"ebus nexus driver %I%", /* Name of module. */
1787c478bd9Sstevel@tonic-gate 	&ebus_ops,		/* driver ops */
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
1827c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
1837c478bd9Sstevel@tonic-gate };
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate /*
1867c478bd9Sstevel@tonic-gate  * driver global data:
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate static void *per_ebus_state;		/* per-ebus soft state pointer */
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate int
1927c478bd9Sstevel@tonic-gate _init(void)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	int e;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	/*
1977c478bd9Sstevel@tonic-gate 	 * Initialize per-ebus soft state pointer.
1987c478bd9Sstevel@tonic-gate 	 */
1997c478bd9Sstevel@tonic-gate 	e = ddi_soft_state_init(&per_ebus_state, sizeof (ebus_devstate_t), 1);
2007c478bd9Sstevel@tonic-gate 	if (e != 0)
2017c478bd9Sstevel@tonic-gate 		return (e);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	/*
2047c478bd9Sstevel@tonic-gate 	 * Install the module.
2057c478bd9Sstevel@tonic-gate 	 */
2067c478bd9Sstevel@tonic-gate 	e = mod_install(&modlinkage);
2077c478bd9Sstevel@tonic-gate 	if (e != 0)
2087c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&per_ebus_state);
2097c478bd9Sstevel@tonic-gate 	return (e);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate int
2137c478bd9Sstevel@tonic-gate _fini(void)
2147c478bd9Sstevel@tonic-gate {
2157c478bd9Sstevel@tonic-gate 	int e;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/*
2187c478bd9Sstevel@tonic-gate 	 * Remove the module.
2197c478bd9Sstevel@tonic-gate 	 */
2207c478bd9Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
2217c478bd9Sstevel@tonic-gate 	if (e != 0)
2227c478bd9Sstevel@tonic-gate 		return (e);
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/*
2257c478bd9Sstevel@tonic-gate 	 * Free the soft state info.
2267c478bd9Sstevel@tonic-gate 	 */
2277c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&per_ebus_state);
2287c478bd9Sstevel@tonic-gate 	return (e);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate int
2327c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /* device driver entry points */
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2407c478bd9Sstevel@tonic-gate static int
2417c478bd9Sstevel@tonic-gate ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
2447c478bd9Sstevel@tonic-gate 	int instance;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	instance = getminor((dev_t)arg);
2477c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(instance);
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	switch (infocmd) {
2507c478bd9Sstevel@tonic-gate 	default:
2517c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2547c478bd9Sstevel@tonic-gate 		*result = (void *)instance;
2557c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2587c478bd9Sstevel@tonic-gate 		if (ebus_p == NULL)
2597c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2607c478bd9Sstevel@tonic-gate 		*result = (void *)ebus_p->dip;
2617c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate }
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate /*
2667c478bd9Sstevel@tonic-gate  * attach entry point:
2677c478bd9Sstevel@tonic-gate  *
2687c478bd9Sstevel@tonic-gate  * normal attach:
2697c478bd9Sstevel@tonic-gate  *
2707c478bd9Sstevel@tonic-gate  *	create soft state structure (dip, reg, nreg and state fields)
2717c478bd9Sstevel@tonic-gate  *	map in configuration header
2727c478bd9Sstevel@tonic-gate  *	make sure device is properly configured
2737c478bd9Sstevel@tonic-gate  *	report device
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate static int
2767c478bd9Sstevel@tonic-gate ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2777c478bd9Sstevel@tonic-gate {
2787c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
2797c478bd9Sstevel@tonic-gate 	int instance;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	DBG1(D_ATTACH, NULL, "dip=%p\n", dip);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	switch (cmd) {
2847c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 		/*
2877c478bd9Sstevel@tonic-gate 		 * Allocate soft state for this instance.
2887c478bd9Sstevel@tonic-gate 		 */
2897c478bd9Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
2907c478bd9Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(per_ebus_state, instance)
2917c478bd9Sstevel@tonic-gate 				!= DDI_SUCCESS) {
2927c478bd9Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "failed to alloc soft state\n");
2937c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
2947c478bd9Sstevel@tonic-gate 		}
2957c478bd9Sstevel@tonic-gate 		ebus_p = get_ebus_soft_state(instance);
2967c478bd9Sstevel@tonic-gate 		ebus_p->dip = dip;
2977c478bd9Sstevel@tonic-gate 		mutex_init(&ebus_p->ebus_mutex, NULL, MUTEX_DRIVER, NULL);
2987c478bd9Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED;
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		/* Set ebus type field based on ddi name info */
3017c478bd9Sstevel@tonic-gate 		if (strcmp(ddi_get_name(dip), "jbus-ebus") == 0) {
3027c478bd9Sstevel@tonic-gate 			ebus_p->type = FEBUS_TYPE;
3037c478bd9Sstevel@tonic-gate 		} else {
3047c478bd9Sstevel@tonic-gate 			ebus_p->type = EBUS_TYPE;
3057c478bd9Sstevel@tonic-gate 		}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
3087c478bd9Sstevel@tonic-gate 			DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0);
3097c478bd9Sstevel@tonic-gate 		/* Get our ranges property for mapping child registers. */
3107c478bd9Sstevel@tonic-gate 		if (get_ranges_prop(ebus_p) != DDI_SUCCESS) {
3117c478bd9Sstevel@tonic-gate 			mutex_destroy(&ebus_p->ebus_mutex);
3127c478bd9Sstevel@tonic-gate 			free_ebus_soft_state(instance);
3137c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 		/*
3177c478bd9Sstevel@tonic-gate 		 * create minor node for devctl interfaces
3187c478bd9Sstevel@tonic-gate 		 */
3197c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
3207c478bd9Sstevel@tonic-gate 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
3217c478bd9Sstevel@tonic-gate 			mutex_destroy(&ebus_p->ebus_mutex);
3227c478bd9Sstevel@tonic-gate 			free_ebus_soft_state(instance);
3237c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 		/*
3267c478bd9Sstevel@tonic-gate 		 * Make sure the master enable and memory access enable
3277c478bd9Sstevel@tonic-gate 		 * bits are set in the config command register.
3287c478bd9Sstevel@tonic-gate 		 */
3297c478bd9Sstevel@tonic-gate 		if (ebus_p->type == EBUS_TYPE) {
3307c478bd9Sstevel@tonic-gate 			if (!ebus_config(ebus_p)) {
3317c478bd9Sstevel@tonic-gate 				ddi_remove_minor_node(dip, "devctl");
3327c478bd9Sstevel@tonic-gate 				mutex_destroy(&ebus_p->ebus_mutex);
3337c478bd9Sstevel@tonic-gate 				free_ebus_soft_state(instance);
3347c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
3357c478bd9Sstevel@tonic-gate 			}
3367c478bd9Sstevel@tonic-gate 		}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 		/*
3397c478bd9Sstevel@tonic-gate 		 * Make the pci_report_pmcap() call only for RIO
3407c478bd9Sstevel@tonic-gate 		 * implementations.
3417c478bd9Sstevel@tonic-gate 		 */
3427c478bd9Sstevel@tonic-gate 		if (IS_RIO(dip)) {
3437c478bd9Sstevel@tonic-gate 			(void) pci_report_pmcap(dip, PCI_PM_IDLESPEED,
3447c478bd9Sstevel@tonic-gate 			    (void *)EBUS_4MHZ);
3457c478bd9Sstevel@tonic-gate 		}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 		/*
3487c478bd9Sstevel@tonic-gate 		 * Make the state as attached and report the device.
3497c478bd9Sstevel@tonic-gate 		 */
3507c478bd9Sstevel@tonic-gate 		ebus_p->state = ATTACHED;
3517c478bd9Sstevel@tonic-gate 		ddi_report_dev(dip);
3527c478bd9Sstevel@tonic-gate 		DBG(D_ATTACH, ebus_p, "returning\n");
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
3597c478bd9Sstevel@tonic-gate 		ebus_p = get_ebus_soft_state(instance);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		/*
3627c478bd9Sstevel@tonic-gate 		 * Make sure the master enable and memory access enable
3637c478bd9Sstevel@tonic-gate 		 * bits are set in the config command register.
3647c478bd9Sstevel@tonic-gate 		 */
3657c478bd9Sstevel@tonic-gate 		if (ebus_p->type == EBUS_TYPE) {
3667c478bd9Sstevel@tonic-gate 			if (!ebus_config(ebus_p)) {
3677c478bd9Sstevel@tonic-gate 				free_ebus_soft_state(instance);
3687c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
3697c478bd9Sstevel@tonic-gate 			}
3707c478bd9Sstevel@tonic-gate 		}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 		ebus_p->state = RESUMED;
3737c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * detach entry point:
3807c478bd9Sstevel@tonic-gate  */
3817c478bd9Sstevel@tonic-gate static int
3827c478bd9Sstevel@tonic-gate ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
3857c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(instance);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	switch (cmd) {
3887c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
3897c478bd9Sstevel@tonic-gate 		DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip);
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 		switch (ebus_p->type) {
3927c478bd9Sstevel@tonic-gate 		case EBUS_TYPE:
3937c478bd9Sstevel@tonic-gate 			kmem_free(ebus_p->rangespec.rangep, ebus_p->range_cnt *
3947c478bd9Sstevel@tonic-gate 				sizeof (struct ebus_pci_rangespec));
3957c478bd9Sstevel@tonic-gate 			break;
3967c478bd9Sstevel@tonic-gate 		case FEBUS_TYPE:
3977c478bd9Sstevel@tonic-gate 			kmem_free(ebus_p->rangespec.ferangep,
3987c478bd9Sstevel@tonic-gate 				ebus_p->range_cnt *
3997c478bd9Sstevel@tonic-gate 				sizeof (struct febus_rangespec));
4007c478bd9Sstevel@tonic-gate 			break;
4017c478bd9Sstevel@tonic-gate 		default:
4027c478bd9Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "failed to recognize ebus type\n");
4037c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, "devctl");
4077c478bd9Sstevel@tonic-gate 		mutex_destroy(&ebus_p->ebus_mutex);
4087c478bd9Sstevel@tonic-gate 		free_ebus_soft_state(instance);
4097c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4127c478bd9Sstevel@tonic-gate 		DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip);
4137c478bd9Sstevel@tonic-gate 		ebus_p->state = SUSPENDED;
4147c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	DBG(D_ATTACH, NULL, "failed to recognize ebus detach command\n");
4177c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate int
4227c478bd9Sstevel@tonic-gate get_ranges_prop(ebus_devstate_t *ebus_p)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	int nrange, range_len;
4257c478bd9Sstevel@tonic-gate 	struct ebus_pci_rangespec *rangep;
4267c478bd9Sstevel@tonic-gate 	struct febus_rangespec *ferangep;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
4297c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
4307c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY,
4317c478bd9Sstevel@tonic-gate 			ebus_p->dip, DDI_PROP_DONTPASS,
4327c478bd9Sstevel@tonic-gate 			"ranges", (caddr_t)&rangep,
4337c478bd9Sstevel@tonic-gate 			&range_len) != DDI_SUCCESS) {
4347c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "Can't get %s ranges property",
4357c478bd9Sstevel@tonic-gate 					ddi_get_name(ebus_p->dip));
4367c478bd9Sstevel@tonic-gate 				return (DDI_ME_REGSPEC_RANGE);
4377c478bd9Sstevel@tonic-gate 		}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		nrange = range_len / sizeof (struct ebus_pci_rangespec);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		if (nrange == 0)  {
4427c478bd9Sstevel@tonic-gate 			kmem_free(rangep, range_len);
4437c478bd9Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "range is equal to zero\n");
4447c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4457c478bd9Sstevel@tonic-gate 		}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate #ifdef DEBUG
4487c478bd9Sstevel@tonic-gate 		{
4497c478bd9Sstevel@tonic-gate 			int i;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 			for (i = 0; i < nrange; i++) {
4527c478bd9Sstevel@tonic-gate 				DBG5(D_MAP, ebus_p,
4537c478bd9Sstevel@tonic-gate 					"ebus range addr 0x%x.0x%x PCI range "
4547c478bd9Sstevel@tonic-gate 					"addr 0x%x.0x%x.0x%x ",
4557c478bd9Sstevel@tonic-gate 					rangep[i].ebus_phys_hi,
4567c478bd9Sstevel@tonic-gate 					rangep[i].ebus_phys_low,
4577c478bd9Sstevel@tonic-gate 					rangep[i].pci_phys_hi,
4587c478bd9Sstevel@tonic-gate 					rangep[i].pci_phys_mid,
4597c478bd9Sstevel@tonic-gate 					rangep[i].pci_phys_low);
4607c478bd9Sstevel@tonic-gate 				DBG1(D_MAP, ebus_p,
4617c478bd9Sstevel@tonic-gate 					"Size 0x%x\n", rangep[i].rng_size);
4627c478bd9Sstevel@tonic-gate 			}
4637c478bd9Sstevel@tonic-gate 		}
4647c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 		ebus_p->rangespec.rangep = rangep;
4677c478bd9Sstevel@tonic-gate 		ebus_p->range_cnt = nrange;
4687c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
4717c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip,
4727c478bd9Sstevel@tonic-gate 			DDI_PROP_DONTPASS, "ranges",
4737c478bd9Sstevel@tonic-gate 			(caddr_t)&ferangep, &range_len) != DDI_SUCCESS) {
4747c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Can't get %s ranges property",
4757c478bd9Sstevel@tonic-gate 				ddi_get_name(ebus_p->dip));
4767c478bd9Sstevel@tonic-gate 				return (DDI_ME_REGSPEC_RANGE);
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 		nrange = range_len / sizeof (struct febus_rangespec);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		if (nrange == 0)  {
4827c478bd9Sstevel@tonic-gate 			kmem_free(ferangep, range_len);
4837c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4847c478bd9Sstevel@tonic-gate 		}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate #ifdef	DEBUG
4877c478bd9Sstevel@tonic-gate 		{
4887c478bd9Sstevel@tonic-gate 			int i;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 			for (i = 0; i < nrange; i++) {
4917c478bd9Sstevel@tonic-gate 				DBG4(D_MAP, ebus_p,
4927c478bd9Sstevel@tonic-gate 					"ebus range addr 0x%x.0x%x"
4937c478bd9Sstevel@tonic-gate 					" Parent range "
4947c478bd9Sstevel@tonic-gate 					"addr 0x%x.0x%x ",
4957c478bd9Sstevel@tonic-gate 					ferangep[i].febus_phys_hi,
4967c478bd9Sstevel@tonic-gate 					ferangep[i].febus_phys_low,
4977c478bd9Sstevel@tonic-gate 					ferangep[i].parent_phys_hi,
4987c478bd9Sstevel@tonic-gate 					ferangep[i].parent_phys_low);
4997c478bd9Sstevel@tonic-gate 				DBG1(D_MAP, ebus_p, "Size 0x%x\n",
5007c478bd9Sstevel@tonic-gate 					ferangep[i].rng_size);
5017c478bd9Sstevel@tonic-gate 			}
5027c478bd9Sstevel@tonic-gate 		}
5037c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5047c478bd9Sstevel@tonic-gate 		ebus_p->rangespec.ferangep = ferangep;
5057c478bd9Sstevel@tonic-gate 		ebus_p->range_cnt = nrange;
5067c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	default:
5097c478bd9Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
5107c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /* bus driver entry points */
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate  * bus map entry point:
5187c478bd9Sstevel@tonic-gate  *
5197c478bd9Sstevel@tonic-gate  * 	if map request is for an rnumber
5207c478bd9Sstevel@tonic-gate  *		get the corresponding regspec from device node
5217c478bd9Sstevel@tonic-gate  * 	build a new regspec in our parent's format
5227c478bd9Sstevel@tonic-gate  *	build a new map_req with the new regspec
5237c478bd9Sstevel@tonic-gate  *	call up the tree to complete the mapping
5247c478bd9Sstevel@tonic-gate  */
5257c478bd9Sstevel@tonic-gate static int
5267c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
5277c478bd9Sstevel@tonic-gate 	off_t off, off_t len, caddr_t *addrp)
5287c478bd9Sstevel@tonic-gate {
5297c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
5307c478bd9Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp, *ebus_regs;
5317c478bd9Sstevel@tonic-gate 	struct regspec reg;
5327c478bd9Sstevel@tonic-gate 	pci_regspec_t pci_reg;
5337c478bd9Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
5347c478bd9Sstevel@tonic-gate 	int rnumber, i, n;
5357c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	/*
5387c478bd9Sstevel@tonic-gate 	 * Handle the mapping according to its type.
5397c478bd9Sstevel@tonic-gate 	 */
5407c478bd9Sstevel@tonic-gate 	DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n",
5417c478bd9Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip), off, len);
5427c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
5437c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		/*
5467c478bd9Sstevel@tonic-gate 		 * We assume the register specification is in ebus format.
5477c478bd9Sstevel@tonic-gate 		 * We must convert it into a PCI format regspec and pass
5487c478bd9Sstevel@tonic-gate 		 * the request to our parent.
5497c478bd9Sstevel@tonic-gate 		 */
5507c478bd9Sstevel@tonic-gate 		DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%p\n",
5517c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip),
5527c478bd9Sstevel@tonic-gate 			mp->map_handlep);
5537c478bd9Sstevel@tonic-gate 		ebus_rp = (ebus_regspec_t *)mp->map_obj.rp;
5547c478bd9Sstevel@tonic-gate 		break;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		/*
5597c478bd9Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
5607c478bd9Sstevel@tonic-gate 		 * it to our parent's format.
5617c478bd9Sstevel@tonic-gate 		 */
5627c478bd9Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
5637c478bd9Sstevel@tonic-gate 		DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%p\n",
5647c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip),
5657c478bd9Sstevel@tonic-gate 			rnumber, mp->map_handlep);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) {
5687c478bd9Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "can't get reg property\n");
5697c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate 		n = i / sizeof (ebus_regspec_t);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 		if (rnumber < 0 || rnumber >= n) {
5747c478bd9Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
5757c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
5767c478bd9Sstevel@tonic-gate 		}
5777c478bd9Sstevel@tonic-gate 		ebus_rp = &ebus_regs[rnumber];
5787c478bd9Sstevel@tonic-gate 		break;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	default:
5817c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	/* Adjust our reg property with offset and length */
5867c478bd9Sstevel@tonic-gate 	ebus_rp->addr_low += off;
5877c478bd9Sstevel@tonic-gate 	if (len)
5887c478bd9Sstevel@tonic-gate 		ebus_rp->size = len;
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	/*
5917c478bd9Sstevel@tonic-gate 	 * Now we have a copy the "reg" entry we're attempting to map.
5927c478bd9Sstevel@tonic-gate 	 * Translate this into our parents PCI address using the ranges
5937c478bd9Sstevel@tonic-gate 	 * property.
5947c478bd9Sstevel@tonic-gate 	 */
5957c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
5967c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
5977c478bd9Sstevel@tonic-gate 		rval = ebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg);
5987c478bd9Sstevel@tonic-gate 		break;
5997c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
6007c478bd9Sstevel@tonic-gate 		rval = febus_apply_range(ebus_p, rdip, ebus_rp, &reg);
6017c478bd9Sstevel@tonic-gate 		break;
6027c478bd9Sstevel@tonic-gate 	default:
6037c478bd9Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
6047c478bd9Sstevel@tonic-gate 		rval = DDI_FAILURE;
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
6087c478bd9Sstevel@tonic-gate 		kmem_free(ebus_regs, i);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS)
6117c478bd9Sstevel@tonic-gate 		return (rval);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate #ifdef DEBUG
6147c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
6157c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
6167c478bd9Sstevel@tonic-gate 		DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n",
6177c478bd9Sstevel@tonic-gate 			pci_reg.pci_phys_hi,
6187c478bd9Sstevel@tonic-gate 			pci_reg.pci_phys_mid,
6197c478bd9Sstevel@tonic-gate 			pci_reg.pci_phys_low,
6207c478bd9Sstevel@tonic-gate 			pci_reg.pci_size_hi,
6217c478bd9Sstevel@tonic-gate 			pci_reg.pci_size_low);
6227c478bd9Sstevel@tonic-gate 		break;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
6257c478bd9Sstevel@tonic-gate 		DBG3(D_MAP, ebus_p, "%x,%x,%x\n",
6267c478bd9Sstevel@tonic-gate 			reg.regspec_bustype,
6277c478bd9Sstevel@tonic-gate 			reg.regspec_addr,
6287c478bd9Sstevel@tonic-gate 			reg.regspec_size);
6297c478bd9Sstevel@tonic-gate 		break;
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate #endif
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	p_map_request = *mp;
6347c478bd9Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
6377c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
6387c478bd9Sstevel@tonic-gate 		p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
6397c478bd9Sstevel@tonic-gate 		break;
6407c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
6417c478bd9Sstevel@tonic-gate 		p_map_request.map_obj.rp = &reg;
6427c478bd9Sstevel@tonic-gate 		break;
6437c478bd9Sstevel@tonic-gate 	default:
6447c478bd9Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
6457c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
6497c478bd9Sstevel@tonic-gate 	DBG1(D_MAP, ebus_p, "parent returned %x\n", rval);
6507c478bd9Sstevel@tonic-gate 	return (rval);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate static int
6557c478bd9Sstevel@tonic-gate ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
6567c478bd9Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, pci_regspec_t *rp)
6577c478bd9Sstevel@tonic-gate {
6587c478bd9Sstevel@tonic-gate 	int b;
6597c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
6607c478bd9Sstevel@tonic-gate 	struct ebus_pci_rangespec *rangep = ebus_p->rangespec.rangep;
6617c478bd9Sstevel@tonic-gate 	int nrange = ebus_p->range_cnt;
6627c478bd9Sstevel@tonic-gate 	static char out_of_range[] =
6637c478bd9Sstevel@tonic-gate 	    "Out of range register specification from device node <%s>";
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
6667c478bd9Sstevel@tonic-gate 	    ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		/* Check for the correct space */
6717c478bd9Sstevel@tonic-gate 		if (ebus_rp->addr_hi == rangep->ebus_phys_hi)
6727c478bd9Sstevel@tonic-gate 			/* See if we fit in this range */
6737c478bd9Sstevel@tonic-gate 			if ((ebus_rp->addr_low >=
6747c478bd9Sstevel@tonic-gate 			    rangep->ebus_phys_low) &&
6757c478bd9Sstevel@tonic-gate 			    ((ebus_rp->addr_low + ebus_rp->size - 1)
6767c478bd9Sstevel@tonic-gate 				<= (rangep->ebus_phys_low +
6777c478bd9Sstevel@tonic-gate 				    rangep->rng_size - 1))) {
6787c478bd9Sstevel@tonic-gate 				uint_t addr_offset = ebus_rp->addr_low -
6797c478bd9Sstevel@tonic-gate 				    rangep->ebus_phys_low;
6807c478bd9Sstevel@tonic-gate 				/*
6817c478bd9Sstevel@tonic-gate 				 * Use the range entry to translate
6827c478bd9Sstevel@tonic-gate 				 * the EBUS physical address into the
6837c478bd9Sstevel@tonic-gate 				 * parents PCI space.
6847c478bd9Sstevel@tonic-gate 				 */
6857c478bd9Sstevel@tonic-gate 				rp->pci_phys_hi =
6867c478bd9Sstevel@tonic-gate 				rangep->pci_phys_hi;
6877c478bd9Sstevel@tonic-gate 				rp->pci_phys_mid = rangep->pci_phys_mid;
6887c478bd9Sstevel@tonic-gate 				rp->pci_phys_low =
6897c478bd9Sstevel@tonic-gate 					rangep->pci_phys_low + addr_offset;
6907c478bd9Sstevel@tonic-gate 				rp->pci_size_hi = 0;
6917c478bd9Sstevel@tonic-gate 				rp->pci_size_low =
6927c478bd9Sstevel@tonic-gate 					min(ebus_rp->size, (rangep->rng_size -
6937c478bd9Sstevel@tonic-gate 					addr_offset));
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
6967c478bd9Sstevel@tonic-gate 					rangep->ebus_phys_hi,
6977c478bd9Sstevel@tonic-gate 					rangep->ebus_phys_low);
6987c478bd9Sstevel@tonic-gate 				DBG4(D_MAP, ebus_p, "Parent hi0x%x "
6997c478bd9Sstevel@tonic-gate 					"mid0x%x lo0x%x size 0x%x\n",
7007c478bd9Sstevel@tonic-gate 					rangep->pci_phys_hi,
7017c478bd9Sstevel@tonic-gate 					rangep->pci_phys_mid,
7027c478bd9Sstevel@tonic-gate 					rangep->pci_phys_low,
7037c478bd9Sstevel@tonic-gate 					rangep->rng_size);
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 				break;
7067c478bd9Sstevel@tonic-gate 			}
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	if (b == nrange)  {
7107c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
7117c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
7127c478bd9Sstevel@tonic-gate 	}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	return (rval);
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate static int
7187c478bd9Sstevel@tonic-gate febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
7197c478bd9Sstevel@tonic-gate 		ebus_regspec_t *ebus_rp, struct regspec *rp) {
7207c478bd9Sstevel@tonic-gate 	int b;
7217c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
7227c478bd9Sstevel@tonic-gate 	struct febus_rangespec *rangep = ebus_p->rangespec.ferangep;
7237c478bd9Sstevel@tonic-gate 	int nrange = ebus_p->range_cnt;
7247c478bd9Sstevel@tonic-gate 	static char out_of_range[] =
7257c478bd9Sstevel@tonic-gate 		"Out of range register specification from device node <%s>";
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
7287c478bd9Sstevel@tonic-gate 	ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
7317c478bd9Sstevel@tonic-gate 		/* Check for the correct space */
7327c478bd9Sstevel@tonic-gate 		if (ebus_rp->addr_hi == rangep->febus_phys_hi)
7337c478bd9Sstevel@tonic-gate 			/* See if we fit in this range */
7347c478bd9Sstevel@tonic-gate 			if ((ebus_rp->addr_low >=
7357c478bd9Sstevel@tonic-gate 				rangep->febus_phys_low) &&
7367c478bd9Sstevel@tonic-gate 				((ebus_rp->addr_low + ebus_rp->size - 1)
7377c478bd9Sstevel@tonic-gate 				<= (rangep->febus_phys_low +
7387c478bd9Sstevel@tonic-gate 				rangep->rng_size - 1))) {
7397c478bd9Sstevel@tonic-gate 					uint_t addr_offset = ebus_rp->addr_low -
7407c478bd9Sstevel@tonic-gate 					rangep->febus_phys_low;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 				/*
7437c478bd9Sstevel@tonic-gate 				 * Use the range entry to translate
7447c478bd9Sstevel@tonic-gate 				 * the FEBUS physical address into the
7457c478bd9Sstevel@tonic-gate 				 * parents space.
7467c478bd9Sstevel@tonic-gate 				 */
7477c478bd9Sstevel@tonic-gate 				rp->regspec_bustype =
7487c478bd9Sstevel@tonic-gate 					rangep->parent_phys_hi;
7497c478bd9Sstevel@tonic-gate 				rp->regspec_addr =
7507c478bd9Sstevel@tonic-gate 				rangep->parent_phys_low + addr_offset;
7517c478bd9Sstevel@tonic-gate 				rp->regspec_size =
7527c478bd9Sstevel@tonic-gate 					min(ebus_rp->size, (rangep->rng_size -
7537c478bd9Sstevel@tonic-gate 					addr_offset));
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
7567c478bd9Sstevel@tonic-gate 					rangep->febus_phys_hi,
7577c478bd9Sstevel@tonic-gate 					rangep->febus_phys_low);
7587c478bd9Sstevel@tonic-gate 				DBG3(D_MAP, ebus_p, "Parent hi0x%x "
7597c478bd9Sstevel@tonic-gate 					"lo0x%x size 0x%x\n",
7607c478bd9Sstevel@tonic-gate 					rangep->parent_phys_hi,
7617c478bd9Sstevel@tonic-gate 					rangep->parent_phys_low,
7627c478bd9Sstevel@tonic-gate 					rangep->rng_size);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 				break;
7657c478bd9Sstevel@tonic-gate 			}
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (b == nrange)  {
7697c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
7707c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	return (rval);
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate static int
7787c478bd9Sstevel@tonic-gate ebus_name_child(dev_info_t *child, char *name, int namelen)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp;
7817c478bd9Sstevel@tonic-gate 	int reglen;
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	/*
7847c478bd9Sstevel@tonic-gate 	 * Get the address portion of the node name based on the
7857c478bd9Sstevel@tonic-gate 	 * address/offset.
7867c478bd9Sstevel@tonic-gate 	 */
787*a3282898Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
7887c478bd9Sstevel@tonic-gate 	    "reg", (caddr_t)&ebus_rp, &reglen) != DDI_SUCCESS) {
7897c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	(void) snprintf(name, namelen, "%x,%x", ebus_rp->addr_hi,
7937c478bd9Sstevel@tonic-gate 	    ebus_rp->addr_low);
7947c478bd9Sstevel@tonic-gate 	kmem_free(ebus_rp, reglen);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate /*
8007c478bd9Sstevel@tonic-gate  * control ops entry point:
8017c478bd9Sstevel@tonic-gate  *
8027c478bd9Sstevel@tonic-gate  * Requests handled completely:
8037c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_INITCHILD
8047c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_UNINITCHILD
8057c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_REPORTDEV
8067c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_REGSIZE
8077c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_NREGS
8087c478bd9Sstevel@tonic-gate  *
8097c478bd9Sstevel@tonic-gate  * All others passed to parent.
8107c478bd9Sstevel@tonic-gate  */
8117c478bd9Sstevel@tonic-gate static int
8127c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
8137c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result)
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate #ifdef DEBUG
8167c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
8177c478bd9Sstevel@tonic-gate #endif
8187c478bd9Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp;
8197c478bd9Sstevel@tonic-gate 	int i, n;
8207c478bd9Sstevel@tonic-gate 	char name[10];
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	switch (op) {
8237c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
8247c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
8257c478bd9Sstevel@tonic-gate 		/*
8267c478bd9Sstevel@tonic-gate 		 * Set the address portion of the node name based on the
8277c478bd9Sstevel@tonic-gate 		 * address/offset.
8287c478bd9Sstevel@tonic-gate 		 */
8297c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
8307c478bd9Sstevel@tonic-gate 		    ddi_get_name(child), ddi_get_instance(child));
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 		if (ebus_name_child(child, name, 10) != DDI_SUCCESS) {
8337c478bd9Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't name child\n");
8347c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8357c478bd9Sstevel@tonic-gate 		}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child, name);
8387c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
8397c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8407c478bd9Sstevel@tonic-gate 	}
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
8437c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
8447c478bd9Sstevel@tonic-gate 			ddi_get_name((dev_info_t *)arg),
8457c478bd9Sstevel@tonic-gate 			ddi_get_instance((dev_info_t *)arg));
8467c478bd9Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, NULL);
8477c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
8487c478bd9Sstevel@tonic-gate 		impl_rem_dev_props((dev_info_t *)arg);
8497c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
8547c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
8557c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
8567c478bd9Sstevel@tonic-gate 			ddi_driver_name(rdip), ddi_get_instance(rdip),
8577c478bd9Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip),
8587c478bd9Sstevel@tonic-gate 			ddi_get_name_addr(rdip));
8597c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
8647c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
8657c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
8667c478bd9Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
8677c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 		n = i / sizeof (ebus_regspec_t);
8707c478bd9Sstevel@tonic-gate 		if (*(int *)arg < 0 || *(int *)arg >= n) {
8717c478bd9Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
8727c478bd9Sstevel@tonic-gate 			kmem_free(ebus_rp, i);
8737c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 		*((off_t *)result) = ebus_rp[*(int *)arg].size;
8767c478bd9Sstevel@tonic-gate 		kmem_free(ebus_rp, i);
8777c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
8827c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
8837c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
8847c478bd9Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
8857c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8867c478bd9Sstevel@tonic-gate 		}
8877c478bd9Sstevel@tonic-gate 		*((uint_t *)result) = i / sizeof (ebus_regspec_t);
8887c478bd9Sstevel@tonic-gate 		kmem_free(ebus_rp, i);
8897c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	/*
8937c478bd9Sstevel@tonic-gate 	 * Now pass the request up to our parent.
8947c478bd9Sstevel@tonic-gate 	 */
8957c478bd9Sstevel@tonic-gate 	DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n",
8967c478bd9Sstevel@tonic-gate 		ddi_get_name(rdip), ddi_get_instance(rdip));
8977c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate struct ebus_string_to_pil {
9017c478bd9Sstevel@tonic-gate 	int8_t *string;
9027c478bd9Sstevel@tonic-gate 	uint32_t pil;
9037c478bd9Sstevel@tonic-gate };
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_name_to_pil[] = {{"SUNW,CS4231", 9},
9067c478bd9Sstevel@tonic-gate 							{"audio", 9},
9077c478bd9Sstevel@tonic-gate 							{"fdthree", 8},
9087c478bd9Sstevel@tonic-gate 							{"floppy", 8},
9097c478bd9Sstevel@tonic-gate 							{"ecpp", 3},
9107c478bd9Sstevel@tonic-gate 							{"parallel", 3},
9117c478bd9Sstevel@tonic-gate 							{"su", 12},
9127c478bd9Sstevel@tonic-gate 							{"se", 12},
9137c478bd9Sstevel@tonic-gate 							{"serial", 12},
9147c478bd9Sstevel@tonic-gate 							{"power", 14}};
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_device_type_to_pil[] = {{"serial", 12},
9177c478bd9Sstevel@tonic-gate 								{"block", 8}};
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate static int
9207c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
9217c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate #ifdef DEBUG
9247c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
9257c478bd9Sstevel@tonic-gate #endif
9267c478bd9Sstevel@tonic-gate 	ddi_ispec_t		*ip = (ddi_ispec_t *)hdlp->ih_private;
9277c478bd9Sstevel@tonic-gate 	int32_t			i, max_children, max_device_types, len;
9287c478bd9Sstevel@tonic-gate 	char			*name_p, *device_type_p;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	DBG1(D_INTR, ebus_p, "ip 0x%p\n", ip);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	/*
9337c478bd9Sstevel@tonic-gate 	 * NOTE: These ops below will never be supported in this nexus
9347c478bd9Sstevel@tonic-gate 	 * driver, hence they always return immediately.
9357c478bd9Sstevel@tonic-gate 	 */
9367c478bd9Sstevel@tonic-gate 	switch (intr_op) {
9377c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
9387c478bd9Sstevel@tonic-gate 		*(int *)result = 0;
9397c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
9407c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
9417c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETMASK:
9427c478bd9Sstevel@tonic-gate 	case DDI_INTROP_CLRMASK:
9437c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPENDING:
9447c478bd9Sstevel@tonic-gate 		return (DDI_ENOTSUP);
9457c478bd9Sstevel@tonic-gate 	default:
9467c478bd9Sstevel@tonic-gate 		break;
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || ip->is_pil)
9507c478bd9Sstevel@tonic-gate 		goto done;
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	/*
9537c478bd9Sstevel@tonic-gate 	 * This is a hack to set the PIL for the devices under ebus.
9547c478bd9Sstevel@tonic-gate 	 * We first look up a device by it's specific name, if we can't
9557c478bd9Sstevel@tonic-gate 	 * match the name, we try and match it's device_type property.
9567c478bd9Sstevel@tonic-gate 	 * Lastly we default a PIL level of 1.
9577c478bd9Sstevel@tonic-gate 	 */
9587c478bd9Sstevel@tonic-gate 	name_p = ddi_node_name(rdip);
9597c478bd9Sstevel@tonic-gate 	max_children = sizeof (ebus_name_to_pil) /
9607c478bd9Sstevel@tonic-gate 	    sizeof (struct ebus_string_to_pil);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	for (i = 0; i < max_children; i++) {
9637c478bd9Sstevel@tonic-gate 		if (strcmp(ebus_name_to_pil[i].string, name_p) == 0) {
9647c478bd9Sstevel@tonic-gate 			DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n",
9657c478bd9Sstevel@tonic-gate 			    ebus_name_to_pil[i].string,
9667c478bd9Sstevel@tonic-gate 			    ebus_name_to_pil[i].pil);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 			ip->is_pil = ebus_name_to_pil[i].pil;
9697c478bd9Sstevel@tonic-gate 			goto done;
9707c478bd9Sstevel@tonic-gate 		}
9717c478bd9Sstevel@tonic-gate 	}
9727c478bd9Sstevel@tonic-gate 
973*a3282898Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
9747c478bd9Sstevel@tonic-gate 	    "device_type", (caddr_t)&device_type_p, &len) == DDI_SUCCESS) {
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		max_device_types = sizeof (ebus_device_type_to_pil) /
9777c478bd9Sstevel@tonic-gate 		    sizeof (struct ebus_string_to_pil);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_device_types; i++) {
9807c478bd9Sstevel@tonic-gate 			if (strcmp(ebus_device_type_to_pil[i].string,
9817c478bd9Sstevel@tonic-gate 			    device_type_p) == 0) {
9827c478bd9Sstevel@tonic-gate 				DBG2(D_INTR, ebus_p, "Device type %s; match "
9837c478bd9Sstevel@tonic-gate 				    "PIL %d\n", ebus_device_type_to_pil[i].
9847c478bd9Sstevel@tonic-gate 				    string, ebus_device_type_to_pil[i].pil);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 				ip->is_pil = ebus_device_type_to_pil[i].pil;
9877c478bd9Sstevel@tonic-gate 				break;
9887c478bd9Sstevel@tonic-gate 			}
9897c478bd9Sstevel@tonic-gate 		}
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 		kmem_free(device_type_p, len);
9927c478bd9Sstevel@tonic-gate 	}
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	/*
9957c478bd9Sstevel@tonic-gate 	 * If we get here, we need to set a default value
9967c478bd9Sstevel@tonic-gate 	 * for the PIL.
9977c478bd9Sstevel@tonic-gate 	 */
9987c478bd9Sstevel@tonic-gate 	if (ip->is_pil == 0) {
9997c478bd9Sstevel@tonic-gate 		ip->is_pil = 1;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d assigning default interrupt level %d "
10027c478bd9Sstevel@tonic-gate 		    "for device %s%d", ddi_get_name(dip), ddi_get_instance(dip),
10037c478bd9Sstevel@tonic-gate 		    ip->is_pil, ddi_get_name(rdip), ddi_get_instance(rdip));
10047c478bd9Sstevel@tonic-gate 	}
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate done:
10077c478bd9Sstevel@tonic-gate 	/* Pass up the request to our parent. */
10087c478bd9Sstevel@tonic-gate 	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate static int
10137c478bd9Sstevel@tonic-gate ebus_config(ebus_devstate_t *ebus_p)
10147c478bd9Sstevel@tonic-gate {
10157c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t conf_handle;
10167c478bd9Sstevel@tonic-gate 	uint16_t comm;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	/*
10197c478bd9Sstevel@tonic-gate 	 * Make sure the master enable and memory access enable
10207c478bd9Sstevel@tonic-gate 	 * bits are set in the config command register.
10217c478bd9Sstevel@tonic-gate 	 */
10227c478bd9Sstevel@tonic-gate 	if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS)
10237c478bd9Sstevel@tonic-gate 		return (0);
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM),
10267c478bd9Sstevel@tonic-gate #ifdef DEBUG
10277c478bd9Sstevel@tonic-gate 	    DBG1(D_MAP, ebus_p, "command register was 0x%x\n", comm);
10287c478bd9Sstevel@tonic-gate #endif
10297c478bd9Sstevel@tonic-gate 	comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE|
10307c478bd9Sstevel@tonic-gate 	    PCI_COMM_PARITY_DETECT);
10317c478bd9Sstevel@tonic-gate 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm),
10327c478bd9Sstevel@tonic-gate #ifdef DEBUG
10337c478bd9Sstevel@tonic-gate 	    DBG1(D_MAP, ebus_p, "command register is now 0x%x\n", comm);
10347c478bd9Sstevel@tonic-gate #endif
10357c478bd9Sstevel@tonic-gate 	pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ,
10367c478bd9Sstevel@tonic-gate 	    (uchar_t)ebus_cache_line_size);
10377c478bd9Sstevel@tonic-gate 	pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER,
10387c478bd9Sstevel@tonic-gate 	    (uchar_t)ebus_latency_timer);
10397c478bd9Sstevel@tonic-gate 	pci_config_teardown(&conf_handle);
10407c478bd9Sstevel@tonic-gate 	return (1);
10417c478bd9Sstevel@tonic-gate }
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate #ifdef DEBUG
10447c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate static void
10477c478bd9Sstevel@tonic-gate ebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt,
10487c478bd9Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
10497c478bd9Sstevel@tonic-gate {
10507c478bd9Sstevel@tonic-gate 	char *s;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	if (ebus_debug_flags & flag) {
10537c478bd9Sstevel@tonic-gate 		switch (flag) {
10547c478bd9Sstevel@tonic-gate 		case D_ATTACH:
10557c478bd9Sstevel@tonic-gate 			s = "attach"; break;
10567c478bd9Sstevel@tonic-gate 		case D_DETACH:
10577c478bd9Sstevel@tonic-gate 			s = "detach"; break;
10587c478bd9Sstevel@tonic-gate 		case D_MAP:
10597c478bd9Sstevel@tonic-gate 			s = "map"; break;
10607c478bd9Sstevel@tonic-gate 		case D_CTLOPS:
10617c478bd9Sstevel@tonic-gate 			s = "ctlops"; break;
10627c478bd9Sstevel@tonic-gate 		case D_INTR:
10637c478bd9Sstevel@tonic-gate 			s = "intr"; break;
10647c478bd9Sstevel@tonic-gate 		}
10657c478bd9Sstevel@tonic-gate 		if (ebus_p)
10667c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: %s: ",
10677c478bd9Sstevel@tonic-gate 				ddi_get_name(ebus_p->dip),
10687c478bd9Sstevel@tonic-gate 				ddi_get_instance(ebus_p->dip), s);
10697c478bd9Sstevel@tonic-gate 		else
10707c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "ebus: ");
10717c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate }
10747c478bd9Sstevel@tonic-gate #endif
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
10777c478bd9Sstevel@tonic-gate static int
10787c478bd9Sstevel@tonic-gate ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	/*
10837c478bd9Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
10847c478bd9Sstevel@tonic-gate 	 */
10857c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
10867c478bd9Sstevel@tonic-gate 		return (EINVAL);
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	/*
10897c478bd9Sstevel@tonic-gate 	 * Get the soft state structure for the device.
10907c478bd9Sstevel@tonic-gate 	 */
10917c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(*devp));
10927c478bd9Sstevel@tonic-gate 	if (ebus_p == NULL)
10937c478bd9Sstevel@tonic-gate 		return (ENXIO);
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	/*
10967c478bd9Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
10977c478bd9Sstevel@tonic-gate 	 */
10987c478bd9Sstevel@tonic-gate 	mutex_enter(&ebus_p->ebus_mutex);
10997c478bd9Sstevel@tonic-gate 	if (flags & FEXCL) {
11007c478bd9Sstevel@tonic-gate 		if (ebus_p->ebus_soft_state != EBUS_SOFT_STATE_CLOSED) {
11017c478bd9Sstevel@tonic-gate 			mutex_exit(&ebus_p->ebus_mutex);
11027c478bd9Sstevel@tonic-gate 			return (EBUSY);
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN_EXCL;
11057c478bd9Sstevel@tonic-gate 	} else {
11067c478bd9Sstevel@tonic-gate 		if (ebus_p->ebus_soft_state == EBUS_SOFT_STATE_OPEN_EXCL) {
11077c478bd9Sstevel@tonic-gate 			mutex_exit(&ebus_p->ebus_mutex);
11087c478bd9Sstevel@tonic-gate 			return (EBUSY);
11097c478bd9Sstevel@tonic-gate 		}
11107c478bd9Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 	mutex_exit(&ebus_p->ebus_mutex);
11137c478bd9Sstevel@tonic-gate 	return (0);
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate /* ARGSUSED */
11187c478bd9Sstevel@tonic-gate static int
11197c478bd9Sstevel@tonic-gate ebus_close(dev_t dev, int flags, int otyp, cred_t *credp)
11207c478bd9Sstevel@tonic-gate {
11217c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
11247c478bd9Sstevel@tonic-gate 		return (EINVAL);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(dev));
11277c478bd9Sstevel@tonic-gate 	if (ebus_p == NULL)
11287c478bd9Sstevel@tonic-gate 		return (ENXIO);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	mutex_enter(&ebus_p->ebus_mutex);
11317c478bd9Sstevel@tonic-gate 	ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED;
11327c478bd9Sstevel@tonic-gate 	mutex_exit(&ebus_p->ebus_mutex);
11337c478bd9Sstevel@tonic-gate 	return (0);
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate /*
11387c478bd9Sstevel@tonic-gate  * ebus_ioctl: devctl hotplug controls
11397c478bd9Sstevel@tonic-gate  */
11407c478bd9Sstevel@tonic-gate /* ARGSUSED */
11417c478bd9Sstevel@tonic-gate static int
11427c478bd9Sstevel@tonic-gate ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
11437c478bd9Sstevel@tonic-gate 	int *rvalp)
11447c478bd9Sstevel@tonic-gate {
11457c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
11467c478bd9Sstevel@tonic-gate 	dev_info_t *self;
11477c478bd9Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
11487c478bd9Sstevel@tonic-gate 	uint_t bus_state;
11497c478bd9Sstevel@tonic-gate 	int rv = 0;
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(dev));
11527c478bd9Sstevel@tonic-gate 	if (ebus_p == NULL)
11537c478bd9Sstevel@tonic-gate 		return (ENXIO);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	self = ebus_p->dip;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	/*
11587c478bd9Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
11597c478bd9Sstevel@tonic-gate 	 */
11607c478bd9Sstevel@tonic-gate 	switch (cmd) {
11617c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
11627c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
11637c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
11647c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
11657c478bd9Sstevel@tonic-gate 		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	/*
11697c478bd9Sstevel@tonic-gate 	 * read devctl ioctl data
11707c478bd9Sstevel@tonic-gate 	 */
11717c478bd9Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
11727c478bd9Sstevel@tonic-gate 		return (EFAULT);
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	switch (cmd) {
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
11777c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
11787c478bd9Sstevel@tonic-gate 		break;
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
11817c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
11827c478bd9Sstevel@tonic-gate 			if (bus_state == BUS_QUIESCED)
11837c478bd9Sstevel@tonic-gate 				break;
11847c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_QUIESCED);
11857c478bd9Sstevel@tonic-gate 		break;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
11887c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
11897c478bd9Sstevel@tonic-gate 			if (bus_state == BUS_ACTIVE)
11907c478bd9Sstevel@tonic-gate 				break;
11917c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
11927c478bd9Sstevel@tonic-gate 		break;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
11957c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
11967c478bd9Sstevel@tonic-gate 		break;
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
11997c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
12007c478bd9Sstevel@tonic-gate 		break;
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	default:
12037c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
12077c478bd9Sstevel@tonic-gate 	return (rv);
12087c478bd9Sstevel@tonic-gate }
1209