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