xref: /titanic_53/usr/src/uts/sun4/io/ebus.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/pci.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/ebus.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/open.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
49*7c478bd9Sstevel@tonic-gate uint64_t ebus_debug_flags = 0;
50*7c478bd9Sstevel@tonic-gate #endif
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate /*
53*7c478bd9Sstevel@tonic-gate  * The values of the following variables are used to initialize
54*7c478bd9Sstevel@tonic-gate  * the cache line size and latency timer registers in the ebus
55*7c478bd9Sstevel@tonic-gate  * configuration header.  Variables are used instead of constants
56*7c478bd9Sstevel@tonic-gate  * to allow tuning from the /etc/system file.
57*7c478bd9Sstevel@tonic-gate  */
58*7c478bd9Sstevel@tonic-gate static uint8_t ebus_cache_line_size = 0x10;	/* 64 bytes */
59*7c478bd9Sstevel@tonic-gate static uint8_t ebus_latency_timer = 0x40;	/* 64 PCI cycles */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /*
62*7c478bd9Sstevel@tonic-gate  * function prototypes for bus ops routines:
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate static int
65*7c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
66*7c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *addrp);
67*7c478bd9Sstevel@tonic-gate static int
68*7c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
69*7c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result);
70*7c478bd9Sstevel@tonic-gate static int
71*7c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
72*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result);
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate /*
75*7c478bd9Sstevel@tonic-gate  * function prototypes for dev ops routines:
76*7c478bd9Sstevel@tonic-gate  */
77*7c478bd9Sstevel@tonic-gate static int ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
78*7c478bd9Sstevel@tonic-gate static int ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
79*7c478bd9Sstevel@tonic-gate static int ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
80*7c478bd9Sstevel@tonic-gate 	void *arg, void **result);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate /*
83*7c478bd9Sstevel@tonic-gate  * general function prototypes:
84*7c478bd9Sstevel@tonic-gate  */
85*7c478bd9Sstevel@tonic-gate static int ebus_config(ebus_devstate_t *ebus_p);
86*7c478bd9Sstevel@tonic-gate static int ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
87*7c478bd9Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, pci_regspec_t *rp);
88*7c478bd9Sstevel@tonic-gate static int febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
89*7c478bd9Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, struct regspec *rp);
90*7c478bd9Sstevel@tonic-gate int get_ranges_prop(ebus_devstate_t *ebus_p);
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate #define	getprop(dip, name, addr, intp)		\
93*7c478bd9Sstevel@tonic-gate 		ddi_getlongprop(DDI_DEV_T_NONE, (dip), DDI_PROP_DONTPASS, \
94*7c478bd9Sstevel@tonic-gate 				(name), (caddr_t)(addr), (intp))
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate static int ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp);
97*7c478bd9Sstevel@tonic-gate static int ebus_close(dev_t dev, int flags, int otyp, cred_t *credp);
98*7c478bd9Sstevel@tonic-gate static int ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
99*7c478bd9Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
100*7c478bd9Sstevel@tonic-gate struct cb_ops ebus_cb_ops = {
101*7c478bd9Sstevel@tonic-gate 	ebus_open,			/* open */
102*7c478bd9Sstevel@tonic-gate 	ebus_close,			/* close */
103*7c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
104*7c478bd9Sstevel@tonic-gate 	nodev,				/* print */
105*7c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
106*7c478bd9Sstevel@tonic-gate 	nodev,				/* read */
107*7c478bd9Sstevel@tonic-gate 	nodev,				/* write */
108*7c478bd9Sstevel@tonic-gate 	ebus_ioctl,			/* ioctl */
109*7c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
110*7c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
111*7c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
112*7c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
113*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* cb_prop_op */
114*7c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
115*7c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
116*7c478bd9Sstevel@tonic-gate 	CB_REV,				/* rev */
117*7c478bd9Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
118*7c478bd9Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
119*7c478bd9Sstevel@tonic-gate };
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate  * bus ops and dev ops structures:
123*7c478bd9Sstevel@tonic-gate  */
124*7c478bd9Sstevel@tonic-gate static struct bus_ops ebus_bus_ops = {
125*7c478bd9Sstevel@tonic-gate 	BUSO_REV,
126*7c478bd9Sstevel@tonic-gate 	ebus_map,
127*7c478bd9Sstevel@tonic-gate 	NULL,
128*7c478bd9Sstevel@tonic-gate 	NULL,
129*7c478bd9Sstevel@tonic-gate 	NULL,
130*7c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,
131*7c478bd9Sstevel@tonic-gate 	ddi_dma_map,
132*7c478bd9Sstevel@tonic-gate 	ddi_dma_allochdl,
133*7c478bd9Sstevel@tonic-gate 	ddi_dma_freehdl,
134*7c478bd9Sstevel@tonic-gate 	ddi_dma_bindhdl,
135*7c478bd9Sstevel@tonic-gate 	ddi_dma_unbindhdl,
136*7c478bd9Sstevel@tonic-gate 	ddi_dma_flush,
137*7c478bd9Sstevel@tonic-gate 	ddi_dma_win,
138*7c478bd9Sstevel@tonic-gate 	ddi_dma_mctl,
139*7c478bd9Sstevel@tonic-gate 	ebus_ctlops,
140*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
141*7c478bd9Sstevel@tonic-gate 	ndi_busop_get_eventcookie,
142*7c478bd9Sstevel@tonic-gate 	ndi_busop_add_eventcall,
143*7c478bd9Sstevel@tonic-gate 	ndi_busop_remove_eventcall,
144*7c478bd9Sstevel@tonic-gate 	ndi_post_event,
145*7c478bd9Sstevel@tonic-gate 	0,
146*7c478bd9Sstevel@tonic-gate 	0,
147*7c478bd9Sstevel@tonic-gate 	0,
148*7c478bd9Sstevel@tonic-gate 	0,
149*7c478bd9Sstevel@tonic-gate 	0,
150*7c478bd9Sstevel@tonic-gate 	0,
151*7c478bd9Sstevel@tonic-gate 	0,
152*7c478bd9Sstevel@tonic-gate 	0,
153*7c478bd9Sstevel@tonic-gate 	ebus_intr_ops
154*7c478bd9Sstevel@tonic-gate };
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate static struct dev_ops ebus_ops = {
157*7c478bd9Sstevel@tonic-gate 	DEVO_REV,
158*7c478bd9Sstevel@tonic-gate 	0,
159*7c478bd9Sstevel@tonic-gate 	ebus_info,
160*7c478bd9Sstevel@tonic-gate 	nulldev,
161*7c478bd9Sstevel@tonic-gate 	nulldev,
162*7c478bd9Sstevel@tonic-gate 	ebus_attach,
163*7c478bd9Sstevel@tonic-gate 	ebus_detach,
164*7c478bd9Sstevel@tonic-gate 	nodev,
165*7c478bd9Sstevel@tonic-gate 	&ebus_cb_ops,
166*7c478bd9Sstevel@tonic-gate 	&ebus_bus_ops
167*7c478bd9Sstevel@tonic-gate };
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate /*
170*7c478bd9Sstevel@tonic-gate  * module definitions:
171*7c478bd9Sstevel@tonic-gate  */
172*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
173*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
176*7c478bd9Sstevel@tonic-gate 	&mod_driverops, 	/* Type of module.  This one is a driver */
177*7c478bd9Sstevel@tonic-gate 	"ebus nexus driver %I%", /* Name of module. */
178*7c478bd9Sstevel@tonic-gate 	&ebus_ops,		/* driver ops */
179*7c478bd9Sstevel@tonic-gate };
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
182*7c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&modldrv, NULL
183*7c478bd9Sstevel@tonic-gate };
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate /*
186*7c478bd9Sstevel@tonic-gate  * driver global data:
187*7c478bd9Sstevel@tonic-gate  */
188*7c478bd9Sstevel@tonic-gate static void *per_ebus_state;		/* per-ebus soft state pointer */
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate int
192*7c478bd9Sstevel@tonic-gate _init(void)
193*7c478bd9Sstevel@tonic-gate {
194*7c478bd9Sstevel@tonic-gate 	int e;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	/*
197*7c478bd9Sstevel@tonic-gate 	 * Initialize per-ebus soft state pointer.
198*7c478bd9Sstevel@tonic-gate 	 */
199*7c478bd9Sstevel@tonic-gate 	e = ddi_soft_state_init(&per_ebus_state, sizeof (ebus_devstate_t), 1);
200*7c478bd9Sstevel@tonic-gate 	if (e != 0)
201*7c478bd9Sstevel@tonic-gate 		return (e);
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	/*
204*7c478bd9Sstevel@tonic-gate 	 * Install the module.
205*7c478bd9Sstevel@tonic-gate 	 */
206*7c478bd9Sstevel@tonic-gate 	e = mod_install(&modlinkage);
207*7c478bd9Sstevel@tonic-gate 	if (e != 0)
208*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&per_ebus_state);
209*7c478bd9Sstevel@tonic-gate 	return (e);
210*7c478bd9Sstevel@tonic-gate }
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate int
213*7c478bd9Sstevel@tonic-gate _fini(void)
214*7c478bd9Sstevel@tonic-gate {
215*7c478bd9Sstevel@tonic-gate 	int e;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	/*
218*7c478bd9Sstevel@tonic-gate 	 * Remove the module.
219*7c478bd9Sstevel@tonic-gate 	 */
220*7c478bd9Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
221*7c478bd9Sstevel@tonic-gate 	if (e != 0)
222*7c478bd9Sstevel@tonic-gate 		return (e);
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/*
225*7c478bd9Sstevel@tonic-gate 	 * Free the soft state info.
226*7c478bd9Sstevel@tonic-gate 	 */
227*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&per_ebus_state);
228*7c478bd9Sstevel@tonic-gate 	return (e);
229*7c478bd9Sstevel@tonic-gate }
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate int
232*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
235*7c478bd9Sstevel@tonic-gate }
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate /* device driver entry points */
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
240*7c478bd9Sstevel@tonic-gate static int
241*7c478bd9Sstevel@tonic-gate ebus_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
244*7c478bd9Sstevel@tonic-gate 	int instance;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	instance = getminor((dev_t)arg);
247*7c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(instance);
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
250*7c478bd9Sstevel@tonic-gate 	default:
251*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
254*7c478bd9Sstevel@tonic-gate 		*result = (void *)instance;
255*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
258*7c478bd9Sstevel@tonic-gate 		if (ebus_p == NULL)
259*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
260*7c478bd9Sstevel@tonic-gate 		*result = (void *)ebus_p->dip;
261*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
262*7c478bd9Sstevel@tonic-gate 	}
263*7c478bd9Sstevel@tonic-gate }
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate /*
266*7c478bd9Sstevel@tonic-gate  * attach entry point:
267*7c478bd9Sstevel@tonic-gate  *
268*7c478bd9Sstevel@tonic-gate  * normal attach:
269*7c478bd9Sstevel@tonic-gate  *
270*7c478bd9Sstevel@tonic-gate  *	create soft state structure (dip, reg, nreg and state fields)
271*7c478bd9Sstevel@tonic-gate  *	map in configuration header
272*7c478bd9Sstevel@tonic-gate  *	make sure device is properly configured
273*7c478bd9Sstevel@tonic-gate  *	report device
274*7c478bd9Sstevel@tonic-gate  */
275*7c478bd9Sstevel@tonic-gate static int
276*7c478bd9Sstevel@tonic-gate ebus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
277*7c478bd9Sstevel@tonic-gate {
278*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;	/* per ebus state pointer */
279*7c478bd9Sstevel@tonic-gate 	int instance;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	DBG1(D_ATTACH, NULL, "dip=%p\n", dip);
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
284*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 		/*
287*7c478bd9Sstevel@tonic-gate 		 * Allocate soft state for this instance.
288*7c478bd9Sstevel@tonic-gate 		 */
289*7c478bd9Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
290*7c478bd9Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(per_ebus_state, instance)
291*7c478bd9Sstevel@tonic-gate 				!= DDI_SUCCESS) {
292*7c478bd9Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "failed to alloc soft state\n");
293*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 		ebus_p = get_ebus_soft_state(instance);
296*7c478bd9Sstevel@tonic-gate 		ebus_p->dip = dip;
297*7c478bd9Sstevel@tonic-gate 		mutex_init(&ebus_p->ebus_mutex, NULL, MUTEX_DRIVER, NULL);
298*7c478bd9Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED;
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 		/* Set ebus type field based on ddi name info */
301*7c478bd9Sstevel@tonic-gate 		if (strcmp(ddi_get_name(dip), "jbus-ebus") == 0) {
302*7c478bd9Sstevel@tonic-gate 			ebus_p->type = FEBUS_TYPE;
303*7c478bd9Sstevel@tonic-gate 		} else {
304*7c478bd9Sstevel@tonic-gate 			ebus_p->type = EBUS_TYPE;
305*7c478bd9Sstevel@tonic-gate 		}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 		(void) ddi_prop_create(DDI_DEV_T_NONE, dip,
308*7c478bd9Sstevel@tonic-gate 			DDI_PROP_CANSLEEP, "no-dma-interrupt-sync", NULL, 0);
309*7c478bd9Sstevel@tonic-gate 		/* Get our ranges property for mapping child registers. */
310*7c478bd9Sstevel@tonic-gate 		if (get_ranges_prop(ebus_p) != DDI_SUCCESS) {
311*7c478bd9Sstevel@tonic-gate 			mutex_destroy(&ebus_p->ebus_mutex);
312*7c478bd9Sstevel@tonic-gate 			free_ebus_soft_state(instance);
313*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
314*7c478bd9Sstevel@tonic-gate 		}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 		/*
317*7c478bd9Sstevel@tonic-gate 		 * create minor node for devctl interfaces
318*7c478bd9Sstevel@tonic-gate 		 */
319*7c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(dip, "devctl", S_IFCHR, instance,
320*7c478bd9Sstevel@tonic-gate 		    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
321*7c478bd9Sstevel@tonic-gate 			mutex_destroy(&ebus_p->ebus_mutex);
322*7c478bd9Sstevel@tonic-gate 			free_ebus_soft_state(instance);
323*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 		/*
326*7c478bd9Sstevel@tonic-gate 		 * Make sure the master enable and memory access enable
327*7c478bd9Sstevel@tonic-gate 		 * bits are set in the config command register.
328*7c478bd9Sstevel@tonic-gate 		 */
329*7c478bd9Sstevel@tonic-gate 		if (ebus_p->type == EBUS_TYPE) {
330*7c478bd9Sstevel@tonic-gate 			if (!ebus_config(ebus_p)) {
331*7c478bd9Sstevel@tonic-gate 				ddi_remove_minor_node(dip, "devctl");
332*7c478bd9Sstevel@tonic-gate 				mutex_destroy(&ebus_p->ebus_mutex);
333*7c478bd9Sstevel@tonic-gate 				free_ebus_soft_state(instance);
334*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
335*7c478bd9Sstevel@tonic-gate 			}
336*7c478bd9Sstevel@tonic-gate 		}
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 		/*
339*7c478bd9Sstevel@tonic-gate 		 * Make the pci_report_pmcap() call only for RIO
340*7c478bd9Sstevel@tonic-gate 		 * implementations.
341*7c478bd9Sstevel@tonic-gate 		 */
342*7c478bd9Sstevel@tonic-gate 		if (IS_RIO(dip)) {
343*7c478bd9Sstevel@tonic-gate 			(void) pci_report_pmcap(dip, PCI_PM_IDLESPEED,
344*7c478bd9Sstevel@tonic-gate 			    (void *)EBUS_4MHZ);
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		/*
348*7c478bd9Sstevel@tonic-gate 		 * Make the state as attached and report the device.
349*7c478bd9Sstevel@tonic-gate 		 */
350*7c478bd9Sstevel@tonic-gate 		ebus_p->state = ATTACHED;
351*7c478bd9Sstevel@tonic-gate 		ddi_report_dev(dip);
352*7c478bd9Sstevel@tonic-gate 		DBG(D_ATTACH, ebus_p, "returning\n");
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
359*7c478bd9Sstevel@tonic-gate 		ebus_p = get_ebus_soft_state(instance);
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		/*
362*7c478bd9Sstevel@tonic-gate 		 * Make sure the master enable and memory access enable
363*7c478bd9Sstevel@tonic-gate 		 * bits are set in the config command register.
364*7c478bd9Sstevel@tonic-gate 		 */
365*7c478bd9Sstevel@tonic-gate 		if (ebus_p->type == EBUS_TYPE) {
366*7c478bd9Sstevel@tonic-gate 			if (!ebus_config(ebus_p)) {
367*7c478bd9Sstevel@tonic-gate 				free_ebus_soft_state(instance);
368*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
369*7c478bd9Sstevel@tonic-gate 			}
370*7c478bd9Sstevel@tonic-gate 		}
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 		ebus_p->state = RESUMED;
373*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
376*7c478bd9Sstevel@tonic-gate }
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate /*
379*7c478bd9Sstevel@tonic-gate  * detach entry point:
380*7c478bd9Sstevel@tonic-gate  */
381*7c478bd9Sstevel@tonic-gate static int
382*7c478bd9Sstevel@tonic-gate ebus_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
383*7c478bd9Sstevel@tonic-gate {
384*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
385*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(instance);
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
388*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
389*7c478bd9Sstevel@tonic-gate 		DBG1(D_DETACH, ebus_p, "DDI_DETACH dip=%p\n", dip);
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 		switch (ebus_p->type) {
392*7c478bd9Sstevel@tonic-gate 		case EBUS_TYPE:
393*7c478bd9Sstevel@tonic-gate 			kmem_free(ebus_p->rangespec.rangep, ebus_p->range_cnt *
394*7c478bd9Sstevel@tonic-gate 				sizeof (struct ebus_pci_rangespec));
395*7c478bd9Sstevel@tonic-gate 			break;
396*7c478bd9Sstevel@tonic-gate 		case FEBUS_TYPE:
397*7c478bd9Sstevel@tonic-gate 			kmem_free(ebus_p->rangespec.ferangep,
398*7c478bd9Sstevel@tonic-gate 				ebus_p->range_cnt *
399*7c478bd9Sstevel@tonic-gate 				sizeof (struct febus_rangespec));
400*7c478bd9Sstevel@tonic-gate 			break;
401*7c478bd9Sstevel@tonic-gate 		default:
402*7c478bd9Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "failed to recognize ebus type\n");
403*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
404*7c478bd9Sstevel@tonic-gate 		}
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, "devctl");
407*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&ebus_p->ebus_mutex);
408*7c478bd9Sstevel@tonic-gate 		free_ebus_soft_state(instance);
409*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
412*7c478bd9Sstevel@tonic-gate 		DBG1(D_DETACH, ebus_p, "DDI_SUSPEND dip=%p\n", dip);
413*7c478bd9Sstevel@tonic-gate 		ebus_p->state = SUSPENDED;
414*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 	DBG(D_ATTACH, NULL, "failed to recognize ebus detach command\n");
417*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
418*7c478bd9Sstevel@tonic-gate }
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate int
422*7c478bd9Sstevel@tonic-gate get_ranges_prop(ebus_devstate_t *ebus_p)
423*7c478bd9Sstevel@tonic-gate {
424*7c478bd9Sstevel@tonic-gate 	int nrange, range_len;
425*7c478bd9Sstevel@tonic-gate 	struct ebus_pci_rangespec *rangep;
426*7c478bd9Sstevel@tonic-gate 	struct febus_rangespec *ferangep;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
429*7c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
430*7c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY,
431*7c478bd9Sstevel@tonic-gate 			ebus_p->dip, DDI_PROP_DONTPASS,
432*7c478bd9Sstevel@tonic-gate 			"ranges", (caddr_t)&rangep,
433*7c478bd9Sstevel@tonic-gate 			&range_len) != DDI_SUCCESS) {
434*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "Can't get %s ranges property",
435*7c478bd9Sstevel@tonic-gate 					ddi_get_name(ebus_p->dip));
436*7c478bd9Sstevel@tonic-gate 				return (DDI_ME_REGSPEC_RANGE);
437*7c478bd9Sstevel@tonic-gate 		}
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 		nrange = range_len / sizeof (struct ebus_pci_rangespec);
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 		if (nrange == 0)  {
442*7c478bd9Sstevel@tonic-gate 			kmem_free(rangep, range_len);
443*7c478bd9Sstevel@tonic-gate 			DBG(D_ATTACH, NULL, "range is equal to zero\n");
444*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
445*7c478bd9Sstevel@tonic-gate 		}
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
448*7c478bd9Sstevel@tonic-gate 		{
449*7c478bd9Sstevel@tonic-gate 			int i;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < nrange; i++) {
452*7c478bd9Sstevel@tonic-gate 				DBG5(D_MAP, ebus_p,
453*7c478bd9Sstevel@tonic-gate 					"ebus range addr 0x%x.0x%x PCI range "
454*7c478bd9Sstevel@tonic-gate 					"addr 0x%x.0x%x.0x%x ",
455*7c478bd9Sstevel@tonic-gate 					rangep[i].ebus_phys_hi,
456*7c478bd9Sstevel@tonic-gate 					rangep[i].ebus_phys_low,
457*7c478bd9Sstevel@tonic-gate 					rangep[i].pci_phys_hi,
458*7c478bd9Sstevel@tonic-gate 					rangep[i].pci_phys_mid,
459*7c478bd9Sstevel@tonic-gate 					rangep[i].pci_phys_low);
460*7c478bd9Sstevel@tonic-gate 				DBG1(D_MAP, ebus_p,
461*7c478bd9Sstevel@tonic-gate 					"Size 0x%x\n", rangep[i].rng_size);
462*7c478bd9Sstevel@tonic-gate 			}
463*7c478bd9Sstevel@tonic-gate 		}
464*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 		ebus_p->rangespec.rangep = rangep;
467*7c478bd9Sstevel@tonic-gate 		ebus_p->range_cnt = nrange;
468*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
471*7c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip,
472*7c478bd9Sstevel@tonic-gate 			DDI_PROP_DONTPASS, "ranges",
473*7c478bd9Sstevel@tonic-gate 			(caddr_t)&ferangep, &range_len) != DDI_SUCCESS) {
474*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "Can't get %s ranges property",
475*7c478bd9Sstevel@tonic-gate 				ddi_get_name(ebus_p->dip));
476*7c478bd9Sstevel@tonic-gate 				return (DDI_ME_REGSPEC_RANGE);
477*7c478bd9Sstevel@tonic-gate 		}
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 		nrange = range_len / sizeof (struct febus_rangespec);
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 		if (nrange == 0)  {
482*7c478bd9Sstevel@tonic-gate 			kmem_free(ferangep, range_len);
483*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
484*7c478bd9Sstevel@tonic-gate 		}
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
487*7c478bd9Sstevel@tonic-gate 		{
488*7c478bd9Sstevel@tonic-gate 			int i;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < nrange; i++) {
491*7c478bd9Sstevel@tonic-gate 				DBG4(D_MAP, ebus_p,
492*7c478bd9Sstevel@tonic-gate 					"ebus range addr 0x%x.0x%x"
493*7c478bd9Sstevel@tonic-gate 					" Parent range "
494*7c478bd9Sstevel@tonic-gate 					"addr 0x%x.0x%x ",
495*7c478bd9Sstevel@tonic-gate 					ferangep[i].febus_phys_hi,
496*7c478bd9Sstevel@tonic-gate 					ferangep[i].febus_phys_low,
497*7c478bd9Sstevel@tonic-gate 					ferangep[i].parent_phys_hi,
498*7c478bd9Sstevel@tonic-gate 					ferangep[i].parent_phys_low);
499*7c478bd9Sstevel@tonic-gate 				DBG1(D_MAP, ebus_p, "Size 0x%x\n",
500*7c478bd9Sstevel@tonic-gate 					ferangep[i].rng_size);
501*7c478bd9Sstevel@tonic-gate 			}
502*7c478bd9Sstevel@tonic-gate 		}
503*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
504*7c478bd9Sstevel@tonic-gate 		ebus_p->rangespec.ferangep = ferangep;
505*7c478bd9Sstevel@tonic-gate 		ebus_p->range_cnt = nrange;
506*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	default:
509*7c478bd9Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
510*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
511*7c478bd9Sstevel@tonic-gate 	}
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate /* bus driver entry points */
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate /*
517*7c478bd9Sstevel@tonic-gate  * bus map entry point:
518*7c478bd9Sstevel@tonic-gate  *
519*7c478bd9Sstevel@tonic-gate  * 	if map request is for an rnumber
520*7c478bd9Sstevel@tonic-gate  *		get the corresponding regspec from device node
521*7c478bd9Sstevel@tonic-gate  * 	build a new regspec in our parent's format
522*7c478bd9Sstevel@tonic-gate  *	build a new map_req with the new regspec
523*7c478bd9Sstevel@tonic-gate  *	call up the tree to complete the mapping
524*7c478bd9Sstevel@tonic-gate  */
525*7c478bd9Sstevel@tonic-gate static int
526*7c478bd9Sstevel@tonic-gate ebus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
527*7c478bd9Sstevel@tonic-gate 	off_t off, off_t len, caddr_t *addrp)
528*7c478bd9Sstevel@tonic-gate {
529*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
530*7c478bd9Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp, *ebus_regs;
531*7c478bd9Sstevel@tonic-gate 	struct regspec reg;
532*7c478bd9Sstevel@tonic-gate 	pci_regspec_t pci_reg;
533*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
534*7c478bd9Sstevel@tonic-gate 	int rnumber, i, n;
535*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	/*
538*7c478bd9Sstevel@tonic-gate 	 * Handle the mapping according to its type.
539*7c478bd9Sstevel@tonic-gate 	 */
540*7c478bd9Sstevel@tonic-gate 	DBG4(D_MAP, ebus_p, "rdip=%s%d: off=%x len=%x\n",
541*7c478bd9Sstevel@tonic-gate 	    ddi_get_name(rdip), ddi_get_instance(rdip), off, len);
542*7c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
543*7c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 		/*
546*7c478bd9Sstevel@tonic-gate 		 * We assume the register specification is in ebus format.
547*7c478bd9Sstevel@tonic-gate 		 * We must convert it into a PCI format regspec and pass
548*7c478bd9Sstevel@tonic-gate 		 * the request to our parent.
549*7c478bd9Sstevel@tonic-gate 		 */
550*7c478bd9Sstevel@tonic-gate 		DBG3(D_MAP, ebus_p, "rdip=%s%d: REGSPEC - handlep=%p\n",
551*7c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip),
552*7c478bd9Sstevel@tonic-gate 			mp->map_handlep);
553*7c478bd9Sstevel@tonic-gate 		ebus_rp = (ebus_regspec_t *)mp->map_obj.rp;
554*7c478bd9Sstevel@tonic-gate 		break;
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 		/*
559*7c478bd9Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
560*7c478bd9Sstevel@tonic-gate 		 * it to our parent's format.
561*7c478bd9Sstevel@tonic-gate 		 */
562*7c478bd9Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
563*7c478bd9Sstevel@tonic-gate 		DBG4(D_MAP, ebus_p, "rdip=%s%d: rnumber=%x handlep=%p\n",
564*7c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip),
565*7c478bd9Sstevel@tonic-gate 			rnumber, mp->map_handlep);
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_regs, &i) != DDI_SUCCESS) {
568*7c478bd9Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "can't get reg property\n");
569*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
570*7c478bd9Sstevel@tonic-gate 		}
571*7c478bd9Sstevel@tonic-gate 		n = i / sizeof (ebus_regspec_t);
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		if (rnumber < 0 || rnumber >= n) {
574*7c478bd9Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
575*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
576*7c478bd9Sstevel@tonic-gate 		}
577*7c478bd9Sstevel@tonic-gate 		ebus_rp = &ebus_regs[rnumber];
578*7c478bd9Sstevel@tonic-gate 		break;
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	default:
581*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/* Adjust our reg property with offset and length */
586*7c478bd9Sstevel@tonic-gate 	ebus_rp->addr_low += off;
587*7c478bd9Sstevel@tonic-gate 	if (len)
588*7c478bd9Sstevel@tonic-gate 		ebus_rp->size = len;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	/*
591*7c478bd9Sstevel@tonic-gate 	 * Now we have a copy the "reg" entry we're attempting to map.
592*7c478bd9Sstevel@tonic-gate 	 * Translate this into our parents PCI address using the ranges
593*7c478bd9Sstevel@tonic-gate 	 * property.
594*7c478bd9Sstevel@tonic-gate 	 */
595*7c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
596*7c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
597*7c478bd9Sstevel@tonic-gate 		rval = ebus_apply_range(ebus_p, rdip, ebus_rp, &pci_reg);
598*7c478bd9Sstevel@tonic-gate 		break;
599*7c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
600*7c478bd9Sstevel@tonic-gate 		rval = febus_apply_range(ebus_p, rdip, ebus_rp, &reg);
601*7c478bd9Sstevel@tonic-gate 		break;
602*7c478bd9Sstevel@tonic-gate 	default:
603*7c478bd9Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
604*7c478bd9Sstevel@tonic-gate 		rval = DDI_FAILURE;
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
608*7c478bd9Sstevel@tonic-gate 		kmem_free(ebus_regs, i);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS)
611*7c478bd9Sstevel@tonic-gate 		return (rval);
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
614*7c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
615*7c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
616*7c478bd9Sstevel@tonic-gate 		DBG5(D_MAP, ebus_p, "(%x,%x,%x)(%x,%x)\n",
617*7c478bd9Sstevel@tonic-gate 			pci_reg.pci_phys_hi,
618*7c478bd9Sstevel@tonic-gate 			pci_reg.pci_phys_mid,
619*7c478bd9Sstevel@tonic-gate 			pci_reg.pci_phys_low,
620*7c478bd9Sstevel@tonic-gate 			pci_reg.pci_size_hi,
621*7c478bd9Sstevel@tonic-gate 			pci_reg.pci_size_low);
622*7c478bd9Sstevel@tonic-gate 		break;
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
625*7c478bd9Sstevel@tonic-gate 		DBG3(D_MAP, ebus_p, "%x,%x,%x\n",
626*7c478bd9Sstevel@tonic-gate 			reg.regspec_bustype,
627*7c478bd9Sstevel@tonic-gate 			reg.regspec_addr,
628*7c478bd9Sstevel@tonic-gate 			reg.regspec_size);
629*7c478bd9Sstevel@tonic-gate 		break;
630*7c478bd9Sstevel@tonic-gate 	}
631*7c478bd9Sstevel@tonic-gate #endif
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	p_map_request = *mp;
634*7c478bd9Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 	switch (ebus_p->type) {
637*7c478bd9Sstevel@tonic-gate 	case EBUS_TYPE:
638*7c478bd9Sstevel@tonic-gate 		p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
639*7c478bd9Sstevel@tonic-gate 		break;
640*7c478bd9Sstevel@tonic-gate 	case FEBUS_TYPE:
641*7c478bd9Sstevel@tonic-gate 		p_map_request.map_obj.rp = &reg;
642*7c478bd9Sstevel@tonic-gate 		break;
643*7c478bd9Sstevel@tonic-gate 	default:
644*7c478bd9Sstevel@tonic-gate 		DBG(D_MAP, NULL, "failed to recognize ebus type\n");
645*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
646*7c478bd9Sstevel@tonic-gate 	}
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
649*7c478bd9Sstevel@tonic-gate 	DBG1(D_MAP, ebus_p, "parent returned %x\n", rval);
650*7c478bd9Sstevel@tonic-gate 	return (rval);
651*7c478bd9Sstevel@tonic-gate }
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate static int
655*7c478bd9Sstevel@tonic-gate ebus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
656*7c478bd9Sstevel@tonic-gate     ebus_regspec_t *ebus_rp, pci_regspec_t *rp)
657*7c478bd9Sstevel@tonic-gate {
658*7c478bd9Sstevel@tonic-gate 	int b;
659*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
660*7c478bd9Sstevel@tonic-gate 	struct ebus_pci_rangespec *rangep = ebus_p->rangespec.rangep;
661*7c478bd9Sstevel@tonic-gate 	int nrange = ebus_p->range_cnt;
662*7c478bd9Sstevel@tonic-gate 	static char out_of_range[] =
663*7c478bd9Sstevel@tonic-gate 	    "Out of range register specification from device node <%s>";
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
666*7c478bd9Sstevel@tonic-gate 	    ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 		/* Check for the correct space */
671*7c478bd9Sstevel@tonic-gate 		if (ebus_rp->addr_hi == rangep->ebus_phys_hi)
672*7c478bd9Sstevel@tonic-gate 			/* See if we fit in this range */
673*7c478bd9Sstevel@tonic-gate 			if ((ebus_rp->addr_low >=
674*7c478bd9Sstevel@tonic-gate 			    rangep->ebus_phys_low) &&
675*7c478bd9Sstevel@tonic-gate 			    ((ebus_rp->addr_low + ebus_rp->size - 1)
676*7c478bd9Sstevel@tonic-gate 				<= (rangep->ebus_phys_low +
677*7c478bd9Sstevel@tonic-gate 				    rangep->rng_size - 1))) {
678*7c478bd9Sstevel@tonic-gate 				uint_t addr_offset = ebus_rp->addr_low -
679*7c478bd9Sstevel@tonic-gate 				    rangep->ebus_phys_low;
680*7c478bd9Sstevel@tonic-gate 				/*
681*7c478bd9Sstevel@tonic-gate 				 * Use the range entry to translate
682*7c478bd9Sstevel@tonic-gate 				 * the EBUS physical address into the
683*7c478bd9Sstevel@tonic-gate 				 * parents PCI space.
684*7c478bd9Sstevel@tonic-gate 				 */
685*7c478bd9Sstevel@tonic-gate 				rp->pci_phys_hi =
686*7c478bd9Sstevel@tonic-gate 				rangep->pci_phys_hi;
687*7c478bd9Sstevel@tonic-gate 				rp->pci_phys_mid = rangep->pci_phys_mid;
688*7c478bd9Sstevel@tonic-gate 				rp->pci_phys_low =
689*7c478bd9Sstevel@tonic-gate 					rangep->pci_phys_low + addr_offset;
690*7c478bd9Sstevel@tonic-gate 				rp->pci_size_hi = 0;
691*7c478bd9Sstevel@tonic-gate 				rp->pci_size_low =
692*7c478bd9Sstevel@tonic-gate 					min(ebus_rp->size, (rangep->rng_size -
693*7c478bd9Sstevel@tonic-gate 					addr_offset));
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
696*7c478bd9Sstevel@tonic-gate 					rangep->ebus_phys_hi,
697*7c478bd9Sstevel@tonic-gate 					rangep->ebus_phys_low);
698*7c478bd9Sstevel@tonic-gate 				DBG4(D_MAP, ebus_p, "Parent hi0x%x "
699*7c478bd9Sstevel@tonic-gate 					"mid0x%x lo0x%x size 0x%x\n",
700*7c478bd9Sstevel@tonic-gate 					rangep->pci_phys_hi,
701*7c478bd9Sstevel@tonic-gate 					rangep->pci_phys_mid,
702*7c478bd9Sstevel@tonic-gate 					rangep->pci_phys_low,
703*7c478bd9Sstevel@tonic-gate 					rangep->rng_size);
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 				break;
706*7c478bd9Sstevel@tonic-gate 			}
707*7c478bd9Sstevel@tonic-gate 	}
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	if (b == nrange)  {
710*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
711*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
712*7c478bd9Sstevel@tonic-gate 	}
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	return (rval);
715*7c478bd9Sstevel@tonic-gate }
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate static int
718*7c478bd9Sstevel@tonic-gate febus_apply_range(ebus_devstate_t *ebus_p, dev_info_t *rdip,
719*7c478bd9Sstevel@tonic-gate 		ebus_regspec_t *ebus_rp, struct regspec *rp) {
720*7c478bd9Sstevel@tonic-gate 	int b;
721*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
722*7c478bd9Sstevel@tonic-gate 	struct febus_rangespec *rangep = ebus_p->rangespec.ferangep;
723*7c478bd9Sstevel@tonic-gate 	int nrange = ebus_p->range_cnt;
724*7c478bd9Sstevel@tonic-gate 	static char out_of_range[] =
725*7c478bd9Sstevel@tonic-gate 		"Out of range register specification from device node <%s>";
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	DBG3(D_MAP, ebus_p, "Range Matching Addr 0x%x.%x size 0x%x\n",
728*7c478bd9Sstevel@tonic-gate 	ebus_rp->addr_hi, ebus_rp->addr_low, ebus_rp->size);
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
731*7c478bd9Sstevel@tonic-gate 		/* Check for the correct space */
732*7c478bd9Sstevel@tonic-gate 		if (ebus_rp->addr_hi == rangep->febus_phys_hi)
733*7c478bd9Sstevel@tonic-gate 			/* See if we fit in this range */
734*7c478bd9Sstevel@tonic-gate 			if ((ebus_rp->addr_low >=
735*7c478bd9Sstevel@tonic-gate 				rangep->febus_phys_low) &&
736*7c478bd9Sstevel@tonic-gate 				((ebus_rp->addr_low + ebus_rp->size - 1)
737*7c478bd9Sstevel@tonic-gate 				<= (rangep->febus_phys_low +
738*7c478bd9Sstevel@tonic-gate 				rangep->rng_size - 1))) {
739*7c478bd9Sstevel@tonic-gate 					uint_t addr_offset = ebus_rp->addr_low -
740*7c478bd9Sstevel@tonic-gate 					rangep->febus_phys_low;
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 				/*
743*7c478bd9Sstevel@tonic-gate 				 * Use the range entry to translate
744*7c478bd9Sstevel@tonic-gate 				 * the FEBUS physical address into the
745*7c478bd9Sstevel@tonic-gate 				 * parents space.
746*7c478bd9Sstevel@tonic-gate 				 */
747*7c478bd9Sstevel@tonic-gate 				rp->regspec_bustype =
748*7c478bd9Sstevel@tonic-gate 					rangep->parent_phys_hi;
749*7c478bd9Sstevel@tonic-gate 				rp->regspec_addr =
750*7c478bd9Sstevel@tonic-gate 				rangep->parent_phys_low + addr_offset;
751*7c478bd9Sstevel@tonic-gate 				rp->regspec_size =
752*7c478bd9Sstevel@tonic-gate 					min(ebus_rp->size, (rangep->rng_size -
753*7c478bd9Sstevel@tonic-gate 					addr_offset));
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 				DBG2(D_MAP, ebus_p, "Child hi0x%x lo0x%x ",
756*7c478bd9Sstevel@tonic-gate 					rangep->febus_phys_hi,
757*7c478bd9Sstevel@tonic-gate 					rangep->febus_phys_low);
758*7c478bd9Sstevel@tonic-gate 				DBG3(D_MAP, ebus_p, "Parent hi0x%x "
759*7c478bd9Sstevel@tonic-gate 					"lo0x%x size 0x%x\n",
760*7c478bd9Sstevel@tonic-gate 					rangep->parent_phys_hi,
761*7c478bd9Sstevel@tonic-gate 					rangep->parent_phys_low,
762*7c478bd9Sstevel@tonic-gate 					rangep->rng_size);
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 				break;
765*7c478bd9Sstevel@tonic-gate 			}
766*7c478bd9Sstevel@tonic-gate 	}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	if (b == nrange)  {
769*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, out_of_range, ddi_get_name(rdip));
770*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	return (rval);
774*7c478bd9Sstevel@tonic-gate }
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate static int
778*7c478bd9Sstevel@tonic-gate ebus_name_child(dev_info_t *child, char *name, int namelen)
779*7c478bd9Sstevel@tonic-gate {
780*7c478bd9Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp;
781*7c478bd9Sstevel@tonic-gate 	int reglen;
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	/*
784*7c478bd9Sstevel@tonic-gate 	 * Get the address portion of the node name based on the
785*7c478bd9Sstevel@tonic-gate 	 * address/offset.
786*7c478bd9Sstevel@tonic-gate 	 */
787*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
788*7c478bd9Sstevel@tonic-gate 	    "reg", (caddr_t)&ebus_rp, &reglen) != DDI_SUCCESS) {
789*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
790*7c478bd9Sstevel@tonic-gate 	}
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	(void) snprintf(name, namelen, "%x,%x", ebus_rp->addr_hi,
793*7c478bd9Sstevel@tonic-gate 	    ebus_rp->addr_low);
794*7c478bd9Sstevel@tonic-gate 	kmem_free(ebus_rp, reglen);
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
797*7c478bd9Sstevel@tonic-gate }
798*7c478bd9Sstevel@tonic-gate 
799*7c478bd9Sstevel@tonic-gate /*
800*7c478bd9Sstevel@tonic-gate  * control ops entry point:
801*7c478bd9Sstevel@tonic-gate  *
802*7c478bd9Sstevel@tonic-gate  * Requests handled completely:
803*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_INITCHILD
804*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_UNINITCHILD
805*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_REPORTDEV
806*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_REGSIZE
807*7c478bd9Sstevel@tonic-gate  *	DDI_CTLOPS_NREGS
808*7c478bd9Sstevel@tonic-gate  *
809*7c478bd9Sstevel@tonic-gate  * All others passed to parent.
810*7c478bd9Sstevel@tonic-gate  */
811*7c478bd9Sstevel@tonic-gate static int
812*7c478bd9Sstevel@tonic-gate ebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
813*7c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result)
814*7c478bd9Sstevel@tonic-gate {
815*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
816*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
817*7c478bd9Sstevel@tonic-gate #endif
818*7c478bd9Sstevel@tonic-gate 	ebus_regspec_t *ebus_rp;
819*7c478bd9Sstevel@tonic-gate 	int i, n;
820*7c478bd9Sstevel@tonic-gate 	char name[10];
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 	switch (op) {
823*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
824*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
825*7c478bd9Sstevel@tonic-gate 		/*
826*7c478bd9Sstevel@tonic-gate 		 * Set the address portion of the node name based on the
827*7c478bd9Sstevel@tonic-gate 		 * address/offset.
828*7c478bd9Sstevel@tonic-gate 		 */
829*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
830*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(child), ddi_get_instance(child));
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 		if (ebus_name_child(child, name, 10) != DDI_SUCCESS) {
833*7c478bd9Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't name child\n");
834*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
835*7c478bd9Sstevel@tonic-gate 		}
836*7c478bd9Sstevel@tonic-gate 
837*7c478bd9Sstevel@tonic-gate 		ddi_set_name_addr(child, name);
838*7c478bd9Sstevel@tonic-gate 		ddi_set_parent_data(child, NULL);
839*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
840*7c478bd9Sstevel@tonic-gate 	}
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
843*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
844*7c478bd9Sstevel@tonic-gate 			ddi_get_name((dev_info_t *)arg),
845*7c478bd9Sstevel@tonic-gate 			ddi_get_instance((dev_info_t *)arg));
846*7c478bd9Sstevel@tonic-gate 		ddi_set_name_addr((dev_info_t *)arg, NULL);
847*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node((dev_info_t *)arg, NULL);
848*7c478bd9Sstevel@tonic-gate 		impl_rem_dev_props((dev_info_t *)arg);
849*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
854*7c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
855*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
856*7c478bd9Sstevel@tonic-gate 			ddi_driver_name(rdip), ddi_get_instance(rdip),
857*7c478bd9Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip),
858*7c478bd9Sstevel@tonic-gate 			ddi_get_name_addr(rdip));
859*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
864*7c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
865*7c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
866*7c478bd9Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
867*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
868*7c478bd9Sstevel@tonic-gate 		}
869*7c478bd9Sstevel@tonic-gate 		n = i / sizeof (ebus_regspec_t);
870*7c478bd9Sstevel@tonic-gate 		if (*(int *)arg < 0 || *(int *)arg >= n) {
871*7c478bd9Sstevel@tonic-gate 			DBG(D_MAP, ebus_p, "rnumber out of range\n");
872*7c478bd9Sstevel@tonic-gate 			kmem_free(ebus_rp, i);
873*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
874*7c478bd9Sstevel@tonic-gate 		}
875*7c478bd9Sstevel@tonic-gate 		*((off_t *)result) = ebus_rp[*(int *)arg].size;
876*7c478bd9Sstevel@tonic-gate 		kmem_free(ebus_rp, i);
877*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
880*7c478bd9Sstevel@tonic-gate 
881*7c478bd9Sstevel@tonic-gate 		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
882*7c478bd9Sstevel@tonic-gate 			ddi_get_name(rdip), ddi_get_instance(rdip));
883*7c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
884*7c478bd9Sstevel@tonic-gate 			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
885*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
886*7c478bd9Sstevel@tonic-gate 		}
887*7c478bd9Sstevel@tonic-gate 		*((uint_t *)result) = i / sizeof (ebus_regspec_t);
888*7c478bd9Sstevel@tonic-gate 		kmem_free(ebus_rp, i);
889*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
890*7c478bd9Sstevel@tonic-gate 	}
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	/*
893*7c478bd9Sstevel@tonic-gate 	 * Now pass the request up to our parent.
894*7c478bd9Sstevel@tonic-gate 	 */
895*7c478bd9Sstevel@tonic-gate 	DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n",
896*7c478bd9Sstevel@tonic-gate 		ddi_get_name(rdip), ddi_get_instance(rdip));
897*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
898*7c478bd9Sstevel@tonic-gate }
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate struct ebus_string_to_pil {
901*7c478bd9Sstevel@tonic-gate 	int8_t *string;
902*7c478bd9Sstevel@tonic-gate 	uint32_t pil;
903*7c478bd9Sstevel@tonic-gate };
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_name_to_pil[] = {{"SUNW,CS4231", 9},
906*7c478bd9Sstevel@tonic-gate 							{"audio", 9},
907*7c478bd9Sstevel@tonic-gate 							{"fdthree", 8},
908*7c478bd9Sstevel@tonic-gate 							{"floppy", 8},
909*7c478bd9Sstevel@tonic-gate 							{"ecpp", 3},
910*7c478bd9Sstevel@tonic-gate 							{"parallel", 3},
911*7c478bd9Sstevel@tonic-gate 							{"su", 12},
912*7c478bd9Sstevel@tonic-gate 							{"se", 12},
913*7c478bd9Sstevel@tonic-gate 							{"serial", 12},
914*7c478bd9Sstevel@tonic-gate 							{"power", 14}};
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate static struct ebus_string_to_pil ebus_device_type_to_pil[] = {{"serial", 12},
917*7c478bd9Sstevel@tonic-gate 								{"block", 8}};
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate static int
920*7c478bd9Sstevel@tonic-gate ebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
921*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
922*7c478bd9Sstevel@tonic-gate {
923*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
924*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p = get_ebus_soft_state(ddi_get_instance(dip));
925*7c478bd9Sstevel@tonic-gate #endif
926*7c478bd9Sstevel@tonic-gate 	ddi_ispec_t		*ip = (ddi_ispec_t *)hdlp->ih_private;
927*7c478bd9Sstevel@tonic-gate 	int32_t			i, max_children, max_device_types, len;
928*7c478bd9Sstevel@tonic-gate 	char			*name_p, *device_type_p;
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 	DBG1(D_INTR, ebus_p, "ip 0x%p\n", ip);
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	/*
933*7c478bd9Sstevel@tonic-gate 	 * NOTE: These ops below will never be supported in this nexus
934*7c478bd9Sstevel@tonic-gate 	 * driver, hence they always return immediately.
935*7c478bd9Sstevel@tonic-gate 	 */
936*7c478bd9Sstevel@tonic-gate 	switch (intr_op) {
937*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
938*7c478bd9Sstevel@tonic-gate 		*(int *)result = 0;
939*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
940*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETCAP:
941*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SETMASK:
942*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_CLRMASK:
943*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPENDING:
944*7c478bd9Sstevel@tonic-gate 		return (DDI_ENOTSUP);
945*7c478bd9Sstevel@tonic-gate 	default:
946*7c478bd9Sstevel@tonic-gate 		break;
947*7c478bd9Sstevel@tonic-gate 	}
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) || ip->is_pil)
950*7c478bd9Sstevel@tonic-gate 		goto done;
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 	/*
953*7c478bd9Sstevel@tonic-gate 	 * This is a hack to set the PIL for the devices under ebus.
954*7c478bd9Sstevel@tonic-gate 	 * We first look up a device by it's specific name, if we can't
955*7c478bd9Sstevel@tonic-gate 	 * match the name, we try and match it's device_type property.
956*7c478bd9Sstevel@tonic-gate 	 * Lastly we default a PIL level of 1.
957*7c478bd9Sstevel@tonic-gate 	 */
958*7c478bd9Sstevel@tonic-gate 	name_p = ddi_node_name(rdip);
959*7c478bd9Sstevel@tonic-gate 	max_children = sizeof (ebus_name_to_pil) /
960*7c478bd9Sstevel@tonic-gate 	    sizeof (struct ebus_string_to_pil);
961*7c478bd9Sstevel@tonic-gate 
962*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < max_children; i++) {
963*7c478bd9Sstevel@tonic-gate 		if (strcmp(ebus_name_to_pil[i].string, name_p) == 0) {
964*7c478bd9Sstevel@tonic-gate 			DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n",
965*7c478bd9Sstevel@tonic-gate 			    ebus_name_to_pil[i].string,
966*7c478bd9Sstevel@tonic-gate 			    ebus_name_to_pil[i].pil);
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 			ip->is_pil = ebus_name_to_pil[i].pil;
969*7c478bd9Sstevel@tonic-gate 			goto done;
970*7c478bd9Sstevel@tonic-gate 		}
971*7c478bd9Sstevel@tonic-gate 	}
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS,
974*7c478bd9Sstevel@tonic-gate 	    "device_type", (caddr_t)&device_type_p, &len) == DDI_SUCCESS) {
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 		max_device_types = sizeof (ebus_device_type_to_pil) /
977*7c478bd9Sstevel@tonic-gate 		    sizeof (struct ebus_string_to_pil);
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < max_device_types; i++) {
980*7c478bd9Sstevel@tonic-gate 			if (strcmp(ebus_device_type_to_pil[i].string,
981*7c478bd9Sstevel@tonic-gate 			    device_type_p) == 0) {
982*7c478bd9Sstevel@tonic-gate 				DBG2(D_INTR, ebus_p, "Device type %s; match "
983*7c478bd9Sstevel@tonic-gate 				    "PIL %d\n", ebus_device_type_to_pil[i].
984*7c478bd9Sstevel@tonic-gate 				    string, ebus_device_type_to_pil[i].pil);
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 				ip->is_pil = ebus_device_type_to_pil[i].pil;
987*7c478bd9Sstevel@tonic-gate 				break;
988*7c478bd9Sstevel@tonic-gate 			}
989*7c478bd9Sstevel@tonic-gate 		}
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 		kmem_free(device_type_p, len);
992*7c478bd9Sstevel@tonic-gate 	}
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	/*
995*7c478bd9Sstevel@tonic-gate 	 * If we get here, we need to set a default value
996*7c478bd9Sstevel@tonic-gate 	 * for the PIL.
997*7c478bd9Sstevel@tonic-gate 	 */
998*7c478bd9Sstevel@tonic-gate 	if (ip->is_pil == 0) {
999*7c478bd9Sstevel@tonic-gate 		ip->is_pil = 1;
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d assigning default interrupt level %d "
1002*7c478bd9Sstevel@tonic-gate 		    "for device %s%d", ddi_get_name(dip), ddi_get_instance(dip),
1003*7c478bd9Sstevel@tonic-gate 		    ip->is_pil, ddi_get_name(rdip), ddi_get_instance(rdip));
1004*7c478bd9Sstevel@tonic-gate 	}
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate done:
1007*7c478bd9Sstevel@tonic-gate 	/* Pass up the request to our parent. */
1008*7c478bd9Sstevel@tonic-gate 	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
1009*7c478bd9Sstevel@tonic-gate }
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate static int
1013*7c478bd9Sstevel@tonic-gate ebus_config(ebus_devstate_t *ebus_p)
1014*7c478bd9Sstevel@tonic-gate {
1015*7c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t conf_handle;
1016*7c478bd9Sstevel@tonic-gate 	uint16_t comm;
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	/*
1019*7c478bd9Sstevel@tonic-gate 	 * Make sure the master enable and memory access enable
1020*7c478bd9Sstevel@tonic-gate 	 * bits are set in the config command register.
1021*7c478bd9Sstevel@tonic-gate 	 */
1022*7c478bd9Sstevel@tonic-gate 	if (pci_config_setup(ebus_p->dip, &conf_handle) != DDI_SUCCESS)
1023*7c478bd9Sstevel@tonic-gate 		return (0);
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM),
1026*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1027*7c478bd9Sstevel@tonic-gate 	    DBG1(D_MAP, ebus_p, "command register was 0x%x\n", comm);
1028*7c478bd9Sstevel@tonic-gate #endif
1029*7c478bd9Sstevel@tonic-gate 	comm |= (PCI_COMM_ME|PCI_COMM_MAE|PCI_COMM_SERR_ENABLE|
1030*7c478bd9Sstevel@tonic-gate 	    PCI_COMM_PARITY_DETECT);
1031*7c478bd9Sstevel@tonic-gate 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm),
1032*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1033*7c478bd9Sstevel@tonic-gate 	    DBG1(D_MAP, ebus_p, "command register is now 0x%x\n", comm);
1034*7c478bd9Sstevel@tonic-gate #endif
1035*7c478bd9Sstevel@tonic-gate 	pci_config_put8(conf_handle, PCI_CONF_CACHE_LINESZ,
1036*7c478bd9Sstevel@tonic-gate 	    (uchar_t)ebus_cache_line_size);
1037*7c478bd9Sstevel@tonic-gate 	pci_config_put8(conf_handle, PCI_CONF_LATENCY_TIMER,
1038*7c478bd9Sstevel@tonic-gate 	    (uchar_t)ebus_latency_timer);
1039*7c478bd9Sstevel@tonic-gate 	pci_config_teardown(&conf_handle);
1040*7c478bd9Sstevel@tonic-gate 	return (1);
1041*7c478bd9Sstevel@tonic-gate }
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1044*7c478bd9Sstevel@tonic-gate extern void prom_printf(const char *, ...);
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate static void
1047*7c478bd9Sstevel@tonic-gate ebus_debug(uint_t flag, ebus_devstate_t *ebus_p, char *fmt,
1048*7c478bd9Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1049*7c478bd9Sstevel@tonic-gate {
1050*7c478bd9Sstevel@tonic-gate 	char *s;
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 	if (ebus_debug_flags & flag) {
1053*7c478bd9Sstevel@tonic-gate 		switch (flag) {
1054*7c478bd9Sstevel@tonic-gate 		case D_ATTACH:
1055*7c478bd9Sstevel@tonic-gate 			s = "attach"; break;
1056*7c478bd9Sstevel@tonic-gate 		case D_DETACH:
1057*7c478bd9Sstevel@tonic-gate 			s = "detach"; break;
1058*7c478bd9Sstevel@tonic-gate 		case D_MAP:
1059*7c478bd9Sstevel@tonic-gate 			s = "map"; break;
1060*7c478bd9Sstevel@tonic-gate 		case D_CTLOPS:
1061*7c478bd9Sstevel@tonic-gate 			s = "ctlops"; break;
1062*7c478bd9Sstevel@tonic-gate 		case D_INTR:
1063*7c478bd9Sstevel@tonic-gate 			s = "intr"; break;
1064*7c478bd9Sstevel@tonic-gate 		}
1065*7c478bd9Sstevel@tonic-gate 		if (ebus_p)
1066*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: %s: ",
1067*7c478bd9Sstevel@tonic-gate 				ddi_get_name(ebus_p->dip),
1068*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(ebus_p->dip), s);
1069*7c478bd9Sstevel@tonic-gate 		else
1070*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "ebus: ");
1071*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
1072*7c478bd9Sstevel@tonic-gate 	}
1073*7c478bd9Sstevel@tonic-gate }
1074*7c478bd9Sstevel@tonic-gate #endif
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
1077*7c478bd9Sstevel@tonic-gate static int
1078*7c478bd9Sstevel@tonic-gate ebus_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1079*7c478bd9Sstevel@tonic-gate {
1080*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	/*
1083*7c478bd9Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
1084*7c478bd9Sstevel@tonic-gate 	 */
1085*7c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1086*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 	/*
1089*7c478bd9Sstevel@tonic-gate 	 * Get the soft state structure for the device.
1090*7c478bd9Sstevel@tonic-gate 	 */
1091*7c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(*devp));
1092*7c478bd9Sstevel@tonic-gate 	if (ebus_p == NULL)
1093*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	/*
1096*7c478bd9Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
1097*7c478bd9Sstevel@tonic-gate 	 */
1098*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ebus_p->ebus_mutex);
1099*7c478bd9Sstevel@tonic-gate 	if (flags & FEXCL) {
1100*7c478bd9Sstevel@tonic-gate 		if (ebus_p->ebus_soft_state != EBUS_SOFT_STATE_CLOSED) {
1101*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ebus_p->ebus_mutex);
1102*7c478bd9Sstevel@tonic-gate 			return (EBUSY);
1103*7c478bd9Sstevel@tonic-gate 		}
1104*7c478bd9Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN_EXCL;
1105*7c478bd9Sstevel@tonic-gate 	} else {
1106*7c478bd9Sstevel@tonic-gate 		if (ebus_p->ebus_soft_state == EBUS_SOFT_STATE_OPEN_EXCL) {
1107*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ebus_p->ebus_mutex);
1108*7c478bd9Sstevel@tonic-gate 			return (EBUSY);
1109*7c478bd9Sstevel@tonic-gate 		}
1110*7c478bd9Sstevel@tonic-gate 		ebus_p->ebus_soft_state = EBUS_SOFT_STATE_OPEN;
1111*7c478bd9Sstevel@tonic-gate 	}
1112*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ebus_p->ebus_mutex);
1113*7c478bd9Sstevel@tonic-gate 	return (0);
1114*7c478bd9Sstevel@tonic-gate }
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1118*7c478bd9Sstevel@tonic-gate static int
1119*7c478bd9Sstevel@tonic-gate ebus_close(dev_t dev, int flags, int otyp, cred_t *credp)
1120*7c478bd9Sstevel@tonic-gate {
1121*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1124*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1125*7c478bd9Sstevel@tonic-gate 
1126*7c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(dev));
1127*7c478bd9Sstevel@tonic-gate 	if (ebus_p == NULL)
1128*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ebus_p->ebus_mutex);
1131*7c478bd9Sstevel@tonic-gate 	ebus_p->ebus_soft_state = EBUS_SOFT_STATE_CLOSED;
1132*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ebus_p->ebus_mutex);
1133*7c478bd9Sstevel@tonic-gate 	return (0);
1134*7c478bd9Sstevel@tonic-gate }
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate /*
1138*7c478bd9Sstevel@tonic-gate  * ebus_ioctl: devctl hotplug controls
1139*7c478bd9Sstevel@tonic-gate  */
1140*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1141*7c478bd9Sstevel@tonic-gate static int
1142*7c478bd9Sstevel@tonic-gate ebus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1143*7c478bd9Sstevel@tonic-gate 	int *rvalp)
1144*7c478bd9Sstevel@tonic-gate {
1145*7c478bd9Sstevel@tonic-gate 	ebus_devstate_t *ebus_p;
1146*7c478bd9Sstevel@tonic-gate 	dev_info_t *self;
1147*7c478bd9Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
1148*7c478bd9Sstevel@tonic-gate 	uint_t bus_state;
1149*7c478bd9Sstevel@tonic-gate 	int rv = 0;
1150*7c478bd9Sstevel@tonic-gate 
1151*7c478bd9Sstevel@tonic-gate 	ebus_p = get_ebus_soft_state(getminor(dev));
1152*7c478bd9Sstevel@tonic-gate 	if (ebus_p == NULL)
1153*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	self = ebus_p->dip;
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	/*
1158*7c478bd9Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
1159*7c478bd9Sstevel@tonic-gate 	 */
1160*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1161*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
1162*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
1163*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
1164*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
1165*7c478bd9Sstevel@tonic-gate 		return (ndi_devctl_ioctl(self, cmd, arg, mode, 0));
1166*7c478bd9Sstevel@tonic-gate 	}
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	/*
1169*7c478bd9Sstevel@tonic-gate 	 * read devctl ioctl data
1170*7c478bd9Sstevel@tonic-gate 	 */
1171*7c478bd9Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1172*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1175*7c478bd9Sstevel@tonic-gate 
1176*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
1177*7c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
1178*7c478bd9Sstevel@tonic-gate 		break;
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
1181*7c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1182*7c478bd9Sstevel@tonic-gate 			if (bus_state == BUS_QUIESCED)
1183*7c478bd9Sstevel@tonic-gate 				break;
1184*7c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_QUIESCED);
1185*7c478bd9Sstevel@tonic-gate 		break;
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
1188*7c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &bus_state) == NDI_SUCCESS)
1189*7c478bd9Sstevel@tonic-gate 			if (bus_state == BUS_ACTIVE)
1190*7c478bd9Sstevel@tonic-gate 				break;
1191*7c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1192*7c478bd9Sstevel@tonic-gate 		break;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
1195*7c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
1196*7c478bd9Sstevel@tonic-gate 		break;
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
1199*7c478bd9Sstevel@tonic-gate 		rv = ENOTSUP;
1200*7c478bd9Sstevel@tonic-gate 		break;
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	default:
1203*7c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
1204*7c478bd9Sstevel@tonic-gate 	}
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
1207*7c478bd9Sstevel@tonic-gate 	return (rv);
1208*7c478bd9Sstevel@tonic-gate }
1209