xref: /titanic_50/usr/src/uts/sun4u/io/sbbc.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 /*
30*7c478bd9Sstevel@tonic-gate  * Starcat PCI SBBC Device Nexus Driver that provides interfaces into
31*7c478bd9Sstevel@tonic-gate  * Console Bus, I2C, Error/Intr. EPLD, IOSRAM, and JTAG.
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
37*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/pci.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/nexusintr_impl.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/pci/pci_nexus.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate 
56*7c478bd9Sstevel@tonic-gate #include <sys/sbbcreg.h>	/* hw description */
57*7c478bd9Sstevel@tonic-gate #include <sys/sbbcvar.h>	/* driver description */
58*7c478bd9Sstevel@tonic-gate #include <sys/sbbcio.h>		/* ioctl description */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #define	getprop(dip, name, addr, intp)		\
62*7c478bd9Sstevel@tonic-gate 		ddi_getlongprop(DDI_DEV_T_NONE, (dip), DDI_PROP_DONTPASS, \
63*7c478bd9Sstevel@tonic-gate 				(name), (caddr_t)(addr), (intp))
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /* driver entry point fn definitions */
66*7c478bd9Sstevel@tonic-gate static int sbbc_open(dev_t *, int, int, cred_t *);
67*7c478bd9Sstevel@tonic-gate static int sbbc_close(dev_t, int, int, cred_t *);
68*7c478bd9Sstevel@tonic-gate static int sbbc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate /* configuration entry point fn definitions */
71*7c478bd9Sstevel@tonic-gate static int sbbc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
72*7c478bd9Sstevel@tonic-gate static int sbbc_attach(dev_info_t *, ddi_attach_cmd_t);
73*7c478bd9Sstevel@tonic-gate static int sbbc_detach(dev_info_t *, ddi_detach_cmd_t);
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /* local utility routines */
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * NOTE - sbbc_offset_valid contains detailed address information taken from
78*7c478bd9Sstevel@tonic-gate  * the Serengeti Architecture Programmer's Reference Manual.  If any
79*7c478bd9Sstevel@tonic-gate  * changes are made to the SBBC registers, this routine may need to be
80*7c478bd9Sstevel@tonic-gate  * updated.
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate static int sbbc_offset_valid(uint32_t offset);
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /*
85*7c478bd9Sstevel@tonic-gate  * function prototypes for bus ops routines:
86*7c478bd9Sstevel@tonic-gate  */
87*7c478bd9Sstevel@tonic-gate static int sbbc_busmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
88*7c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *addrp);
89*7c478bd9Sstevel@tonic-gate static int sbbc_ctlops(dev_info_t *dip, dev_info_t *rdip,
90*7c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result);
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate static int sbbc_intr_ops(dev_info_t *dip, dev_info_t *rdip,
93*7c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
94*7c478bd9Sstevel@tonic-gate static int sbbc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
95*7c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
96*7c478bd9Sstevel@tonic-gate static int sbbc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
97*7c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
98*7c478bd9Sstevel@tonic-gate static int sbbc_update_intr_state(dev_info_t *dip, dev_info_t *rdip,
99*7c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate static int sbbc_apply_range(struct sbbcsoft *sbbc_p, dev_info_t *rdip,
102*7c478bd9Sstevel@tonic-gate     sbbc_child_regspec_t *child_rp, pci_regspec_t *rp);
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate static int sbbc_init(struct sbbcsoft *);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate static uint_t sbbc_intr_wrapper(caddr_t arg);
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate static int sbbc_get_ranges(struct sbbcsoft *);
109*7c478bd9Sstevel@tonic-gate static int sbbc_config4pci(struct sbbcsoft *);
110*7c478bd9Sstevel@tonic-gate static int sbbc_initchild(dev_info_t *, dev_info_t *, dev_info_t *);
111*7c478bd9Sstevel@tonic-gate static int sbbc_uninitchild(dev_info_t *, dev_info_t *);
112*7c478bd9Sstevel@tonic-gate static void sbbc_remove_reg_maps(struct sbbcsoft *);
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /* debugging functions */
115*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
116*7c478bd9Sstevel@tonic-gate uint32_t sbbc_dbg_flags = 0x0;
117*7c478bd9Sstevel@tonic-gate static void sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt,
118*7c478bd9Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5);
119*7c478bd9Sstevel@tonic-gate #endif
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate  * For tracing, allocate space for the trace buffer
123*7c478bd9Sstevel@tonic-gate  */
124*7c478bd9Sstevel@tonic-gate #if defined(SBBC_TRACE)
125*7c478bd9Sstevel@tonic-gate struct sbbctrace sbbctrace_buffer[NSBBCTRACE+1];
126*7c478bd9Sstevel@tonic-gate struct sbbctrace *sbbctrace_ptr;
127*7c478bd9Sstevel@tonic-gate int sbbctrace_count;
128*7c478bd9Sstevel@tonic-gate #endif
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /*
131*7c478bd9Sstevel@tonic-gate  * Local declarations and variables
132*7c478bd9Sstevel@tonic-gate  */
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate static void *sbbcsoft_statep;
135*7c478bd9Sstevel@tonic-gate int sbbc_scmode = FALSE;
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate /*
138*7c478bd9Sstevel@tonic-gate  * ops stuff.
139*7c478bd9Sstevel@tonic-gate  */
140*7c478bd9Sstevel@tonic-gate static struct bus_ops sbbc_bus_ops = {
141*7c478bd9Sstevel@tonic-gate 	BUSO_REV,
142*7c478bd9Sstevel@tonic-gate 	sbbc_busmap,
143*7c478bd9Sstevel@tonic-gate 	0,
144*7c478bd9Sstevel@tonic-gate 	0,
145*7c478bd9Sstevel@tonic-gate 	0,
146*7c478bd9Sstevel@tonic-gate 	NULL, 			/* (*bus_map_fault)() */
147*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_map,
148*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_allochdl,
149*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_freehdl, 	/* (*bus_dma_freehdl)() */
150*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_bindhdl, 	/* (*bus_dma_bindhdl)() */
151*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_unbindhdl, 	/* (*bus_dma_unbindhdl)() */
152*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_flush, 	/* (*bus_dma_flush)() */
153*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_win, 	/* (*bus_dma_win)() */
154*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_mctl, 	/* (*bus_dma_ctl)() */
155*7c478bd9Sstevel@tonic-gate 	sbbc_ctlops,
156*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
157*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_get_eventcookie)();	*/
158*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_add_eventcall)();	*/
159*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_remove_eventcall)();	*/
160*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_post_event)();		*/
161*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_intr_ctl)();	*/
162*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_config)();	*/
163*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_unconfig)();	*/
164*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_init)();	*/
165*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_fini)();	*/
166*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_access_enter)();	*/
167*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_access_exit)();	*/
168*7c478bd9Sstevel@tonic-gate 	0,			/* (*bus_power)();	*/
169*7c478bd9Sstevel@tonic-gate 	sbbc_intr_ops		/* (*bus_intr_op)();	*/
170*7c478bd9Sstevel@tonic-gate };
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate /*
173*7c478bd9Sstevel@tonic-gate  * cb_ops
174*7c478bd9Sstevel@tonic-gate  */
175*7c478bd9Sstevel@tonic-gate static struct cb_ops sbbc_cb_ops = {
176*7c478bd9Sstevel@tonic-gate 	sbbc_open,		/* cb_open */
177*7c478bd9Sstevel@tonic-gate 	sbbc_close,		/* cb_close */
178*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_strategy */
179*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_print */
180*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_dump */
181*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_read */
182*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_write */
183*7c478bd9Sstevel@tonic-gate 	sbbc_ioctl,		/* cb_ioctl */
184*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_devmap */
185*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_mmap */
186*7c478bd9Sstevel@tonic-gate 	nodev,			/* cb_segmap */
187*7c478bd9Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
188*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
189*7c478bd9Sstevel@tonic-gate 	NULL,			/* cb_stream */
190*7c478bd9Sstevel@tonic-gate 	(int)(D_NEW | D_MP)	/* cb_flag */
191*7c478bd9Sstevel@tonic-gate };
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate /*
194*7c478bd9Sstevel@tonic-gate  * Declare ops vectors for auto configuration.
195*7c478bd9Sstevel@tonic-gate  */
196*7c478bd9Sstevel@tonic-gate struct dev_ops  sbbc_ops = {
197*7c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
198*7c478bd9Sstevel@tonic-gate 	0,			/* devo_refcnt */
199*7c478bd9Sstevel@tonic-gate 	sbbc_getinfo,		/* devo_getinfo */
200*7c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_identify */
201*7c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_probe */
202*7c478bd9Sstevel@tonic-gate 	sbbc_attach,		/* devo_attach */
203*7c478bd9Sstevel@tonic-gate 	sbbc_detach,		/* devo_detach */
204*7c478bd9Sstevel@tonic-gate 	nodev,			/* devo_reset */
205*7c478bd9Sstevel@tonic-gate 	&sbbc_cb_ops,		/* devo_cb_ops */
206*7c478bd9Sstevel@tonic-gate 	&sbbc_bus_ops,		/* devo_bus_ops */
207*7c478bd9Sstevel@tonic-gate 	nulldev			/* devo_power */
208*7c478bd9Sstevel@tonic-gate };
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate /*
211*7c478bd9Sstevel@tonic-gate  * Loadable module support.
212*7c478bd9Sstevel@tonic-gate  */
213*7c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate static struct modldrv sbbcmodldrv = {
216*7c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* type of module - driver */
217*7c478bd9Sstevel@tonic-gate 	"PCI Sbbc Nexus Driver v%I%",
218*7c478bd9Sstevel@tonic-gate 	&sbbc_ops,
219*7c478bd9Sstevel@tonic-gate };
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate static struct modlinkage sbbcmodlinkage = {
222*7c478bd9Sstevel@tonic-gate 	MODREV_1,
223*7c478bd9Sstevel@tonic-gate 	&sbbcmodldrv,
224*7c478bd9Sstevel@tonic-gate 	NULL
225*7c478bd9Sstevel@tonic-gate };
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate int
228*7c478bd9Sstevel@tonic-gate _init(void)
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	int    error;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&sbbcsoft_statep,
233*7c478bd9Sstevel@tonic-gate 		    sizeof (struct sbbcsoft), 1)) != 0)
234*7c478bd9Sstevel@tonic-gate 		return (error);
235*7c478bd9Sstevel@tonic-gate 	if ((error = mod_install(&sbbcmodlinkage)) != 0)
236*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&sbbcsoft_statep);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	return (error);
239*7c478bd9Sstevel@tonic-gate }
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate int
242*7c478bd9Sstevel@tonic-gate _fini(void)
243*7c478bd9Sstevel@tonic-gate {
244*7c478bd9Sstevel@tonic-gate 	int    error;
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	if ((error = mod_remove(&sbbcmodlinkage)) == 0)
247*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&sbbcsoft_statep);
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	return (error);
250*7c478bd9Sstevel@tonic-gate }
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate int
253*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
254*7c478bd9Sstevel@tonic-gate {
255*7c478bd9Sstevel@tonic-gate 	return (mod_info(&sbbcmodlinkage, modinfop));
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate static int
259*7c478bd9Sstevel@tonic-gate sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
260*7c478bd9Sstevel@tonic-gate {
261*7c478bd9Sstevel@tonic-gate 	int	instance;
262*7c478bd9Sstevel@tonic-gate 	char	name[32];
263*7c478bd9Sstevel@tonic-gate 	struct	sbbcsoft *sbbcsoftp;
264*7c478bd9Sstevel@tonic-gate 	struct ddi_device_acc_attr attr;
265*7c478bd9Sstevel@tonic-gate 	uint32_t sbbc_id_reg = 0;
266*7c478bd9Sstevel@tonic-gate 	uint16_t sbbc_id_reg_partid;
267*7c478bd9Sstevel@tonic-gate 	uint16_t sbbc_id_reg_manfid;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
270*7c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
271*7c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	/* initialize tracing */
274*7c478bd9Sstevel@tonic-gate 	SBBCTRACEINIT();
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attaching\n");
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
279*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
280*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
281*7c478bd9Sstevel@tonic-gate 		break;
282*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
283*7c478bd9Sstevel@tonic-gate 		if (!(sbbcsoftp =
284*7c478bd9Sstevel@tonic-gate 		    ddi_get_soft_state(sbbcsoft_statep, instance))) {
285*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
286*7c478bd9Sstevel@tonic-gate 	    "sbbc_attach:resume: unable to acquire sbbcsoftp for instance %d",
287*7c478bd9Sstevel@tonic-gate 			    instance);
288*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
289*7c478bd9Sstevel@tonic-gate 		}
290*7c478bd9Sstevel@tonic-gate 		mutex_enter(&sbbcsoftp->umutex);
291*7c478bd9Sstevel@tonic-gate 		if (!sbbcsoftp->suspended) {
292*7c478bd9Sstevel@tonic-gate 			mutex_exit(&sbbcsoftp->umutex);
293*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 		sbbcsoftp->suspended = 0;
296*7c478bd9Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
297*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	default:
300*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(sbbcsoft_statep, instance) != 0) {
304*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_WARN,
305*7c478bd9Sstevel@tonic-gate 	    "sbbc_attach: Unable to allocate statep for instance %d",
306*7c478bd9Sstevel@tonic-gate 				    instance);
307*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance);
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if (sbbcsoftp == NULL) {
313*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_WARN,
314*7c478bd9Sstevel@tonic-gate 	    "sbbc_attach: Unable to acquire sbbcsoftp for instance %d",
315*7c478bd9Sstevel@tonic-gate 					    instance);
316*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(sbbcsoft_statep, instance);
317*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
318*7c478bd9Sstevel@tonic-gate 	}
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->instance = instance;
321*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->dip = dip;
322*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->oflag = FALSE;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	/*
325*7c478bd9Sstevel@tonic-gate 	 * Read our ranges property from OBP to map children space.
326*7c478bd9Sstevel@tonic-gate 	 * And setup the internal structure for a later use when
327*7c478bd9Sstevel@tonic-gate 	 * a child gets initialized.
328*7c478bd9Sstevel@tonic-gate 	 */
329*7c478bd9Sstevel@tonic-gate 	if (sbbc_get_ranges(sbbcsoftp)) {
330*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_WARN,
331*7c478bd9Sstevel@tonic-gate 	    "sbbc_attach: Unable to read sbbc ranges from OBP %d", instance);
332*7c478bd9Sstevel@tonic-gate 	    ddi_soft_state_free(sbbcsoft_statep, instance);
333*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	if (sbbc_config4pci(sbbcsoftp)) {
337*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_WARN,
338*7c478bd9Sstevel@tonic-gate 	    "sbbc_attach: Unable to configure sbbc on PCI %d", instance);
339*7c478bd9Sstevel@tonic-gate 	    kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
340*7c478bd9Sstevel@tonic-gate 	    ddi_soft_state_free(sbbcsoft_statep, instance);
341*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
342*7c478bd9Sstevel@tonic-gate 	}
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	/*
345*7c478bd9Sstevel@tonic-gate 	 * Map SBBC's internal registers used by hardware access daemon.
346*7c478bd9Sstevel@tonic-gate 	 */
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	/* map the whole thing since OBP does not map individual devices */
349*7c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&sbbcsoftp->pci_sbbc_map,
350*7c478bd9Sstevel@tonic-gate 	    0, 0, &attr, &sbbcsoftp->pci_sbbc_map_handle) != DDI_SUCCESS) {
351*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "(%d):sbbc_attach failed to map sbbc_reg",
352*7c478bd9Sstevel@tonic-gate 			instance);
353*7c478bd9Sstevel@tonic-gate 		goto failed;
354*7c478bd9Sstevel@tonic-gate 	}
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 	sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
357*7c478bd9Sstevel@tonic-gate 		    (uint32_t *)
358*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.device_conf);
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	if (sbbc_id_reg & SBBC_SC_MODE) {
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 		SBBC_DBG5(SBBC_DBG_ATTACH, dip,
363*7c478bd9Sstevel@tonic-gate 	"Mapped sbbc %llx, regs %llx, eregs %llx, sram %llx, consbus %llx\n",
364*7c478bd9Sstevel@tonic-gate 		    sbbcsoftp->pci_sbbc_map,
365*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs,
366*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->echip_regs,
367*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sram[0],
368*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->consbus);
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 		sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
371*7c478bd9Sstevel@tonic-gate 			    (uint32_t *)
372*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.devid);
373*7c478bd9Sstevel@tonic-gate 		sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16);
374*7c478bd9Sstevel@tonic-gate 		sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21);
375*7c478bd9Sstevel@tonic-gate 		SBBC_DBG4(SBBC_DBG_ATTACH, dip,
376*7c478bd9Sstevel@tonic-gate 		    "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n",
377*7c478bd9Sstevel@tonic-gate 		    instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid,
378*7c478bd9Sstevel@tonic-gate 		    sbbc_id_reg_manfid);
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 		sbbc_scmode = TRUE;
381*7c478bd9Sstevel@tonic-gate 		SBBC_DBG1(SBBC_DBG_ATTACH, dip,
382*7c478bd9Sstevel@tonic-gate 	    "SBBC(%d) nexus running in System Controller Mode.\n",
383*7c478bd9Sstevel@tonic-gate 		    instance);
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 		/*
386*7c478bd9Sstevel@tonic-gate 		 * There will be only one SBBC instance on SC and no
387*7c478bd9Sstevel@tonic-gate 		 * chosen node stuff to deal with :-)
388*7c478bd9Sstevel@tonic-gate 		 */
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	} else {
391*7c478bd9Sstevel@tonic-gate 		/* The code below needs to be common with SC mode above */
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 		SBBC_DBG4(SBBC_DBG_ATTACH, dip,
394*7c478bd9Sstevel@tonic-gate 	"Mapped sbbc %llx, regs %llx, eregs %llx, sram %llx\n",
395*7c478bd9Sstevel@tonic-gate 		    sbbcsoftp->pci_sbbc_map,
396*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs,
397*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->echip_regs,
398*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sram[0]);
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 		sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
401*7c478bd9Sstevel@tonic-gate 			    (uint32_t *)
402*7c478bd9Sstevel@tonic-gate 		    &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.devid);
403*7c478bd9Sstevel@tonic-gate 		sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16);
404*7c478bd9Sstevel@tonic-gate 		sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21);
405*7c478bd9Sstevel@tonic-gate 		SBBC_DBG4(SBBC_DBG_ATTACH, dip,
406*7c478bd9Sstevel@tonic-gate 		    "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n",
407*7c478bd9Sstevel@tonic-gate 		    instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid,
408*7c478bd9Sstevel@tonic-gate 		    sbbc_id_reg_manfid);
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 		sbbc_scmode = FALSE;
411*7c478bd9Sstevel@tonic-gate 		SBBC_DBG1(SBBC_DBG_ATTACH, dip,
412*7c478bd9Sstevel@tonic-gate 	    "SBBC(%d) nexus running in Domain Mode.\n",
413*7c478bd9Sstevel@tonic-gate 		    instance);
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 		/*
416*7c478bd9Sstevel@tonic-gate 		 * There will be only one SBBC instance on SC and no
417*7c478bd9Sstevel@tonic-gate 		 * chosen node stuff to deal with :-)
418*7c478bd9Sstevel@tonic-gate 		 */
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	}
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	mutex_init(&sbbcsoftp->umutex, NULL, MUTEX_DRIVER, (void *)NULL);
423*7c478bd9Sstevel@tonic-gate 	mutex_init(&sbbcsoftp->sbbc_intr_mutex, NULL,
424*7c478bd9Sstevel@tonic-gate 	    MUTEX_DRIVER, (void *)NULL);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	/* initialize sbbc */
427*7c478bd9Sstevel@tonic-gate 	if (!sbbc_init(sbbcsoftp)) {
428*7c478bd9Sstevel@tonic-gate 		goto remlock;
429*7c478bd9Sstevel@tonic-gate 	}
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "sbbc%d", instance);
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL,
434*7c478bd9Sstevel@tonic-gate 	    NULL) == DDI_FAILURE) {
435*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
436*7c478bd9Sstevel@tonic-gate 		goto remlock;
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attached successfully\n");
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate remlock:
446*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->sbbc_intr_mutex);
447*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->umutex);
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate failed:
450*7c478bd9Sstevel@tonic-gate 	sbbc_remove_reg_maps(sbbcsoftp);
451*7c478bd9Sstevel@tonic-gate 	kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
452*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(sbbcsoft_statep, instance);
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attach failed\n");
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
457*7c478bd9Sstevel@tonic-gate }
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate static int
460*7c478bd9Sstevel@tonic-gate sbbc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
461*7c478bd9Sstevel@tonic-gate {
462*7c478bd9Sstevel@tonic-gate 	int		instance;
463*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_detach, 'DETA', dip);
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
470*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
471*7c478bd9Sstevel@tonic-gate 		break;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
474*7c478bd9Sstevel@tonic-gate 		if (!(sbbcsoftp =
475*7c478bd9Sstevel@tonic-gate 		    ddi_get_soft_state(sbbcsoft_statep, instance))) {
476*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
477*7c478bd9Sstevel@tonic-gate 			    "sbbc_detach: unable to get softstate %p",
478*7c478bd9Sstevel@tonic-gate 			    (void *)sbbcsoftp);
479*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
480*7c478bd9Sstevel@tonic-gate 		}
481*7c478bd9Sstevel@tonic-gate 		mutex_enter(&sbbcsoftp->umutex);
482*7c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->suspended) {
483*7c478bd9Sstevel@tonic-gate 		    mutex_exit(&sbbcsoftp->umutex);
484*7c478bd9Sstevel@tonic-gate 		    return (DDI_FAILURE);
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 		sbbcsoftp->suspended = 1;
487*7c478bd9Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
488*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	default:
491*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
492*7c478bd9Sstevel@tonic-gate 	}
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance))) {
495*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc_detach: unable to get softstate %p",
496*7c478bd9Sstevel@tonic-gate 		    (void *)sbbcsoftp);
497*7c478bd9Sstevel@tonic-gate 	    return (DDI_FAILURE);
498*7c478bd9Sstevel@tonic-gate 	}
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->sbbc_intr_mutex);
503*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->umutex);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	sbbc_remove_reg_maps(sbbcsoftp);
506*7c478bd9Sstevel@tonic-gate 	kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(sbbcsoft_statep, instance);
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate }
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate /*
516*7c478bd9Sstevel@tonic-gate  * Translate child's address into parents.
517*7c478bd9Sstevel@tonic-gate  */
518*7c478bd9Sstevel@tonic-gate static int
519*7c478bd9Sstevel@tonic-gate sbbc_busmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
520*7c478bd9Sstevel@tonic-gate 	    off_t off, off_t len, caddr_t *addrp)
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
523*7c478bd9Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp, *child_regs;
524*7c478bd9Sstevel@tonic-gate 	pci_regspec_t pci_reg;
525*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
526*7c478bd9Sstevel@tonic-gate 	int rnumber, i, n;
527*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
528*7c478bd9Sstevel@tonic-gate 	int instance;
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	SBBC_DBG4(SBBC_DBG_BUSMAP, dip,
531*7c478bd9Sstevel@tonic-gate 	    "mapping child %s, type %llx, off %llx, len %llx\n",
532*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), mp->map_type, off, len);
533*7c478bd9Sstevel@tonic-gate 
534*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_busmap, 'BMAP', mp);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	/*
537*7c478bd9Sstevel@tonic-gate 	 * Handle the mapping according to its type.
538*7c478bd9Sstevel@tonic-gate 	 */
539*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
540*7c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
541*7c478bd9Sstevel@tonic-gate 	    return (DDI_FAILURE);
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
544*7c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		/*
547*7c478bd9Sstevel@tonic-gate 		 * We assume the register specification is in sbbc format.
548*7c478bd9Sstevel@tonic-gate 		 * We must convert it into a PCI format regspec and pass
549*7c478bd9Sstevel@tonic-gate 		 * the request to our parent.
550*7c478bd9Sstevel@tonic-gate 		 */
551*7c478bd9Sstevel@tonic-gate 		child_rp = (sbbc_child_regspec_t *)mp->map_obj.rp;
552*7c478bd9Sstevel@tonic-gate 		break;
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 		/*
557*7c478bd9Sstevel@tonic-gate 		 * map_type 0
558*7c478bd9Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
559*7c478bd9Sstevel@tonic-gate 		 * it to our parent's format.
560*7c478bd9Sstevel@tonic-gate 		 */
561*7c478bd9Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 		/* get the requester's reg property */
564*7c478bd9Sstevel@tonic-gate 		if (ddi_getlongprop(DDI_DEV_T_NONE, rdip, DDI_PROP_DONTPASS,
565*7c478bd9Sstevel@tonic-gate 		    "reg", (caddr_t)&child_regs, &i) != DDI_SUCCESS) {
566*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
567*7c478bd9Sstevel@tonic-gate 			    "SBBC: couldn't get %s ranges property %d",
568*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(sbbcsoftp->dip), instance);
569*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
570*7c478bd9Sstevel@tonic-gate 		}
571*7c478bd9Sstevel@tonic-gate 		n = i / sizeof (sbbc_child_regspec_t);
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 		if (rnumber < 0 || rnumber >= n) {
574*7c478bd9Sstevel@tonic-gate 			kmem_free(child_regs, i);
575*7c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
576*7c478bd9Sstevel@tonic-gate 		}
577*7c478bd9Sstevel@tonic-gate 		child_rp = &child_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 	child_rp->addr_low += off;
587*7c478bd9Sstevel@tonic-gate 
588*7c478bd9Sstevel@tonic-gate 	if (len)
589*7c478bd9Sstevel@tonic-gate 		child_rp->size = len;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	/*
592*7c478bd9Sstevel@tonic-gate 	 * Combine this reg prop. into our parents PCI address using the ranges
593*7c478bd9Sstevel@tonic-gate 	 * property.
594*7c478bd9Sstevel@tonic-gate 	 */
595*7c478bd9Sstevel@tonic-gate 	rval = sbbc_apply_range(sbbcsoftp, rdip, child_rp, &pci_reg);
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
598*7c478bd9Sstevel@tonic-gate 		kmem_free(child_regs, i);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS)
601*7c478bd9Sstevel@tonic-gate 		return (rval);
602*7c478bd9Sstevel@tonic-gate 
603*7c478bd9Sstevel@tonic-gate 	p_map_request = *mp;
604*7c478bd9Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
605*7c478bd9Sstevel@tonic-gate 	p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	/* Send it to PCI nexus to map into the PCI space */
608*7c478bd9Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	return (rval);
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate }
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate /* new intr_ops structure */
616*7c478bd9Sstevel@tonic-gate static int
617*7c478bd9Sstevel@tonic-gate sbbc_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
618*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
619*7c478bd9Sstevel@tonic-gate {
620*7c478bd9Sstevel@tonic-gate 	ddi_ispec_t	*ip = (ddi_ispec_t *)hdlp->ih_private;
621*7c478bd9Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 	switch (intr_op) {
624*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
625*7c478bd9Sstevel@tonic-gate 		*(int *)result = 0;
626*7c478bd9Sstevel@tonic-gate 		break;
627*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
628*7c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
629*7c478bd9Sstevel@tonic-gate 		break;
630*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
631*7c478bd9Sstevel@tonic-gate 		break;
632*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
633*7c478bd9Sstevel@tonic-gate 		if (ip->is_pil == 0) {
634*7c478bd9Sstevel@tonic-gate 			ip->is_pil = 0x1;
635*7c478bd9Sstevel@tonic-gate 
636*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d assigning default interrupt "
637*7c478bd9Sstevel@tonic-gate 			    "level %d for device %s%d", ddi_get_name(dip),
638*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(dip), ip->is_pil,
639*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(rdip), ddi_get_instance(rdip));
640*7c478bd9Sstevel@tonic-gate 		}
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 		*(int *)result = ip->is_pil;
643*7c478bd9Sstevel@tonic-gate 		break;
644*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
645*7c478bd9Sstevel@tonic-gate 		ret = sbbc_add_intr_impl(dip, rdip, intr_op, hdlp, result);
646*7c478bd9Sstevel@tonic-gate 		break;
647*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
648*7c478bd9Sstevel@tonic-gate 		ret = sbbc_remove_intr_impl(dip, rdip, intr_op, hdlp, result);
649*7c478bd9Sstevel@tonic-gate 		break;
650*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
651*7c478bd9Sstevel@tonic-gate 		ret = sbbc_update_intr_state(dip, rdip, intr_op, hdlp, &result);
652*7c478bd9Sstevel@tonic-gate 		break;
653*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
654*7c478bd9Sstevel@tonic-gate 		ret = sbbc_update_intr_state(dip, rdip, intr_op, hdlp, &result);
655*7c478bd9Sstevel@tonic-gate 		break;
656*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
657*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
658*7c478bd9Sstevel@tonic-gate 		*(int *)result = i_ddi_get_nintrs(rdip);
659*7c478bd9Sstevel@tonic-gate 		break;
660*7c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
661*7c478bd9Sstevel@tonic-gate 		/* PCI nexus driver supports only fixed interrupts */
662*7c478bd9Sstevel@tonic-gate 		*(int *)result = i_ddi_get_nintrs(rdip) ?
663*7c478bd9Sstevel@tonic-gate 		    DDI_INTR_TYPE_FIXED : 0;
664*7c478bd9Sstevel@tonic-gate 		break;
665*7c478bd9Sstevel@tonic-gate 	default:
666*7c478bd9Sstevel@tonic-gate 		ret = DDI_ENOTSUP;
667*7c478bd9Sstevel@tonic-gate 		break;
668*7c478bd9Sstevel@tonic-gate 	}
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	return (ret);
671*7c478bd9Sstevel@tonic-gate }
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate static int
675*7c478bd9Sstevel@tonic-gate sbbc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
676*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
677*7c478bd9Sstevel@tonic-gate {
678*7c478bd9Sstevel@tonic-gate 	sbbcsoft_t *sbbcsoftp;
679*7c478bd9Sstevel@tonic-gate 	sbbc_child_intr_t *childintr;
680*7c478bd9Sstevel@tonic-gate 	int instance, i, rval = DDI_SUCCESS;
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip,
683*7c478bd9Sstevel@tonic-gate 	    "add: rdip 0x%llx hdlp 0x%llx\n", rdip, hdlp);
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	/* insert the sbbc isr wrapper instead */
686*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
687*7c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
688*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 	childintr = kmem_zalloc(sizeof (struct sbbc_child_intr), KM_SLEEP);
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 	childintr->name = ddi_get_name(rdip);
693*7c478bd9Sstevel@tonic-gate 	childintr->inum = hdlp->ih_inum;
694*7c478bd9Sstevel@tonic-gate 	childintr->intr_handler = hdlp->ih_cb_func;
695*7c478bd9Sstevel@tonic-gate 	childintr->arg1 = hdlp->ih_cb_arg1;
696*7c478bd9Sstevel@tonic-gate 	childintr->arg2 = hdlp->ih_cb_arg2;
697*7c478bd9Sstevel@tonic-gate 	childintr->status = SBBC_INTR_STATE_DISABLE;
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
700*7c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i] == 0) {
701*7c478bd9Sstevel@tonic-gate 			sbbcsoftp->child_intr[i] = childintr;
702*7c478bd9Sstevel@tonic-gate 			break;
703*7c478bd9Sstevel@tonic-gate 		}
704*7c478bd9Sstevel@tonic-gate 	}
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
707*7c478bd9Sstevel@tonic-gate 	    (ddi_intr_handler_t *)sbbc_intr_wrapper,
708*7c478bd9Sstevel@tonic-gate 	    (caddr_t)sbbcsoftp, NULL);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	if ((rval = i_ddi_intr_ops(dip, rdip, intr_op,
711*7c478bd9Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
712*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to add intr for %s",
713*7c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
714*7c478bd9Sstevel@tonic-gate 		kmem_free(childintr, sizeof (struct sbbc_child_intr));
715*7c478bd9Sstevel@tonic-gate 		sbbcsoftp->child_intr[i] = NULL;
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	/*
719*7c478bd9Sstevel@tonic-gate 	 * Restore original interrupt handler
720*7c478bd9Sstevel@tonic-gate 	 * and arguments in interrupt handle.
721*7c478bd9Sstevel@tonic-gate 	 */
722*7c478bd9Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, childintr->intr_handler,
723*7c478bd9Sstevel@tonic-gate 	    childintr->arg1, childintr->arg2);
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 	return (rval);
726*7c478bd9Sstevel@tonic-gate }
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate static int
729*7c478bd9Sstevel@tonic-gate sbbc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
730*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
731*7c478bd9Sstevel@tonic-gate {
732*7c478bd9Sstevel@tonic-gate 	sbbcsoft_t *sbbcsoftp;
733*7c478bd9Sstevel@tonic-gate 	sbbc_child_intr_t *childintr;
734*7c478bd9Sstevel@tonic-gate 	int instance, i, rval = DDI_SUCCESS;
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip,
737*7c478bd9Sstevel@tonic-gate 	    "remove: rdip 0x%llx hdlp 0x%llx\n", rdip, hdlp);
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
740*7c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
741*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	/* remove the sbbc isr wrapper instead */
744*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
745*7c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i]) {
746*7c478bd9Sstevel@tonic-gate 			childintr = sbbcsoftp->child_intr[i];
747*7c478bd9Sstevel@tonic-gate 			if (childintr->status == SBBC_INTR_STATE_DISABLE &&
748*7c478bd9Sstevel@tonic-gate 			    childintr->name == ddi_get_name(rdip)) {
749*7c478bd9Sstevel@tonic-gate 				/* put back child's inum */
750*7c478bd9Sstevel@tonic-gate 				hdlp->ih_inum = childintr->inum;
751*7c478bd9Sstevel@tonic-gate 				break;
752*7c478bd9Sstevel@tonic-gate 			}
753*7c478bd9Sstevel@tonic-gate 		}
754*7c478bd9Sstevel@tonic-gate 	}
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 	if (i >= MAX_SBBC_DEVICES) {
757*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d:obound failed to remove intr for %s",
758*7c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
759*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
760*7c478bd9Sstevel@tonic-gate 	}
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate 	if ((rval = i_ddi_intr_ops(dip, rdip, intr_op,
763*7c478bd9Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
764*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to remove intr for %s",
765*7c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
766*7c478bd9Sstevel@tonic-gate 		return (rval);
767*7c478bd9Sstevel@tonic-gate 	}
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	kmem_free(childintr, sizeof (struct sbbc_child_intr));
770*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->child_intr[i] = NULL;
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	return (rval);
773*7c478bd9Sstevel@tonic-gate }
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate static int
777*7c478bd9Sstevel@tonic-gate sbbc_update_intr_state(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
778*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
779*7c478bd9Sstevel@tonic-gate {
780*7c478bd9Sstevel@tonic-gate 	sbbcsoft_t		*sbbcsoftp;
781*7c478bd9Sstevel@tonic-gate 	sbbc_child_intr_t	*childintr;
782*7c478bd9Sstevel@tonic-gate 	int			instance, i;
783*7c478bd9Sstevel@tonic-gate 	int			ret = DDI_SUCCESS;
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip, "sbbc_update_intr_state: "
786*7c478bd9Sstevel@tonic-gate 	    "rdip 0x%llx hdlp 0x%llx state 0x%x\n", rdip, hdlp);
787*7c478bd9Sstevel@tonic-gate 
788*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
789*7c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
790*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
793*7c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i]) {
794*7c478bd9Sstevel@tonic-gate 			childintr = sbbcsoftp->child_intr[i];
795*7c478bd9Sstevel@tonic-gate 			if (childintr->name == ddi_get_name(rdip))
796*7c478bd9Sstevel@tonic-gate 				break;
797*7c478bd9Sstevel@tonic-gate 		}
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	if (i >= MAX_SBBC_DEVICES) {
801*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to update intr state for %s",
802*7c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
803*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
804*7c478bd9Sstevel@tonic-gate 	}
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_intr_ops(dip, rdip, intr_op,
807*7c478bd9Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
808*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to update intr state for %s",
809*7c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
810*7c478bd9Sstevel@tonic-gate 		return (ret);
811*7c478bd9Sstevel@tonic-gate 	}
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 	/* Update the interrupt state */
814*7c478bd9Sstevel@tonic-gate 	childintr->status = (intr_op == DDI_INTROP_ENABLE) ?
815*7c478bd9Sstevel@tonic-gate 	    SBBC_INTR_STATE_ENABLE : SBBC_INTR_STATE_DISABLE;
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 	return (ret);
818*7c478bd9Sstevel@tonic-gate }
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate /*
822*7c478bd9Sstevel@tonic-gate  * This entry point is called before a child's probe or attach is called.
823*7c478bd9Sstevel@tonic-gate  * The arg pointer points to child's dev_info_t structure.
824*7c478bd9Sstevel@tonic-gate  */
825*7c478bd9Sstevel@tonic-gate static int
826*7c478bd9Sstevel@tonic-gate sbbc_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
827*7c478bd9Sstevel@tonic-gate 	    void *arg, void *result)
828*7c478bd9Sstevel@tonic-gate {
829*7c478bd9Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp;
830*7c478bd9Sstevel@tonic-gate 	int i, n;
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	SBBC_DBG3(SBBC_DBG_CTLOPS, dip,
833*7c478bd9Sstevel@tonic-gate 	    "Initializing %s, arg %x, op %x\n",
834*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), arg, op);
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_ctlops, 'CTLO', arg);
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	switch (op) {
839*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
840*7c478bd9Sstevel@tonic-gate 		return (sbbc_initchild(dip, rdip, (dev_info_t *)arg));
841*7c478bd9Sstevel@tonic-gate 	}
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD: {
844*7c478bd9Sstevel@tonic-gate 		return (sbbc_uninitchild(rdip, (dev_info_t *)arg));
845*7c478bd9Sstevel@tonic-gate 	}
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
850*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(rdip), ddi_get_instance(rdip),
851*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
852*7c478bd9Sstevel@tonic-gate 		    ddi_get_name_addr(rdip));
853*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
856*7c478bd9Sstevel@tonic-gate 
857*7c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &child_rp, &i) != DDI_SUCCESS) {
858*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
859*7c478bd9Sstevel@tonic-gate 		}
860*7c478bd9Sstevel@tonic-gate 		n = i / sizeof (sbbc_child_regspec_t);
861*7c478bd9Sstevel@tonic-gate 		if (*(int *)arg < 0 || *(int *)arg >= n) {
862*7c478bd9Sstevel@tonic-gate 			kmem_free(child_rp, i);
863*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
864*7c478bd9Sstevel@tonic-gate 		}
865*7c478bd9Sstevel@tonic-gate 		*((off_t *)result) = child_rp[*(int *)arg].size;
866*7c478bd9Sstevel@tonic-gate 		kmem_free(child_rp, i);
867*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &child_rp, &i) != DDI_SUCCESS) {
872*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
873*7c478bd9Sstevel@tonic-gate 		}
874*7c478bd9Sstevel@tonic-gate 		*((uint_t *)result) = i / sizeof (sbbc_child_regspec_t);
875*7c478bd9Sstevel@tonic-gate 		kmem_free(child_rp, i);
876*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
877*7c478bd9Sstevel@tonic-gate 	}
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	/*
880*7c478bd9Sstevel@tonic-gate 	 * Now pass the request up to our parent.
881*7c478bd9Sstevel@tonic-gate 	 */
882*7c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_CTLOPS, dip, "Calling ddi_ctlops\n");
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
885*7c478bd9Sstevel@tonic-gate }
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate /*
889*7c478bd9Sstevel@tonic-gate  * The following routine uses ranges property, that was read earlier, and
890*7c478bd9Sstevel@tonic-gate  * takes child's reg property, and computes the complete address and size
891*7c478bd9Sstevel@tonic-gate  * for the PCI parent to map.
892*7c478bd9Sstevel@tonic-gate  */
893*7c478bd9Sstevel@tonic-gate static int
894*7c478bd9Sstevel@tonic-gate sbbc_apply_range(struct sbbcsoft *sbbc_p, dev_info_t *rdip,
895*7c478bd9Sstevel@tonic-gate     sbbc_child_regspec_t *child_rp, pci_regspec_t *rp)
896*7c478bd9Sstevel@tonic-gate {
897*7c478bd9Sstevel@tonic-gate 	int b;
898*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
899*7c478bd9Sstevel@tonic-gate 	struct sbbc_pci_rangespec *rangep = sbbc_p->rangep;
900*7c478bd9Sstevel@tonic-gate 	int nrange = sbbc_p->range_cnt;
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	SBBC_DBG4(SBBC_DBG_MAPRANGES, rdip,
903*7c478bd9Sstevel@tonic-gate 	    "Applying ranges for %s, rangep %llx, child_rp %llx, range %x\n",
904*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), sbbc_p->rangep, child_rp, nrange);
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_apply_range, 'APPL', sbbc_p);
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 		/* Make sure the correct range is being mapped */
911*7c478bd9Sstevel@tonic-gate 		if (child_rp->addr_hi == rangep->sbbc_phys_hi)
912*7c478bd9Sstevel@tonic-gate 			/* See if we fit in this range */
913*7c478bd9Sstevel@tonic-gate 			if ((child_rp->addr_low >=
914*7c478bd9Sstevel@tonic-gate 			    rangep->sbbc_phys_low) &&
915*7c478bd9Sstevel@tonic-gate 			    ((child_rp->addr_low + child_rp->size - 1)
916*7c478bd9Sstevel@tonic-gate 				<= (rangep->sbbc_phys_low +
917*7c478bd9Sstevel@tonic-gate 				    rangep->rng_size - 1))) {
918*7c478bd9Sstevel@tonic-gate 				uint_t addr_offset = child_rp->addr_low -
919*7c478bd9Sstevel@tonic-gate 				    rangep->sbbc_phys_low;
920*7c478bd9Sstevel@tonic-gate 				/*
921*7c478bd9Sstevel@tonic-gate 				 * Use the range entry to translate
922*7c478bd9Sstevel@tonic-gate 				 * the SBBC physical address into the
923*7c478bd9Sstevel@tonic-gate 				 * parents PCI space.
924*7c478bd9Sstevel@tonic-gate 				 */
925*7c478bd9Sstevel@tonic-gate 				rp->pci_phys_hi =
926*7c478bd9Sstevel@tonic-gate 				    rangep->pci_phys_hi;
927*7c478bd9Sstevel@tonic-gate 				rp->pci_phys_mid = rangep->pci_phys_mid;
928*7c478bd9Sstevel@tonic-gate 				rp->pci_phys_low =
929*7c478bd9Sstevel@tonic-gate 				    rangep->pci_phys_low + addr_offset;
930*7c478bd9Sstevel@tonic-gate 				rp->pci_size_hi = 0;
931*7c478bd9Sstevel@tonic-gate 				rp->pci_size_low =
932*7c478bd9Sstevel@tonic-gate 				    min(child_rp->size, (rangep->rng_size -
933*7c478bd9Sstevel@tonic-gate 					addr_offset));
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate 				break;
936*7c478bd9Sstevel@tonic-gate 			}
937*7c478bd9Sstevel@tonic-gate 	}
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	if (b == nrange)  {
940*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "out_of_range %s", ddi_get_name(rdip));
941*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
942*7c478bd9Sstevel@tonic-gate 	}
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	return (rval);
945*7c478bd9Sstevel@tonic-gate }
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 
948*7c478bd9Sstevel@tonic-gate /*
949*7c478bd9Sstevel@tonic-gate  * The following routine reads sbbc's ranges property from OBP and sets up
950*7c478bd9Sstevel@tonic-gate  * its soft structure with it.
951*7c478bd9Sstevel@tonic-gate  */
952*7c478bd9Sstevel@tonic-gate static int
953*7c478bd9Sstevel@tonic-gate sbbc_get_ranges(struct sbbcsoft *sbbcsoftp)
954*7c478bd9Sstevel@tonic-gate {
955*7c478bd9Sstevel@tonic-gate 	struct sbbc_pci_rangespec *rangep;
956*7c478bd9Sstevel@tonic-gate 	int range_len, nrange;
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, sbbcsoftp->dip, DDI_PROP_DONTPASS,
959*7c478bd9Sstevel@tonic-gate 	    "ranges", (caddr_t)&rangep, &range_len) != DDI_SUCCESS) {
960*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "SBBC: couldn't get %s ranges property %d",
961*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(sbbcsoftp->dip), sbbcsoftp->instance);
962*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
963*7c478bd9Sstevel@tonic-gate 	}
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 	nrange = range_len / sizeof (struct sbbc_pci_rangespec);
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	if (!nrange) {
968*7c478bd9Sstevel@tonic-gate 		kmem_free(rangep, range_len);
969*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
970*7c478bd9Sstevel@tonic-gate 	}
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	/* setup the soft structure with ranges info. */
973*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->rangep = rangep;
974*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->range_cnt = nrange;
975*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->range_len = range_len;
976*7c478bd9Sstevel@tonic-gate 
977*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
978*7c478bd9Sstevel@tonic-gate }
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate /*
982*7c478bd9Sstevel@tonic-gate  * Configure the SBBC for PCI
983*7c478bd9Sstevel@tonic-gate  */
984*7c478bd9Sstevel@tonic-gate static int
985*7c478bd9Sstevel@tonic-gate sbbc_config4pci(struct sbbcsoft *sbbcsoftp)
986*7c478bd9Sstevel@tonic-gate {
987*7c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t conf_handle;
988*7c478bd9Sstevel@tonic-gate 	uint16_t comm, vendid, devid, stat;
989*7c478bd9Sstevel@tonic-gate 	uint8_t revid;
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
992*7c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
993*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
994*7c478bd9Sstevel@tonic-gate 		    "sbbc_config4pci: sbbcsoftp %p\n", (void *)sbbcsoftp);
995*7c478bd9Sstevel@tonic-gate 	}
996*7c478bd9Sstevel@tonic-gate #endif
997*7c478bd9Sstevel@tonic-gate 	if (pci_config_setup(sbbcsoftp->dip, &conf_handle) != DDI_SUCCESS)
998*7c478bd9Sstevel@tonic-gate 		return (1);
999*7c478bd9Sstevel@tonic-gate 
1000*7c478bd9Sstevel@tonic-gate 	vendid = pci_config_get16(conf_handle, PCI_CONF_VENID);
1001*7c478bd9Sstevel@tonic-gate 	devid = pci_config_get16(conf_handle, PCI_CONF_DEVID);
1002*7c478bd9Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM);
1003*7c478bd9Sstevel@tonic-gate 	stat = pci_config_get16(conf_handle, PCI_CONF_STAT);
1004*7c478bd9Sstevel@tonic-gate 	revid = pci_config_get8(conf_handle, PCI_CONF_REVID);
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1007*7c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
1008*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
1009*7c478bd9Sstevel@tonic-gate 		    "SBBC vendid %x, devid %x, comm %x, stat %x, revid %x\n",
1010*7c478bd9Sstevel@tonic-gate 		    vendid, devid, comm, stat, revid);
1011*7c478bd9Sstevel@tonic-gate 	}
1012*7c478bd9Sstevel@tonic-gate #endif
1013*7c478bd9Sstevel@tonic-gate 	comm = (PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_SERR_ENABLE |
1014*7c478bd9Sstevel@tonic-gate 		    PCI_COMM_PARITY_DETECT);
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm);
1017*7c478bd9Sstevel@tonic-gate 
1018*7c478bd9Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM);
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1021*7c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
1022*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "comm %x\n", comm);
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate #endif
1025*7c478bd9Sstevel@tonic-gate 	pci_config_teardown(&conf_handle);
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 	return (0);
1028*7c478bd9Sstevel@tonic-gate }
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
1032*7c478bd9Sstevel@tonic-gate int
1033*7c478bd9Sstevel@tonic-gate sbbc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
1034*7c478bd9Sstevel@tonic-gate {
1035*7c478bd9Sstevel@tonic-gate 	dev_t	dev = (dev_t)arg;
1036*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
1037*7c478bd9Sstevel@tonic-gate 	int	instance, ret;
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate 	instance = getminor(dev);
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_getinfo, 'GINF', instance);
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
1044*7c478bd9Sstevel@tonic-gate 		case DDI_INFO_DEVT2DEVINFO:
1045*7c478bd9Sstevel@tonic-gate 			sbbcsoftp = (struct sbbcsoft *)
1046*7c478bd9Sstevel@tonic-gate 				ddi_get_soft_state(sbbcsoft_statep, instance);
1047*7c478bd9Sstevel@tonic-gate 			*result = sbbcsoftp->dip;
1048*7c478bd9Sstevel@tonic-gate 			ret = DDI_SUCCESS;
1049*7c478bd9Sstevel@tonic-gate 			break;
1050*7c478bd9Sstevel@tonic-gate 		case DDI_INFO_DEVT2INSTANCE:
1051*7c478bd9Sstevel@tonic-gate 			*result = (void *)instance;
1052*7c478bd9Sstevel@tonic-gate 			ret = DDI_SUCCESS;
1053*7c478bd9Sstevel@tonic-gate 			break;
1054*7c478bd9Sstevel@tonic-gate 		default:
1055*7c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
1056*7c478bd9Sstevel@tonic-gate 			break;
1057*7c478bd9Sstevel@tonic-gate 	}
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	return (ret);
1060*7c478bd9Sstevel@tonic-gate }
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
1063*7c478bd9Sstevel@tonic-gate static int
1064*7c478bd9Sstevel@tonic-gate sbbc_open(dev_t *dev, int flag, int otype, cred_t *credp)
1065*7c478bd9Sstevel@tonic-gate {
1066*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
1067*7c478bd9Sstevel@tonic-gate 	int		instance;
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	/* check privilege of caller process */
1070*7c478bd9Sstevel@tonic-gate 	if (drv_priv(credp)) {
1071*7c478bd9Sstevel@tonic-gate 		return (EPERM);
1072*7c478bd9Sstevel@tonic-gate 	}
1073*7c478bd9Sstevel@tonic-gate 
1074*7c478bd9Sstevel@tonic-gate 	instance = getminor(*dev);
1075*7c478bd9Sstevel@tonic-gate 	if (instance < 0)
1076*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1077*7c478bd9Sstevel@tonic-gate 	sbbcsoftp = (struct sbbcsoft *)ddi_get_soft_state(sbbcsoft_statep,
1078*7c478bd9Sstevel@tonic-gate 							    instance);
1079*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_open, 'OPEN', sbbcsoftp);
1080*7c478bd9Sstevel@tonic-gate 
1081*7c478bd9Sstevel@tonic-gate 	if (sbbcsoftp == NULL)
1082*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->umutex);
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	/* check for exclusive access */
1087*7c478bd9Sstevel@tonic-gate 	if ((sbbcsoftp->oflag == TRUE)) {
1088*7c478bd9Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
1089*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
1090*7c478bd9Sstevel@tonic-gate 	}
1091*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->oflag = TRUE;
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->umutex);
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	return (0);
1096*7c478bd9Sstevel@tonic-gate }
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
1099*7c478bd9Sstevel@tonic-gate static int
1100*7c478bd9Sstevel@tonic-gate sbbc_close(dev_t dev, int flag, int otype, cred_t *credp)
1101*7c478bd9Sstevel@tonic-gate {
1102*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
1103*7c478bd9Sstevel@tonic-gate 	int		instance;
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	instance = getminor(dev);
1106*7c478bd9Sstevel@tonic-gate 	if (instance < 0)
1107*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1108*7c478bd9Sstevel@tonic-gate 	sbbcsoftp = (struct sbbcsoft *)ddi_get_soft_state(sbbcsoft_statep,
1109*7c478bd9Sstevel@tonic-gate 							    instance);
1110*7c478bd9Sstevel@tonic-gate 	/* wait till all output activity has ceased */
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->umutex);
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_close, 'CLOS', sbbcsoftp);
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	sbbcsoftp->oflag = FALSE;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->umutex);
1119*7c478bd9Sstevel@tonic-gate 
1120*7c478bd9Sstevel@tonic-gate 	return (0);
1121*7c478bd9Sstevel@tonic-gate }
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
1124*7c478bd9Sstevel@tonic-gate static int
1125*7c478bd9Sstevel@tonic-gate sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1126*7c478bd9Sstevel@tonic-gate 		int *rvalp)
1127*7c478bd9Sstevel@tonic-gate {
1128*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_ioctl, 'IOCT', arg);
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, getminor(dev));
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 	if (sbbcsoftp == NULL) {
1135*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1136*7c478bd9Sstevel@tonic-gate 	}
1137*7c478bd9Sstevel@tonic-gate 
1138*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1139*7c478bd9Sstevel@tonic-gate 	case SBBC_SBBCREG_WR:
1140*7c478bd9Sstevel@tonic-gate 		{
1141*7c478bd9Sstevel@tonic-gate 		struct ssc_sbbc_regio sbbcregs;
1142*7c478bd9Sstevel@tonic-gate 		uint64_t offset;
1143*7c478bd9Sstevel@tonic-gate 
1144*7c478bd9Sstevel@tonic-gate 		if (arg == NULL) {
1145*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
1146*7c478bd9Sstevel@tonic-gate 		}
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&sbbcregs,
1149*7c478bd9Sstevel@tonic-gate 				    sizeof (struct ssc_sbbc_regio), mode)) {
1150*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl: copyin failed arg %p",
1151*7c478bd9Sstevel@tonic-gate 			    (void *)arg);
1152*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1153*7c478bd9Sstevel@tonic-gate 		}
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 		/*
1156*7c478bd9Sstevel@tonic-gate 		 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
1157*7c478bd9Sstevel@tonic-gate 		 *		reads or writes
1158*7c478bd9Sstevel@tonic-gate 		 * Note that I've also added a check to make sure the offset is
1159*7c478bd9Sstevel@tonic-gate 		 * valid, since misaligned (i.e. not on 16-byte boundary)
1160*7c478bd9Sstevel@tonic-gate 		 * accesses or accesses to "Reserved" register offsets are
1161*7c478bd9Sstevel@tonic-gate 		 * treated as unmapped by the SBBC.
1162*7c478bd9Sstevel@tonic-gate 		 */
1163*7c478bd9Sstevel@tonic-gate 		if ((sbbcregs.len != 4) ||
1164*7c478bd9Sstevel@tonic-gate 		    !sbbc_offset_valid(sbbcregs.offset)) {
1165*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1166*7c478bd9Sstevel@tonic-gate 		}
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 		offset = (uint64_t)&sbbcsoftp->pci_sbbc_map->sbbc_internal_regs;
1169*7c478bd9Sstevel@tonic-gate 		offset += sbbcregs.offset;
1170*7c478bd9Sstevel@tonic-gate 		ddi_put32(sbbcsoftp->pci_sbbc_map_handle, (uint32_t *)offset,
1171*7c478bd9Sstevel@tonic-gate 			    sbbcregs.value);
1172*7c478bd9Sstevel@tonic-gate 		}
1173*7c478bd9Sstevel@tonic-gate 		break;
1174*7c478bd9Sstevel@tonic-gate 	case SBBC_SBBCREG_RD:
1175*7c478bd9Sstevel@tonic-gate 		{
1176*7c478bd9Sstevel@tonic-gate 		struct ssc_sbbc_regio sbbcregs;
1177*7c478bd9Sstevel@tonic-gate 		uint64_t offset;
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 		if (arg == NULL) {
1180*7c478bd9Sstevel@tonic-gate 			return (ENXIO);
1181*7c478bd9Sstevel@tonic-gate 		}
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&sbbcregs,
1184*7c478bd9Sstevel@tonic-gate 				    sizeof (struct ssc_sbbc_regio), mode)) {
1185*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl: copyin failed arg %p",
1186*7c478bd9Sstevel@tonic-gate 			    (void *)arg);
1187*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1188*7c478bd9Sstevel@tonic-gate 		}
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate 		/*
1191*7c478bd9Sstevel@tonic-gate 		 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
1192*7c478bd9Sstevel@tonic-gate 		 *		reads or writes
1193*7c478bd9Sstevel@tonic-gate 		 * Note that I've also added a check to make sure the offset is
1194*7c478bd9Sstevel@tonic-gate 		 * valid, since misaligned (i.e. not on 16-byte boundary)
1195*7c478bd9Sstevel@tonic-gate 		 * accesses or accesses to "Reserved" register offsets are
1196*7c478bd9Sstevel@tonic-gate 		 * treated as unmapped by the SBBC.
1197*7c478bd9Sstevel@tonic-gate 		 */
1198*7c478bd9Sstevel@tonic-gate 		if ((sbbcregs.len != 4) ||
1199*7c478bd9Sstevel@tonic-gate 		    !sbbc_offset_valid(sbbcregs.offset)) {
1200*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
1201*7c478bd9Sstevel@tonic-gate 		}
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 		offset = (uint64_t)&sbbcsoftp->pci_sbbc_map->sbbc_internal_regs;
1204*7c478bd9Sstevel@tonic-gate 		offset += sbbcregs.offset;
1205*7c478bd9Sstevel@tonic-gate 
1206*7c478bd9Sstevel@tonic-gate 		sbbcregs.value = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
1207*7c478bd9Sstevel@tonic-gate 						    (uint32_t *)offset);
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&sbbcregs.value,
1210*7c478bd9Sstevel@tonic-gate 	    &((struct ssc_sbbc_regio *)arg)->value, sbbcregs.len, mode)) {
1211*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl:copyout failed arg %p",
1212*7c478bd9Sstevel@tonic-gate 			    (void *)arg);
1213*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1214*7c478bd9Sstevel@tonic-gate 		}
1215*7c478bd9Sstevel@tonic-gate 		}
1216*7c478bd9Sstevel@tonic-gate 		break;
1217*7c478bd9Sstevel@tonic-gate 	default:
1218*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc_ioctl:Illegal command 0x%08x", cmd);
1219*7c478bd9Sstevel@tonic-gate 		return (ENOTTY);
1220*7c478bd9Sstevel@tonic-gate 	}
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate static void
1226*7c478bd9Sstevel@tonic-gate sbbc_remove_reg_maps(struct sbbcsoft *sbbcsoftp)
1227*7c478bd9Sstevel@tonic-gate {
1228*7c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_remove_reg_maps, 'RMAP', sbbcsoftp);
1229*7c478bd9Sstevel@tonic-gate 	if (sbbcsoftp->pci_sbbc_map_handle)
1230*7c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&sbbcsoftp->pci_sbbc_map_handle);
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	/* need to unmap other registers as well */
1233*7c478bd9Sstevel@tonic-gate }
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate static int
1237*7c478bd9Sstevel@tonic-gate sbbc_init(struct sbbcsoft *sbbcsoftp)
1238*7c478bd9Sstevel@tonic-gate {
1239*7c478bd9Sstevel@tonic-gate 
1240*7c478bd9Sstevel@tonic-gate 	/*
1241*7c478bd9Sstevel@tonic-gate 	 * setup the regs. and mask all the interrupts
1242*7c478bd9Sstevel@tonic-gate 	 * till we are ready.
1243*7c478bd9Sstevel@tonic-gate 	 */
1244*7c478bd9Sstevel@tonic-gate 	ddi_put32(sbbcsoftp->pci_sbbc_map_handle,
1245*7c478bd9Sstevel@tonic-gate 	    &sbbcsoftp->pci_sbbc_map->sbbc_internal_regs.sys_intr_enable,
1246*7c478bd9Sstevel@tonic-gate 	    0x00000000);
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate 	return (1);
1249*7c478bd9Sstevel@tonic-gate }
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate /*
1252*7c478bd9Sstevel@tonic-gate  * The following routine is a generic routine to initialize any child of
1253*7c478bd9Sstevel@tonic-gate  * sbbc nexus driver information into parent private data structure.
1254*7c478bd9Sstevel@tonic-gate  */
1255*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
1256*7c478bd9Sstevel@tonic-gate static int
1257*7c478bd9Sstevel@tonic-gate sbbc_initchild(dev_info_t *dip, dev_info_t *rdip, dev_info_t *child)
1258*7c478bd9Sstevel@tonic-gate {
1259*7c478bd9Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp;
1260*7c478bd9Sstevel@tonic-gate 	int reglen, slot;
1261*7c478bd9Sstevel@tonic-gate 	char name[10];
1262*7c478bd9Sstevel@tonic-gate 
1263*7c478bd9Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_INITCHILD, dip, "Initializing %s\n",
1264*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip));
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	/*
1267*7c478bd9Sstevel@tonic-gate 	 * Initialize a child
1268*7c478bd9Sstevel@tonic-gate 	 * Set the address portion of the node name based on the
1269*7c478bd9Sstevel@tonic-gate 	 * address/offset.
1270*7c478bd9Sstevel@tonic-gate 	 */
1271*7c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_NONE, child, DDI_PROP_DONTPASS,
1272*7c478bd9Sstevel@tonic-gate 	    "reg", (caddr_t)&child_rp, &reglen) != DDI_SUCCESS) {
1273*7c478bd9Sstevel@tonic-gate 		if (strcmp(ddi_node_name(child), "hotplug-controller") == 0) {
1274*7c478bd9Sstevel@tonic-gate 			slot = 1;
1275*7c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x", slot);
1276*7c478bd9Sstevel@tonic-gate 			ddi_set_name_addr(child, name);
1277*7c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
1278*7c478bd9Sstevel@tonic-gate 		}
1279*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1280*7c478bd9Sstevel@tonic-gate 	}
1281*7c478bd9Sstevel@tonic-gate 
1282*7c478bd9Sstevel@tonic-gate 	SBBC_DBG3(SBBC_DBG_INITCHILD, dip, "hi 0x%x, low 0x%x, size 0x%x\n",
1283*7c478bd9Sstevel@tonic-gate 	    child_rp->addr_hi, child_rp->addr_low, child_rp->size);
1284*7c478bd9Sstevel@tonic-gate 
1285*7c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%x,%x", child_rp->addr_hi, child_rp->addr_low);
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 	/*
1288*7c478bd9Sstevel@tonic-gate 	 * set child's addresses from the reg property into parent private
1289*7c478bd9Sstevel@tonic-gate 	 * data structure.
1290*7c478bd9Sstevel@tonic-gate 	 */
1291*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
1292*7c478bd9Sstevel@tonic-gate 	kmem_free(child_rp, reglen);
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	ddi_set_parent_data(child, NULL);
1295*7c478bd9Sstevel@tonic-gate 
1296*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1297*7c478bd9Sstevel@tonic-gate }
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
1301*7c478bd9Sstevel@tonic-gate static int
1302*7c478bd9Sstevel@tonic-gate sbbc_uninitchild(dev_info_t *rdip, dev_info_t *child)
1303*7c478bd9Sstevel@tonic-gate {
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_UNINITCHILD, rdip, "Uninitializing %s\n",
1306*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip));
1307*7c478bd9Sstevel@tonic-gate 
1308*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
1309*7c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(child, NULL);
1310*7c478bd9Sstevel@tonic-gate 	impl_rem_dev_props(child);
1311*7c478bd9Sstevel@tonic-gate 
1312*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate }
1315*7c478bd9Sstevel@tonic-gate 
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate /*
1318*7c478bd9Sstevel@tonic-gate  * The following routine is an interrupt service routine that is used
1319*7c478bd9Sstevel@tonic-gate  * as a wrapper to all the children requiring interrupt services.
1320*7c478bd9Sstevel@tonic-gate  */
1321*7c478bd9Sstevel@tonic-gate static uint_t
1322*7c478bd9Sstevel@tonic-gate sbbc_intr_wrapper(caddr_t arg)
1323*7c478bd9Sstevel@tonic-gate {
1324*7c478bd9Sstevel@tonic-gate 
1325*7c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp = (struct sbbcsoft *)arg;
1326*7c478bd9Sstevel@tonic-gate 	int i, rval;
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_INTR, sbbcsoftp->dip, "Isr arg 0x%llx\n", arg);
1329*7c478bd9Sstevel@tonic-gate 
1330*7c478bd9Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->sbbc_intr_mutex);
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
1333*7c478bd9Sstevel@tonic-gate 		/*
1334*7c478bd9Sstevel@tonic-gate 		 * Check the interrupt status reg. to determine the cause.
1335*7c478bd9Sstevel@tonic-gate 		 */
1336*7c478bd9Sstevel@tonic-gate 		/*
1337*7c478bd9Sstevel@tonic-gate 		 * Check the error status reg. to determine the cause.
1338*7c478bd9Sstevel@tonic-gate 		 */
1339*7c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i] &&
1340*7c478bd9Sstevel@tonic-gate 		    sbbcsoftp->child_intr[i]->status ==
1341*7c478bd9Sstevel@tonic-gate 		    SBBC_INTR_STATE_ENABLE) {
1342*7c478bd9Sstevel@tonic-gate 			/*
1343*7c478bd9Sstevel@tonic-gate 			 * Dispatch the children interrupt service routines and
1344*7c478bd9Sstevel@tonic-gate 			 * look for someone to claim.
1345*7c478bd9Sstevel@tonic-gate 			 */
1346*7c478bd9Sstevel@tonic-gate 			rval = sbbcsoftp->child_intr[i]->intr_handler(
1347*7c478bd9Sstevel@tonic-gate 			    sbbcsoftp->child_intr[i]->arg1,
1348*7c478bd9Sstevel@tonic-gate 			    sbbcsoftp->child_intr[i]->arg2);
1349*7c478bd9Sstevel@tonic-gate 
1350*7c478bd9Sstevel@tonic-gate 			if (rval == DDI_INTR_CLAIMED) {
1351*7c478bd9Sstevel@tonic-gate 				mutex_exit(&sbbcsoftp->sbbc_intr_mutex);
1352*7c478bd9Sstevel@tonic-gate 				return (rval);
1353*7c478bd9Sstevel@tonic-gate 			}
1354*7c478bd9Sstevel@tonic-gate 		}
1355*7c478bd9Sstevel@tonic-gate 	}
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->sbbc_intr_mutex);
1358*7c478bd9Sstevel@tonic-gate 
1359*7c478bd9Sstevel@tonic-gate 	/* for now do not claim since we know its not enabled */
1360*7c478bd9Sstevel@tonic-gate 	return (DDI_INTR_UNCLAIMED);
1361*7c478bd9Sstevel@tonic-gate }
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate /*
1365*7c478bd9Sstevel@tonic-gate  * This function checks an SBBC register offset to make sure that it is properly
1366*7c478bd9Sstevel@tonic-gate  * aligned (i.e. on a 16-byte boundary) and that it corresponds to an accessible
1367*7c478bd9Sstevel@tonic-gate  * register.  Since the SBBC treates accesses to unaligned or reserved addresses
1368*7c478bd9Sstevel@tonic-gate  * as unmapped, failing to check for these would leave a loophole that could be
1369*7c478bd9Sstevel@tonic-gate  * used to crash the system.
1370*7c478bd9Sstevel@tonic-gate  */
1371*7c478bd9Sstevel@tonic-gate static int
1372*7c478bd9Sstevel@tonic-gate sbbc_offset_valid(uint32_t offset) {
1373*7c478bd9Sstevel@tonic-gate 	/*
1374*7c478bd9Sstevel@tonic-gate 	 * Check for proper alignment first.
1375*7c478bd9Sstevel@tonic-gate 	 */
1376*7c478bd9Sstevel@tonic-gate 	if ((offset % 16) != 0) {
1377*7c478bd9Sstevel@tonic-gate 		return (0);
1378*7c478bd9Sstevel@tonic-gate 	}
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	/*
1381*7c478bd9Sstevel@tonic-gate 	 * Now start checking for the various reserved ranges.
1382*7c478bd9Sstevel@tonic-gate 	 * While sticking a bunch of constants in the code (rather than
1383*7c478bd9Sstevel@tonic-gate 	 * #define'd values) is usually best avoided, it would probably
1384*7c478bd9Sstevel@tonic-gate 	 * do more harm than good here.  These values were taken from the
1385*7c478bd9Sstevel@tonic-gate 	 * Serengeti Architecture Programmer's Reference Manual dated
1386*7c478bd9Sstevel@tonic-gate 	 * August 10, 1999, pages 2-99 through 2-103.  While there are
1387*7c478bd9Sstevel@tonic-gate 	 * various "clever" ways this check could be performed that would
1388*7c478bd9Sstevel@tonic-gate 	 * be slightly more efficient, arranging the code in this fashion
1389*7c478bd9Sstevel@tonic-gate 	 * should maximize maintainability.
1390*7c478bd9Sstevel@tonic-gate 	 */
1391*7c478bd9Sstevel@tonic-gate 	if (((offset >= 0x001a0) && (offset <= 0x001ff)) ||
1392*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x002a0) && (offset <= 0x002ff)) ||
1393*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x00350) && (offset <= 0x003ff)) ||
1394*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x00500) && (offset <= 0x00fff)) ||
1395*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x01160) && (offset <= 0x011ff)) ||
1396*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x01210) && (offset <= 0x017ff)) ||
1397*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x01810) && (offset <= 0x01fff)) ||
1398*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x02030) && (offset <= 0x022ff)) ||
1399*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x02340) && (offset <= 0x03fff)) ||
1400*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x04030) && (offset <= 0x05fff)) ||
1401*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x060a0) && (offset <= 0x060ff)) ||
1402*7c478bd9Sstevel@tonic-gate 	    (offset == 0x06120) ||
1403*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x06190) && (offset <= 0x061ff)) ||
1404*7c478bd9Sstevel@tonic-gate 	    ((offset >= 0x06230) && (offset <= 0x062f0)) ||
1405*7c478bd9Sstevel@tonic-gate 	    (offset > 0x06320)) {
1406*7c478bd9Sstevel@tonic-gate 		return (0);
1407*7c478bd9Sstevel@tonic-gate 	}
1408*7c478bd9Sstevel@tonic-gate 
1409*7c478bd9Sstevel@tonic-gate 	return (1);
1410*7c478bd9Sstevel@tonic-gate }
1411*7c478bd9Sstevel@tonic-gate 
1412*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1413*7c478bd9Sstevel@tonic-gate void
1414*7c478bd9Sstevel@tonic-gate sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt,
1415*7c478bd9Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
1416*7c478bd9Sstevel@tonic-gate {
1417*7c478bd9Sstevel@tonic-gate 	char *s = NULL;
1418*7c478bd9Sstevel@tonic-gate 
1419*7c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags && ((sbbc_dbg_flags & flag) == flag)) {
1420*7c478bd9Sstevel@tonic-gate 		switch (flag) {
1421*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_ATTACH:
1422*7c478bd9Sstevel@tonic-gate 			s = "attach";
1423*7c478bd9Sstevel@tonic-gate 			break;
1424*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_DETACH:
1425*7c478bd9Sstevel@tonic-gate 			s = "detach";
1426*7c478bd9Sstevel@tonic-gate 			break;
1427*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_CTLOPS:
1428*7c478bd9Sstevel@tonic-gate 			s = "ctlops";
1429*7c478bd9Sstevel@tonic-gate 			break;
1430*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_INITCHILD:
1431*7c478bd9Sstevel@tonic-gate 			s = "initchild";
1432*7c478bd9Sstevel@tonic-gate 			break;
1433*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_UNINITCHILD:
1434*7c478bd9Sstevel@tonic-gate 			s = "uninitchild";
1435*7c478bd9Sstevel@tonic-gate 			break;
1436*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_BUSMAP:
1437*7c478bd9Sstevel@tonic-gate 			s = "busmap";
1438*7c478bd9Sstevel@tonic-gate 			break;
1439*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_INTR:
1440*7c478bd9Sstevel@tonic-gate 			s = "intr";
1441*7c478bd9Sstevel@tonic-gate 			break;
1442*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_INTROPS:
1443*7c478bd9Sstevel@tonic-gate 			s = "intr_ops";
1444*7c478bd9Sstevel@tonic-gate 			break;
1445*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_PCICONF:
1446*7c478bd9Sstevel@tonic-gate 			s = "pciconfig";
1447*7c478bd9Sstevel@tonic-gate 			break;
1448*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_MAPRANGES:
1449*7c478bd9Sstevel@tonic-gate 			s = "mapranges";
1450*7c478bd9Sstevel@tonic-gate 			break;
1451*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_PROPERTIES:
1452*7c478bd9Sstevel@tonic-gate 			s = "properties";
1453*7c478bd9Sstevel@tonic-gate 			break;
1454*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_OPEN:
1455*7c478bd9Sstevel@tonic-gate 			s = "open";
1456*7c478bd9Sstevel@tonic-gate 			break;
1457*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_CLOSE:
1458*7c478bd9Sstevel@tonic-gate 			s = "close";
1459*7c478bd9Sstevel@tonic-gate 			break;
1460*7c478bd9Sstevel@tonic-gate 		case SBBC_DBG_IOCTL:
1461*7c478bd9Sstevel@tonic-gate 			s = "ioctl";
1462*7c478bd9Sstevel@tonic-gate 			break;
1463*7c478bd9Sstevel@tonic-gate 		default:
1464*7c478bd9Sstevel@tonic-gate 			s = "Unknown debug flag";
1465*7c478bd9Sstevel@tonic-gate 			break;
1466*7c478bd9Sstevel@tonic-gate 		}
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s_%s(%d): ", ddi_driver_name(dip), s,
1469*7c478bd9Sstevel@tonic-gate 			ddi_get_instance(dip));
1470*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
1471*7c478bd9Sstevel@tonic-gate 	}
1472*7c478bd9Sstevel@tonic-gate }
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1475