xref: /illumos-gate/usr/src/uts/sun4u/io/sbbc.c (revision 836be2fe)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b8dc8477Sarutz  * Common Development and Distribution License (the "License").
6b8dc8477Sarutz  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2219397407SSherry Moore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
28b8dc8477Sarutz  * Starcat PCI SBBC Nexus Driver.
29b8dc8477Sarutz  *
30b8dc8477Sarutz  * This source code's compiled binary runs on both a Starcat System
31b8dc8477Sarutz  * Controller (SSC) and a Starcat Domain.  One of the SBBC hardware
32b8dc8477Sarutz  * registers is read during attach(9e) in order to determine which
33b8dc8477Sarutz  * environment the driver is executing on.
34b8dc8477Sarutz  *
35b8dc8477Sarutz  * On both the SSC and the Domain, this driver provides nexus driver
36b8dc8477Sarutz  * services to its Device Tree children.  Note that the children in
37b8dc8477Sarutz  * each environment are not necessarily the same.
38b8dc8477Sarutz  *
39b8dc8477Sarutz  * This driver allows one concurrent open(2) of its associated device
40b8dc8477Sarutz  * (/dev/sbbc0).  The client uses the file descriptor to issue
41b8dc8477Sarutz  * ioctl(2)'s in order to read and write from the 2MB (PCI) space
42b8dc8477Sarutz  * reserved for "SBBC Internal Registers".  Among other things,
43b8dc8477Sarutz  * these registers consist of command/control/status registers for
44b8dc8477Sarutz  * devices such as Console Bus, I2C, EPLD, IOSRAM, and JTAG.  The 2MB
45b8dc8477Sarutz  * space is very sparse; EINVAL is returned if a reserved or unaligned
46b8dc8477Sarutz  * address is specified in the ioctl(2).
47b8dc8477Sarutz  *
48b8dc8477Sarutz  * Note that the 2MB region reserved for SBBC Internal Registers is
49b8dc8477Sarutz  * a subset of the 128MB of PCI address space addressable by the SBBC
50b8dc8477Sarutz  * ASIC.  Address space outside of the 2MB (such as the 64MB reserved
51b8dc8477Sarutz  * for the Console Bus) is not accessible via this driver.
52b8dc8477Sarutz  *
53b8dc8477Sarutz  * Also, note that the SBBC Internal Registers are only read and
54b8dc8477Sarutz  * written by the SSC; no process on the Domain accesses these
55b8dc8477Sarutz  * registers.  As a result, the registers are unmapped (when running
56b8dc8477Sarutz  * on the Domain) near the end of attach(9e) processing.  This conserves
57b8dc8477Sarutz  * kernel virtual address space resources (as one instance of the driver
58b8dc8477Sarutz  * is created for each Domain-side IO assembly).  (To be complete, only
59b8dc8477Sarutz  * one instance of the driver is created on the SSC).
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include <sys/types.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
657c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
667c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
677c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
687c478bd9Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
697c478bd9Sstevel@tonic-gate #include <sys/pci.h>
707c478bd9Sstevel@tonic-gate #include <sys/pci/pci_nexus.h>
717c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
727c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
737c478bd9Sstevel@tonic-gate #include <sys/param.h>
747c478bd9Sstevel@tonic-gate #include <sys/errno.h>
757c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
767c478bd9Sstevel@tonic-gate #include <sys/debug.h>
777c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
787c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
797c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
807c478bd9Sstevel@tonic-gate #include <sys/stat.h>
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #include <sys/sbbcreg.h>	/* hw description */
847c478bd9Sstevel@tonic-gate #include <sys/sbbcvar.h>	/* driver description */
857c478bd9Sstevel@tonic-gate #include <sys/sbbcio.h>		/* ioctl description */
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	getprop(dip, name, addr, intp)		\
88a3282898Scth 		ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
897c478bd9Sstevel@tonic-gate 				(name), (caddr_t)(addr), (intp))
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /* driver entry point fn definitions */
927c478bd9Sstevel@tonic-gate static int sbbc_open(dev_t *, int, int, cred_t *);
937c478bd9Sstevel@tonic-gate static int sbbc_close(dev_t, int, int, cred_t *);
947c478bd9Sstevel@tonic-gate static int sbbc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /* configuration entry point fn definitions */
977c478bd9Sstevel@tonic-gate static int sbbc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
987c478bd9Sstevel@tonic-gate static int sbbc_attach(dev_info_t *, ddi_attach_cmd_t);
997c478bd9Sstevel@tonic-gate static int sbbc_detach(dev_info_t *, ddi_detach_cmd_t);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* local utility routines */
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * NOTE - sbbc_offset_valid contains detailed address information taken from
1047c478bd9Sstevel@tonic-gate  * the Serengeti Architecture Programmer's Reference Manual.  If any
1057c478bd9Sstevel@tonic-gate  * changes are made to the SBBC registers, this routine may need to be
1067c478bd9Sstevel@tonic-gate  * updated.
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate static int sbbc_offset_valid(uint32_t offset);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * function prototypes for bus ops routines:
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate static int sbbc_busmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
1147c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *addrp);
1157c478bd9Sstevel@tonic-gate static int sbbc_ctlops(dev_info_t *dip, dev_info_t *rdip,
1167c478bd9Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static int sbbc_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1197c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1207c478bd9Sstevel@tonic-gate static int sbbc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1217c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1227c478bd9Sstevel@tonic-gate static int sbbc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1237c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1247c478bd9Sstevel@tonic-gate static int sbbc_update_intr_state(dev_info_t *dip, dev_info_t *rdip,
1257c478bd9Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static int sbbc_apply_range(struct sbbcsoft *sbbc_p, dev_info_t *rdip,
1287c478bd9Sstevel@tonic-gate     sbbc_child_regspec_t *child_rp, pci_regspec_t *rp);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate static int sbbc_init(struct sbbcsoft *);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static uint_t sbbc_intr_wrapper(caddr_t arg);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate static int sbbc_get_ranges(struct sbbcsoft *);
1357c478bd9Sstevel@tonic-gate static int sbbc_config4pci(struct sbbcsoft *);
1367c478bd9Sstevel@tonic-gate static int sbbc_initchild(dev_info_t *, dev_info_t *, dev_info_t *);
1377c478bd9Sstevel@tonic-gate static int sbbc_uninitchild(dev_info_t *, dev_info_t *);
1387c478bd9Sstevel@tonic-gate static void sbbc_remove_reg_maps(struct sbbcsoft *);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /* debugging functions */
1417c478bd9Sstevel@tonic-gate #ifdef DEBUG
1427c478bd9Sstevel@tonic-gate uint32_t sbbc_dbg_flags = 0x0;
1437c478bd9Sstevel@tonic-gate static void sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt,
1447c478bd9Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5);
145b8dc8477Sarutz static void sbbc_dump_devid(dev_info_t *, struct sbbcsoft *, int instance);
1467c478bd9Sstevel@tonic-gate #endif
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * For tracing, allocate space for the trace buffer
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate #if defined(SBBC_TRACE)
1527c478bd9Sstevel@tonic-gate struct sbbctrace sbbctrace_buffer[NSBBCTRACE+1];
1537c478bd9Sstevel@tonic-gate struct sbbctrace *sbbctrace_ptr;
1547c478bd9Sstevel@tonic-gate int sbbctrace_count;
1557c478bd9Sstevel@tonic-gate #endif
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate  * Local declarations and variables
1597c478bd9Sstevel@tonic-gate  */
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static void *sbbcsoft_statep;
162b8dc8477Sarutz 
163b8dc8477Sarutz /* Determines whether driver is executing on System Controller or Domain */
1647c478bd9Sstevel@tonic-gate int sbbc_scmode = FALSE;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * ops stuff.
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate static struct bus_ops sbbc_bus_ops = {
1707c478bd9Sstevel@tonic-gate 	BUSO_REV,
1717c478bd9Sstevel@tonic-gate 	sbbc_busmap,
1727c478bd9Sstevel@tonic-gate 	0,
1737c478bd9Sstevel@tonic-gate 	0,
1747c478bd9Sstevel@tonic-gate 	0,
175*836be2feSToomas Soome 	NULL,			/* (*bus_map_fault)() */
1767c478bd9Sstevel@tonic-gate 	ddi_no_dma_map,
1777c478bd9Sstevel@tonic-gate 	ddi_no_dma_allochdl,
178*836be2feSToomas Soome 	ddi_no_dma_freehdl,	/* (*bus_dma_freehdl)() */
179*836be2feSToomas Soome 	ddi_no_dma_bindhdl,	/* (*bus_dma_bindhdl)() */
180*836be2feSToomas Soome 	ddi_no_dma_unbindhdl,	/* (*bus_dma_unbindhdl)() */
181*836be2feSToomas Soome 	ddi_no_dma_flush,	/* (*bus_dma_flush)() */
182*836be2feSToomas Soome 	ddi_no_dma_win,		/* (*bus_dma_win)() */
183*836be2feSToomas Soome 	ddi_no_dma_mctl,	/* (*bus_dma_ctl)() */
1847c478bd9Sstevel@tonic-gate 	sbbc_ctlops,
1857c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,
1867c478bd9Sstevel@tonic-gate 	0,			/* (*bus_get_eventcookie)();	*/
1877c478bd9Sstevel@tonic-gate 	0,			/* (*bus_add_eventcall)();	*/
1887c478bd9Sstevel@tonic-gate 	0,			/* (*bus_remove_eventcall)();	*/
1897c478bd9Sstevel@tonic-gate 	0,			/* (*bus_post_event)();		*/
1907c478bd9Sstevel@tonic-gate 	0,			/* (*bus_intr_ctl)();	*/
1917c478bd9Sstevel@tonic-gate 	0,			/* (*bus_config)();	*/
1927c478bd9Sstevel@tonic-gate 	0,			/* (*bus_unconfig)();	*/
1937c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_init)();	*/
1947c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_fini)();	*/
1957c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_access_enter)();	*/
1967c478bd9Sstevel@tonic-gate 	0,			/* (*bus_fm_access_exit)();	*/
1977c478bd9Sstevel@tonic-gate 	0,			/* (*bus_power)();	*/
1987c478bd9Sstevel@tonic-gate 	sbbc_intr_ops		/* (*bus_intr_op)();	*/
1997c478bd9Sstevel@tonic-gate };
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate /*
2027c478bd9Sstevel@tonic-gate  * cb_ops
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate static struct cb_ops sbbc_cb_ops = {
2057c478bd9Sstevel@tonic-gate 	sbbc_open,		/* cb_open */
2067c478bd9Sstevel@tonic-gate 	sbbc_close,		/* cb_close */
2077c478bd9Sstevel@tonic-gate 	nodev,			/* cb_strategy */
2087c478bd9Sstevel@tonic-gate 	nodev,			/* cb_print */
2097c478bd9Sstevel@tonic-gate 	nodev,			/* cb_dump */
2107c478bd9Sstevel@tonic-gate 	nodev,			/* cb_read */
2117c478bd9Sstevel@tonic-gate 	nodev,			/* cb_write */
2127c478bd9Sstevel@tonic-gate 	sbbc_ioctl,		/* cb_ioctl */
2137c478bd9Sstevel@tonic-gate 	nodev,			/* cb_devmap */
2147c478bd9Sstevel@tonic-gate 	nodev,			/* cb_mmap */
2157c478bd9Sstevel@tonic-gate 	nodev,			/* cb_segmap */
2167c478bd9Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
2177c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
2187c478bd9Sstevel@tonic-gate 	NULL,			/* cb_stream */
2197c478bd9Sstevel@tonic-gate 	(int)(D_NEW | D_MP)	/* cb_flag */
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * Declare ops vectors for auto configuration.
2247c478bd9Sstevel@tonic-gate  */
2257c478bd9Sstevel@tonic-gate struct dev_ops  sbbc_ops = {
2267c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
2277c478bd9Sstevel@tonic-gate 	0,			/* devo_refcnt */
2287c478bd9Sstevel@tonic-gate 	sbbc_getinfo,		/* devo_getinfo */
2297c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_identify */
2307c478bd9Sstevel@tonic-gate 	nulldev,		/* devo_probe */
2317c478bd9Sstevel@tonic-gate 	sbbc_attach,		/* devo_attach */
2327c478bd9Sstevel@tonic-gate 	sbbc_detach,		/* devo_detach */
2337c478bd9Sstevel@tonic-gate 	nodev,			/* devo_reset */
2347c478bd9Sstevel@tonic-gate 	&sbbc_cb_ops,		/* devo_cb_ops */
2357c478bd9Sstevel@tonic-gate 	&sbbc_bus_ops,		/* devo_bus_ops */
23619397407SSherry Moore 	nulldev,			/* devo_power */
23719397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
2387c478bd9Sstevel@tonic-gate };
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate  * Loadable module support.
2427c478bd9Sstevel@tonic-gate  */
2437c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate static struct modldrv sbbcmodldrv = {
2467c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* type of module - driver */
24719397407SSherry Moore 	"PCI Sbbc Nexus Driver",
2487c478bd9Sstevel@tonic-gate 	&sbbc_ops,
2497c478bd9Sstevel@tonic-gate };
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate static struct modlinkage sbbcmodlinkage = {
2527c478bd9Sstevel@tonic-gate 	MODREV_1,
2537c478bd9Sstevel@tonic-gate 	&sbbcmodldrv,
2547c478bd9Sstevel@tonic-gate 	NULL
2557c478bd9Sstevel@tonic-gate };
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate int
_init(void)2587c478bd9Sstevel@tonic-gate _init(void)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	int    error;
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&sbbcsoft_statep,
26319397407SSherry Moore 	    sizeof (struct sbbcsoft), 1)) != 0)
2647c478bd9Sstevel@tonic-gate 		return (error);
2657c478bd9Sstevel@tonic-gate 	if ((error = mod_install(&sbbcmodlinkage)) != 0)
2667c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&sbbcsoft_statep);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	return (error);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate int
_fini(void)2727c478bd9Sstevel@tonic-gate _fini(void)
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate 	int    error;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	if ((error = mod_remove(&sbbcmodlinkage)) == 0)
2777c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&sbbcsoft_statep);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	return (error);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2837c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	return (mod_info(&sbbcmodlinkage, modinfop));
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate static int
sbbc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2897c478bd9Sstevel@tonic-gate sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate 	int	instance;
2927c478bd9Sstevel@tonic-gate 	char	name[32];
2937c478bd9Sstevel@tonic-gate 	struct	sbbcsoft *sbbcsoftp;
2947c478bd9Sstevel@tonic-gate 	struct ddi_device_acc_attr attr;
295b8dc8477Sarutz 	uint32_t sbbc_id_reg;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2987c478bd9Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2997c478bd9Sstevel@tonic-gate 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/* initialize tracing */
3027c478bd9Sstevel@tonic-gate 	SBBCTRACEINIT();
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attaching\n");
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
3077c478bd9Sstevel@tonic-gate 	switch (cmd) {
3087c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
3097c478bd9Sstevel@tonic-gate 		break;
3107c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
3117c478bd9Sstevel@tonic-gate 		if (!(sbbcsoftp =
3127c478bd9Sstevel@tonic-gate 		    ddi_get_soft_state(sbbcsoft_statep, instance))) {
313b8dc8477Sarutz 			cmn_err(CE_WARN, "sbbc_attach:resume: unable "
314b8dc8477Sarutz 			    "to acquire sbbcsoftp for instance %d",
3157c478bd9Sstevel@tonic-gate 			    instance);
3167c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3177c478bd9Sstevel@tonic-gate 		}
3187c478bd9Sstevel@tonic-gate 		mutex_enter(&sbbcsoftp->umutex);
3197c478bd9Sstevel@tonic-gate 		if (!sbbcsoftp->suspended) {
3207c478bd9Sstevel@tonic-gate 			mutex_exit(&sbbcsoftp->umutex);
3217c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 		sbbcsoftp->suspended = 0;
3247c478bd9Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
3257c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	default:
3287c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(sbbcsoft_statep, instance) != 0) {
332b8dc8477Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to allocate statep "
333b8dc8477Sarutz 		    "for instance %d", instance);
3347c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if (sbbcsoftp == NULL) {
340b8dc8477Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to acquire "
341b8dc8477Sarutz 		    "sbbcsoftp for instance %d", instance);
3427c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(sbbcsoft_statep, instance);
3437c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	sbbcsoftp->instance = instance;
3477c478bd9Sstevel@tonic-gate 	sbbcsoftp->dip = dip;
3487c478bd9Sstevel@tonic-gate 	sbbcsoftp->oflag = FALSE;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/*
3517c478bd9Sstevel@tonic-gate 	 * Read our ranges property from OBP to map children space.
3527c478bd9Sstevel@tonic-gate 	 * And setup the internal structure for a later use when
3537c478bd9Sstevel@tonic-gate 	 * a child gets initialized.
3547c478bd9Sstevel@tonic-gate 	 */
3557c478bd9Sstevel@tonic-gate 	if (sbbc_get_ranges(sbbcsoftp)) {
356b8dc8477Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to read sbbc "
357b8dc8477Sarutz 		    "ranges from OBP %d", instance);
358b8dc8477Sarutz 		ddi_soft_state_free(sbbcsoft_statep, instance);
3597c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (sbbc_config4pci(sbbcsoftp)) {
363b8dc8477Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to configure "
364b8dc8477Sarutz 		    "sbbc on PCI %d", instance);
365b8dc8477Sarutz 		kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
366b8dc8477Sarutz 		ddi_soft_state_free(sbbcsoft_statep, instance);
3677c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
370b8dc8477Sarutz 	mutex_init(&sbbcsoftp->umutex, NULL, MUTEX_DRIVER, (void *)NULL);
371b8dc8477Sarutz 	mutex_init(&sbbcsoftp->sbbc_intr_mutex, NULL,
372b8dc8477Sarutz 	    MUTEX_DRIVER, (void *)NULL);
3737c478bd9Sstevel@tonic-gate 
374b8dc8477Sarutz 	/* Map SBBC's Internal Registers */
3757c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&sbbcsoftp->pci_sbbc_map,
376b8dc8477Sarutz 	    offsetof(struct pci_sbbc, sbbc_internal_regs),
377b8dc8477Sarutz 	    sizeof (struct sbbc_regs_map), &attr,
378b8dc8477Sarutz 	    &sbbcsoftp->pci_sbbc_map_handle) != DDI_SUCCESS) {
3797c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "(%d):sbbc_attach failed to map sbbc_reg",
380b8dc8477Sarutz 		    instance);
3817c478bd9Sstevel@tonic-gate 		goto failed;
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
384b8dc8477Sarutz 	SBBC_DBG1(SBBC_DBG_ATTACH, dip, "Mapped sbbc at %lx\n",
385b8dc8477Sarutz 	    sbbcsoftp->pci_sbbc_map);
386b8dc8477Sarutz #ifdef DEBUG
387b8dc8477Sarutz 	sbbc_dump_devid(dip, sbbcsoftp, instance);
388b8dc8477Sarutz #endif
389b8dc8477Sarutz 	/*
390b8dc8477Sarutz 	 * Read a hardware register to determine if we are executing on
391b8dc8477Sarutz 	 * a Starcat System Controller or a Starcat Domain.
392b8dc8477Sarutz 	 */
3937c478bd9Sstevel@tonic-gate 	sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
394b8dc8477Sarutz 	    &sbbcsoftp->pci_sbbc_map->device_conf);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (sbbc_id_reg & SBBC_SC_MODE) {
3977c478bd9Sstevel@tonic-gate 		sbbc_scmode = TRUE;
398b8dc8477Sarutz 		SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d) nexus running "
399b8dc8477Sarutz 		    "in System Controller Mode.\n", instance);
4007c478bd9Sstevel@tonic-gate 
401b8dc8477Sarutz 		/* initialize SBBC ASIC */
402b8dc8477Sarutz 		if (!sbbc_init(sbbcsoftp)) {
403b8dc8477Sarutz 			goto failed;
404b8dc8477Sarutz 		}
4057c478bd9Sstevel@tonic-gate 	} else {
4067c478bd9Sstevel@tonic-gate 		sbbc_scmode = FALSE;
407b8dc8477Sarutz 		SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d) nexus "
408b8dc8477Sarutz 		    "running in Domain Mode.\n", instance);
409b8dc8477Sarutz 
410b8dc8477Sarutz 		/* initialize SBBC ASIC before we unmap registers */
411b8dc8477Sarutz 		if (!sbbc_init(sbbcsoftp)) {
412b8dc8477Sarutz 			goto failed;
413b8dc8477Sarutz 		}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 		/*
416b8dc8477Sarutz 		 * Access to SBBC registers is no longer needed.  Unmap
417b8dc8477Sarutz 		 * the registers to conserve kernel virtual address space.
4187c478bd9Sstevel@tonic-gate 		 */
419b8dc8477Sarutz 		SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d): unmap "
420b8dc8477Sarutz 		    "SBBC registers\n", instance);
421b8dc8477Sarutz 		sbbc_remove_reg_maps(sbbcsoftp);
422b8dc8477Sarutz 		sbbcsoftp->pci_sbbc_map = NULL;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "sbbc%d", instance);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL,
428*836be2feSToomas Soome 	    0) == DDI_FAILURE) {
4297c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
430b8dc8477Sarutz 		goto failed;
4317c478bd9Sstevel@tonic-gate 	}
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attached successfully\n");
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4387c478bd9Sstevel@tonic-gate 
439b8dc8477Sarutz failed:
4407c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->sbbc_intr_mutex);
4417c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->umutex);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	sbbc_remove_reg_maps(sbbcsoftp);
4447c478bd9Sstevel@tonic-gate 	kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
4457c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(sbbcsoft_statep, instance);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attach failed\n");
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate static int
sbbc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4537c478bd9Sstevel@tonic-gate sbbc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4547c478bd9Sstevel@tonic-gate {
4557c478bd9Sstevel@tonic-gate 	int		instance;
4567c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_detach, 'DETA', dip);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	switch (cmd) {
4637c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
4647c478bd9Sstevel@tonic-gate 		break;
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
4677c478bd9Sstevel@tonic-gate 		if (!(sbbcsoftp =
4687c478bd9Sstevel@tonic-gate 		    ddi_get_soft_state(sbbcsoft_statep, instance))) {
4697c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
4707c478bd9Sstevel@tonic-gate 			    "sbbc_detach: unable to get softstate %p",
4717c478bd9Sstevel@tonic-gate 			    (void *)sbbcsoftp);
4727c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 		mutex_enter(&sbbcsoftp->umutex);
4757c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->suspended) {
47619397407SSherry Moore 			mutex_exit(&sbbcsoftp->umutex);
47719397407SSherry Moore 			return (DDI_FAILURE);
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 		sbbcsoftp->suspended = 1;
4807c478bd9Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
4817c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	default:
4847c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance))) {
4887c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc_detach: unable to get softstate %p",
4897c478bd9Sstevel@tonic-gate 		    (void *)sbbcsoftp);
49019397407SSherry Moore 		return (DDI_FAILURE);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->sbbc_intr_mutex);
4967c478bd9Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->umutex);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	sbbc_remove_reg_maps(sbbcsoftp);
4997c478bd9Sstevel@tonic-gate 	kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(sbbcsoft_statep, instance);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate  * Translate child's address into parents.
5107c478bd9Sstevel@tonic-gate  */
5117c478bd9Sstevel@tonic-gate static int
sbbc_busmap(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t off,off_t len,caddr_t * addrp)5127c478bd9Sstevel@tonic-gate sbbc_busmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
513*836be2feSToomas Soome     off_t off, off_t len, caddr_t *addrp)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
5167c478bd9Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp, *child_regs;
5177c478bd9Sstevel@tonic-gate 	pci_regspec_t pci_reg;
5187c478bd9Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
5197c478bd9Sstevel@tonic-gate 	int rnumber, i, n;
5207c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
5217c478bd9Sstevel@tonic-gate 	int instance;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	SBBC_DBG4(SBBC_DBG_BUSMAP, dip,
5247c478bd9Sstevel@tonic-gate 	    "mapping child %s, type %llx, off %llx, len %llx\n",
5257c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), mp->map_type, off, len);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_busmap, 'BMAP', mp);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/*
5307c478bd9Sstevel@tonic-gate 	 * Handle the mapping according to its type.
5317c478bd9Sstevel@tonic-gate 	 */
5327c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
5337c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
53419397407SSherry Moore 		return (DDI_FAILURE);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	switch (mp->map_type) {
5377c478bd9Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		/*
5407c478bd9Sstevel@tonic-gate 		 * We assume the register specification is in sbbc format.
5417c478bd9Sstevel@tonic-gate 		 * We must convert it into a PCI format regspec and pass
5427c478bd9Sstevel@tonic-gate 		 * the request to our parent.
5437c478bd9Sstevel@tonic-gate 		 */
5447c478bd9Sstevel@tonic-gate 		child_rp = (sbbc_child_regspec_t *)mp->map_obj.rp;
5457c478bd9Sstevel@tonic-gate 		break;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 		/*
5507c478bd9Sstevel@tonic-gate 		 * map_type 0
5517c478bd9Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
5527c478bd9Sstevel@tonic-gate 		 * it to our parent's format.
5537c478bd9Sstevel@tonic-gate 		 */
5547c478bd9Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		/* get the requester's reg property */
557a3282898Scth 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
5587c478bd9Sstevel@tonic-gate 		    "reg", (caddr_t)&child_regs, &i) != DDI_SUCCESS) {
5597c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
5607c478bd9Sstevel@tonic-gate 			    "SBBC: couldn't get %s ranges property %d",
5617c478bd9Sstevel@tonic-gate 			    ddi_get_name(sbbcsoftp->dip), instance);
5627c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 		n = i / sizeof (sbbc_child_regspec_t);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 		if (rnumber < 0 || rnumber >= n) {
5677c478bd9Sstevel@tonic-gate 			kmem_free(child_regs, i);
5687c478bd9Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
5697c478bd9Sstevel@tonic-gate 		}
5707c478bd9Sstevel@tonic-gate 		child_rp = &child_regs[rnumber];
5717c478bd9Sstevel@tonic-gate 		break;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	default:
5747c478bd9Sstevel@tonic-gate 		return (DDI_ME_INVAL);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/* Adjust our reg property with offset and length */
5797c478bd9Sstevel@tonic-gate 	child_rp->addr_low += off;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if (len)
5827c478bd9Sstevel@tonic-gate 		child_rp->size = len;
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	/*
5857c478bd9Sstevel@tonic-gate 	 * Combine this reg prop. into our parents PCI address using the ranges
5867c478bd9Sstevel@tonic-gate 	 * property.
5877c478bd9Sstevel@tonic-gate 	 */
5887c478bd9Sstevel@tonic-gate 	rval = sbbc_apply_range(sbbcsoftp, rdip, child_rp, &pci_reg);
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
5917c478bd9Sstevel@tonic-gate 		kmem_free(child_regs, i);
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS)
5947c478bd9Sstevel@tonic-gate 		return (rval);
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	p_map_request = *mp;
5977c478bd9Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
5987c478bd9Sstevel@tonic-gate 	p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	/* Send it to PCI nexus to map into the PCI space */
6017c478bd9Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	return (rval);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate }
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate /* new intr_ops structure */
6097c478bd9Sstevel@tonic-gate static int
sbbc_intr_ops(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)6107c478bd9Sstevel@tonic-gate sbbc_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
6117c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
6127c478bd9Sstevel@tonic-gate {
613a195726fSgovinda 	int	ret = DDI_SUCCESS;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	switch (intr_op) {
6167c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
617a195726fSgovinda 		*(int *)result = DDI_INTR_FLAG_LEVEL;
6187c478bd9Sstevel@tonic-gate 		break;
6197c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
6207c478bd9Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
6217c478bd9Sstevel@tonic-gate 		break;
6227c478bd9Sstevel@tonic-gate 	case DDI_INTROP_FREE:
6237c478bd9Sstevel@tonic-gate 		break;
6247c478bd9Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
625a195726fSgovinda 		if (hdlp->ih_pri == 0) {
626a195726fSgovinda 			hdlp->ih_pri = 0x1;
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d assigning default interrupt "
629a195726fSgovinda 			    "level %d for device %s%d", ddi_driver_name(dip),
630a195726fSgovinda 			    ddi_get_instance(dip), hdlp->ih_pri,
631a195726fSgovinda 			    ddi_driver_name(rdip), ddi_get_instance(rdip));
6327c478bd9Sstevel@tonic-gate 		}
6337c478bd9Sstevel@tonic-gate 
634a195726fSgovinda 		*(int *)result = hdlp->ih_pri;
635a195726fSgovinda 
6367c478bd9Sstevel@tonic-gate 		break;
6377c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
6387c478bd9Sstevel@tonic-gate 		ret = sbbc_add_intr_impl(dip, rdip, intr_op, hdlp, result);
6397c478bd9Sstevel@tonic-gate 		break;
6407c478bd9Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
6417c478bd9Sstevel@tonic-gate 		ret = sbbc_remove_intr_impl(dip, rdip, intr_op, hdlp, result);
6427c478bd9Sstevel@tonic-gate 		break;
6437c478bd9Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
6447c478bd9Sstevel@tonic-gate 		ret = sbbc_update_intr_state(dip, rdip, intr_op, hdlp, &result);
6457c478bd9Sstevel@tonic-gate 		break;
6467c478bd9Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
6477c478bd9Sstevel@tonic-gate 		ret = sbbc_update_intr_state(dip, rdip, intr_op, hdlp, &result);
6487c478bd9Sstevel@tonic-gate 		break;
6497c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
6507c478bd9Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
651a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
6527c478bd9Sstevel@tonic-gate 		break;
6537c478bd9Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
6547c478bd9Sstevel@tonic-gate 		/* PCI nexus driver supports only fixed interrupts */
655a54f81fbSanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
6567c478bd9Sstevel@tonic-gate 		    DDI_INTR_TYPE_FIXED : 0;
6577c478bd9Sstevel@tonic-gate 		break;
6587c478bd9Sstevel@tonic-gate 	default:
6597c478bd9Sstevel@tonic-gate 		ret = DDI_ENOTSUP;
6607c478bd9Sstevel@tonic-gate 		break;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	return (ret);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate static int
sbbc_add_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)6687c478bd9Sstevel@tonic-gate sbbc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
6697c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	sbbcsoft_t *sbbcsoftp;
6727c478bd9Sstevel@tonic-gate 	sbbc_child_intr_t *childintr;
6737c478bd9Sstevel@tonic-gate 	int instance, i, rval = DDI_SUCCESS;
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip,
6767c478bd9Sstevel@tonic-gate 	    "add: rdip 0x%llx hdlp 0x%llx\n", rdip, hdlp);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	/* insert the sbbc isr wrapper instead */
6797c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
6807c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
6817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	childintr = kmem_zalloc(sizeof (struct sbbc_child_intr), KM_SLEEP);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	childintr->name = ddi_get_name(rdip);
6867c478bd9Sstevel@tonic-gate 	childintr->inum = hdlp->ih_inum;
6877c478bd9Sstevel@tonic-gate 	childintr->intr_handler = hdlp->ih_cb_func;
6887c478bd9Sstevel@tonic-gate 	childintr->arg1 = hdlp->ih_cb_arg1;
6897c478bd9Sstevel@tonic-gate 	childintr->arg2 = hdlp->ih_cb_arg2;
6907c478bd9Sstevel@tonic-gate 	childintr->status = SBBC_INTR_STATE_DISABLE;
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
693*836be2feSToomas Soome 		if (sbbcsoftp->child_intr[i] == NULL) {
6947c478bd9Sstevel@tonic-gate 			sbbcsoftp->child_intr[i] = childintr;
6957c478bd9Sstevel@tonic-gate 			break;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
7007c478bd9Sstevel@tonic-gate 	    (ddi_intr_handler_t *)sbbc_intr_wrapper,
7017c478bd9Sstevel@tonic-gate 	    (caddr_t)sbbcsoftp, NULL);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if ((rval = i_ddi_intr_ops(dip, rdip, intr_op,
7047c478bd9Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
7057c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to add intr for %s",
7067c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7077c478bd9Sstevel@tonic-gate 		kmem_free(childintr, sizeof (struct sbbc_child_intr));
708*836be2feSToomas Soome 		if (i < MAX_SBBC_DEVICES)
709*836be2feSToomas Soome 			sbbcsoftp->child_intr[i] = NULL;
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/*
7137c478bd9Sstevel@tonic-gate 	 * Restore original interrupt handler
7147c478bd9Sstevel@tonic-gate 	 * and arguments in interrupt handle.
7157c478bd9Sstevel@tonic-gate 	 */
7167c478bd9Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, childintr->intr_handler,
7177c478bd9Sstevel@tonic-gate 	    childintr->arg1, childintr->arg2);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	return (rval);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate static int
sbbc_remove_intr_impl(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)7237c478bd9Sstevel@tonic-gate sbbc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7247c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
7257c478bd9Sstevel@tonic-gate {
7267c478bd9Sstevel@tonic-gate 	sbbcsoft_t *sbbcsoftp;
7277c478bd9Sstevel@tonic-gate 	sbbc_child_intr_t *childintr;
7287c478bd9Sstevel@tonic-gate 	int instance, i, rval = DDI_SUCCESS;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip,
7317c478bd9Sstevel@tonic-gate 	    "remove: rdip 0x%llx hdlp 0x%llx\n", rdip, hdlp);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
7347c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
7357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	/* remove the sbbc isr wrapper instead */
7387c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
7397c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i]) {
7407c478bd9Sstevel@tonic-gate 			childintr = sbbcsoftp->child_intr[i];
7417c478bd9Sstevel@tonic-gate 			if (childintr->status == SBBC_INTR_STATE_DISABLE &&
7427c478bd9Sstevel@tonic-gate 			    childintr->name == ddi_get_name(rdip)) {
7437c478bd9Sstevel@tonic-gate 				/* put back child's inum */
7447c478bd9Sstevel@tonic-gate 				hdlp->ih_inum = childintr->inum;
7457c478bd9Sstevel@tonic-gate 				break;
7467c478bd9Sstevel@tonic-gate 			}
7477c478bd9Sstevel@tonic-gate 		}
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (i >= MAX_SBBC_DEVICES) {
7517c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d:obound failed to remove intr for %s",
7527c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7537c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	if ((rval = i_ddi_intr_ops(dip, rdip, intr_op,
7577c478bd9Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
7587c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to remove intr for %s",
7597c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7607c478bd9Sstevel@tonic-gate 		return (rval);
7617c478bd9Sstevel@tonic-gate 	}
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	kmem_free(childintr, sizeof (struct sbbc_child_intr));
7647c478bd9Sstevel@tonic-gate 	sbbcsoftp->child_intr[i] = NULL;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	return (rval);
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate static int
sbbc_update_intr_state(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)7717c478bd9Sstevel@tonic-gate sbbc_update_intr_state(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7727c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
7737c478bd9Sstevel@tonic-gate {
7747c478bd9Sstevel@tonic-gate 	sbbcsoft_t		*sbbcsoftp;
7757c478bd9Sstevel@tonic-gate 	sbbc_child_intr_t	*childintr;
7767c478bd9Sstevel@tonic-gate 	int			instance, i;
7777c478bd9Sstevel@tonic-gate 	int			ret = DDI_SUCCESS;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip, "sbbc_update_intr_state: "
7807c478bd9Sstevel@tonic-gate 	    "rdip 0x%llx hdlp 0x%llx state 0x%x\n", rdip, hdlp);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
7837c478bd9Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
7847c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
7877c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i]) {
7887c478bd9Sstevel@tonic-gate 			childintr = sbbcsoftp->child_intr[i];
7897c478bd9Sstevel@tonic-gate 			if (childintr->name == ddi_get_name(rdip))
7907c478bd9Sstevel@tonic-gate 				break;
7917c478bd9Sstevel@tonic-gate 		}
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (i >= MAX_SBBC_DEVICES) {
7957c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to update intr state for %s",
7967c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7977c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_intr_ops(dip, rdip, intr_op,
8017c478bd9Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
8027c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to update intr state for %s",
8037c478bd9Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
8047c478bd9Sstevel@tonic-gate 		return (ret);
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	/* Update the interrupt state */
8087c478bd9Sstevel@tonic-gate 	childintr->status = (intr_op == DDI_INTROP_ENABLE) ?
8097c478bd9Sstevel@tonic-gate 	    SBBC_INTR_STATE_ENABLE : SBBC_INTR_STATE_DISABLE;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	return (ret);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate /*
8167c478bd9Sstevel@tonic-gate  * This entry point is called before a child's probe or attach is called.
8177c478bd9Sstevel@tonic-gate  * The arg pointer points to child's dev_info_t structure.
8187c478bd9Sstevel@tonic-gate  */
8197c478bd9Sstevel@tonic-gate static int
sbbc_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)8207c478bd9Sstevel@tonic-gate sbbc_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
821*836be2feSToomas Soome     void *arg, void *result)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp;
8247c478bd9Sstevel@tonic-gate 	int i, n;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	SBBC_DBG3(SBBC_DBG_CTLOPS, dip,
8277c478bd9Sstevel@tonic-gate 	    "Initializing %s, arg %x, op %x\n",
8287c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), arg, op);
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_ctlops, 'CTLO', arg);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	switch (op) {
8337c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
8347c478bd9Sstevel@tonic-gate 		return (sbbc_initchild(dip, rdip, (dev_info_t *)arg));
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD: {
8387c478bd9Sstevel@tonic-gate 		return (sbbc_uninitchild(rdip, (dev_info_t *)arg));
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
8447c478bd9Sstevel@tonic-gate 		    ddi_driver_name(rdip), ddi_get_instance(rdip),
8457c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
8467c478bd9Sstevel@tonic-gate 		    ddi_get_name_addr(rdip));
8477c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &child_rp, &i) != DDI_SUCCESS) {
8527c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8537c478bd9Sstevel@tonic-gate 		}
8547c478bd9Sstevel@tonic-gate 		n = i / sizeof (sbbc_child_regspec_t);
8557c478bd9Sstevel@tonic-gate 		if (*(int *)arg < 0 || *(int *)arg >= n) {
8567c478bd9Sstevel@tonic-gate 			kmem_free(child_rp, i);
8577c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 		*((off_t *)result) = child_rp[*(int *)arg].size;
8607c478bd9Sstevel@tonic-gate 		kmem_free(child_rp, i);
8617c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 		if (getprop(rdip, "reg", &child_rp, &i) != DDI_SUCCESS) {
8667c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 		*((uint_t *)result) = i / sizeof (sbbc_child_regspec_t);
8697c478bd9Sstevel@tonic-gate 		kmem_free(child_rp, i);
8707c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/*
8747c478bd9Sstevel@tonic-gate 	 * Now pass the request up to our parent.
8757c478bd9Sstevel@tonic-gate 	 */
8767c478bd9Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_CTLOPS, dip, "Calling ddi_ctlops\n");
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
8797c478bd9Sstevel@tonic-gate }
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate  * The following routine uses ranges property, that was read earlier, and
8847c478bd9Sstevel@tonic-gate  * takes child's reg property, and computes the complete address and size
8857c478bd9Sstevel@tonic-gate  * for the PCI parent to map.
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate static int
sbbc_apply_range(struct sbbcsoft * sbbc_p,dev_info_t * rdip,sbbc_child_regspec_t * child_rp,pci_regspec_t * rp)8887c478bd9Sstevel@tonic-gate sbbc_apply_range(struct sbbcsoft *sbbc_p, dev_info_t *rdip,
8897c478bd9Sstevel@tonic-gate     sbbc_child_regspec_t *child_rp, pci_regspec_t *rp)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	int b;
8927c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
8937c478bd9Sstevel@tonic-gate 	struct sbbc_pci_rangespec *rangep = sbbc_p->rangep;
8947c478bd9Sstevel@tonic-gate 	int nrange = sbbc_p->range_cnt;
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	SBBC_DBG4(SBBC_DBG_MAPRANGES, rdip,
8977c478bd9Sstevel@tonic-gate 	    "Applying ranges for %s, rangep %llx, child_rp %llx, range %x\n",
8987c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip), sbbc_p->rangep, child_rp, nrange);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_apply_range, 'APPL', sbbc_p);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 		/* Make sure the correct range is being mapped */
9057c478bd9Sstevel@tonic-gate 		if (child_rp->addr_hi == rangep->sbbc_phys_hi)
9067c478bd9Sstevel@tonic-gate 			/* See if we fit in this range */
9077c478bd9Sstevel@tonic-gate 			if ((child_rp->addr_low >=
9087c478bd9Sstevel@tonic-gate 			    rangep->sbbc_phys_low) &&
9097c478bd9Sstevel@tonic-gate 			    ((child_rp->addr_low + child_rp->size - 1)
91019397407SSherry Moore 			    <= (rangep->sbbc_phys_low +
91119397407SSherry Moore 			    rangep->rng_size - 1))) {
9127c478bd9Sstevel@tonic-gate 				uint_t addr_offset = child_rp->addr_low -
9137c478bd9Sstevel@tonic-gate 				    rangep->sbbc_phys_low;
9147c478bd9Sstevel@tonic-gate 				/*
9157c478bd9Sstevel@tonic-gate 				 * Use the range entry to translate
9167c478bd9Sstevel@tonic-gate 				 * the SBBC physical address into the
9177c478bd9Sstevel@tonic-gate 				 * parents PCI space.
9187c478bd9Sstevel@tonic-gate 				 */
9197c478bd9Sstevel@tonic-gate 				rp->pci_phys_hi =
9207c478bd9Sstevel@tonic-gate 				    rangep->pci_phys_hi;
9217c478bd9Sstevel@tonic-gate 				rp->pci_phys_mid = rangep->pci_phys_mid;
9227c478bd9Sstevel@tonic-gate 				rp->pci_phys_low =
9237c478bd9Sstevel@tonic-gate 				    rangep->pci_phys_low + addr_offset;
9247c478bd9Sstevel@tonic-gate 				rp->pci_size_hi = 0;
9257c478bd9Sstevel@tonic-gate 				rp->pci_size_low =
9267c478bd9Sstevel@tonic-gate 				    min(child_rp->size, (rangep->rng_size -
92719397407SSherry Moore 				    addr_offset));
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 				break;
9307c478bd9Sstevel@tonic-gate 			}
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	if (b == nrange)  {
9347c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "out_of_range %s", ddi_get_name(rdip));
9357c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	return (rval);
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate /*
9437c478bd9Sstevel@tonic-gate  * The following routine reads sbbc's ranges property from OBP and sets up
9447c478bd9Sstevel@tonic-gate  * its soft structure with it.
9457c478bd9Sstevel@tonic-gate  */
9467c478bd9Sstevel@tonic-gate static int
sbbc_get_ranges(struct sbbcsoft * sbbcsoftp)9477c478bd9Sstevel@tonic-gate sbbc_get_ranges(struct sbbcsoft *sbbcsoftp)
9487c478bd9Sstevel@tonic-gate {
9497c478bd9Sstevel@tonic-gate 	struct sbbc_pci_rangespec *rangep;
9507c478bd9Sstevel@tonic-gate 	int range_len, nrange;
9517c478bd9Sstevel@tonic-gate 
952a3282898Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, sbbcsoftp->dip, DDI_PROP_DONTPASS,
9537c478bd9Sstevel@tonic-gate 	    "ranges", (caddr_t)&rangep, &range_len) != DDI_SUCCESS) {
9547c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "SBBC: couldn't get %s ranges property %d",
9557c478bd9Sstevel@tonic-gate 		    ddi_get_name(sbbcsoftp->dip), sbbcsoftp->instance);
9567c478bd9Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	nrange = range_len / sizeof (struct sbbc_pci_rangespec);
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 	if (!nrange) {
9627c478bd9Sstevel@tonic-gate 		kmem_free(rangep, range_len);
9637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9647c478bd9Sstevel@tonic-gate 	}
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/* setup the soft structure with ranges info. */
9677c478bd9Sstevel@tonic-gate 	sbbcsoftp->rangep = rangep;
9687c478bd9Sstevel@tonic-gate 	sbbcsoftp->range_cnt = nrange;
9697c478bd9Sstevel@tonic-gate 	sbbcsoftp->range_len = range_len;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate  * Configure the SBBC for PCI
9777c478bd9Sstevel@tonic-gate  */
9787c478bd9Sstevel@tonic-gate static int
sbbc_config4pci(struct sbbcsoft * sbbcsoftp)9797c478bd9Sstevel@tonic-gate sbbc_config4pci(struct sbbcsoft *sbbcsoftp)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t conf_handle;
9827c478bd9Sstevel@tonic-gate 	uint16_t comm, vendid, devid, stat;
9837c478bd9Sstevel@tonic-gate 	uint8_t revid;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate #ifdef DEBUG
9867c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
9877c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
9887c478bd9Sstevel@tonic-gate 		    "sbbc_config4pci: sbbcsoftp %p\n", (void *)sbbcsoftp);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate #endif
9917c478bd9Sstevel@tonic-gate 	if (pci_config_setup(sbbcsoftp->dip, &conf_handle) != DDI_SUCCESS)
9927c478bd9Sstevel@tonic-gate 		return (1);
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	vendid = pci_config_get16(conf_handle, PCI_CONF_VENID);
9957c478bd9Sstevel@tonic-gate 	devid = pci_config_get16(conf_handle, PCI_CONF_DEVID);
9967c478bd9Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM);
9977c478bd9Sstevel@tonic-gate 	stat = pci_config_get16(conf_handle, PCI_CONF_STAT);
9987c478bd9Sstevel@tonic-gate 	revid = pci_config_get8(conf_handle, PCI_CONF_REVID);
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate #ifdef DEBUG
10017c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
10027c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
10037c478bd9Sstevel@tonic-gate 		    "SBBC vendid %x, devid %x, comm %x, stat %x, revid %x\n",
10047c478bd9Sstevel@tonic-gate 		    vendid, devid, comm, stat, revid);
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate #endif
10077c478bd9Sstevel@tonic-gate 	comm = (PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_SERR_ENABLE |
100819397407SSherry Moore 	    PCI_COMM_PARITY_DETECT);
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM);
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate #ifdef DEBUG
10157c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
10167c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "comm %x\n", comm);
10177c478bd9Sstevel@tonic-gate 	}
10187c478bd9Sstevel@tonic-gate #endif
10197c478bd9Sstevel@tonic-gate 	pci_config_teardown(&conf_handle);
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	return (0);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
10267c478bd9Sstevel@tonic-gate int
sbbc_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)10277c478bd9Sstevel@tonic-gate sbbc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
10287c478bd9Sstevel@tonic-gate {
10297c478bd9Sstevel@tonic-gate 	dev_t	dev = (dev_t)arg;
10307c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
10317c478bd9Sstevel@tonic-gate 	int	instance, ret;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	instance = getminor(dev);
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_getinfo, 'GINF', instance);
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	switch (infocmd) {
10387c478bd9Sstevel@tonic-gate 		case DDI_INFO_DEVT2DEVINFO:
10397c478bd9Sstevel@tonic-gate 			sbbcsoftp = (struct sbbcsoft *)
1040634ee332Szk 			    ddi_get_soft_state(sbbcsoft_statep, instance);
1041634ee332Szk 			if (sbbcsoftp == NULL) {
1042634ee332Szk 				*result = (void *) NULL;
1043634ee332Szk 				ret = DDI_FAILURE;
1044634ee332Szk 			} else {
1045634ee332Szk 				*result = sbbcsoftp->dip;
1046634ee332Szk 				ret = DDI_SUCCESS;
1047634ee332Szk 			}
10487c478bd9Sstevel@tonic-gate 			break;
10497c478bd9Sstevel@tonic-gate 		case DDI_INFO_DEVT2INSTANCE:
1050bf30efa4Smathue 			*result = (void *)(uintptr_t)instance;
10517c478bd9Sstevel@tonic-gate 			ret = DDI_SUCCESS;
10527c478bd9Sstevel@tonic-gate 			break;
10537c478bd9Sstevel@tonic-gate 		default:
10547c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
10557c478bd9Sstevel@tonic-gate 			break;
10567c478bd9Sstevel@tonic-gate 	}
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	return (ret);
10597c478bd9Sstevel@tonic-gate }
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
10627c478bd9Sstevel@tonic-gate static int
sbbc_open(dev_t * dev,int flag,int otype,cred_t * credp)10637c478bd9Sstevel@tonic-gate sbbc_open(dev_t *dev, int flag, int otype, cred_t *credp)
10647c478bd9Sstevel@tonic-gate {
10657c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
10667c478bd9Sstevel@tonic-gate 	int		instance;
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	/* check privilege of caller process */
10697c478bd9Sstevel@tonic-gate 	if (drv_priv(credp)) {
10707c478bd9Sstevel@tonic-gate 		return (EPERM);
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	instance = getminor(*dev);
10747c478bd9Sstevel@tonic-gate 	if (instance < 0)
10757c478bd9Sstevel@tonic-gate 		return (ENXIO);
10767c478bd9Sstevel@tonic-gate 	sbbcsoftp = (struct sbbcsoft *)ddi_get_soft_state(sbbcsoft_statep,
107719397407SSherry Moore 	    instance);
10787c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_open, 'OPEN', sbbcsoftp);
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	if (sbbcsoftp == NULL)
10817c478bd9Sstevel@tonic-gate 		return (ENXIO);
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->umutex);
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	/* check for exclusive access */
10867c478bd9Sstevel@tonic-gate 	if ((sbbcsoftp->oflag == TRUE)) {
10877c478bd9Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
10887c478bd9Sstevel@tonic-gate 		return (EBUSY);
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate 	sbbcsoftp->oflag = TRUE;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->umutex);
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	return (0);
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
10987c478bd9Sstevel@tonic-gate static int
sbbc_close(dev_t dev,int flag,int otype,cred_t * credp)10997c478bd9Sstevel@tonic-gate sbbc_close(dev_t dev, int flag, int otype, cred_t *credp)
11007c478bd9Sstevel@tonic-gate {
11017c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
11027c478bd9Sstevel@tonic-gate 	int		instance;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	instance = getminor(dev);
11057c478bd9Sstevel@tonic-gate 	if (instance < 0)
11067c478bd9Sstevel@tonic-gate 		return (ENXIO);
11077c478bd9Sstevel@tonic-gate 	sbbcsoftp = (struct sbbcsoft *)ddi_get_soft_state(sbbcsoft_statep,
110819397407SSherry Moore 	    instance);
11097c478bd9Sstevel@tonic-gate 	/* wait till all output activity has ceased */
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->umutex);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_close, 'CLOS', sbbcsoftp);
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	sbbcsoftp->oflag = FALSE;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->umutex);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	return (0);
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
11237c478bd9Sstevel@tonic-gate static int
sbbc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)11247c478bd9Sstevel@tonic-gate sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1125*836be2feSToomas Soome     int *rvalp)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_ioctl, 'IOCT', arg);
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, getminor(dev));
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	if (sbbcsoftp == NULL) {
11347c478bd9Sstevel@tonic-gate 		return (ENXIO);
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	switch (cmd) {
11387c478bd9Sstevel@tonic-gate 	case SBBC_SBBCREG_WR:
11397c478bd9Sstevel@tonic-gate 		{
11407c478bd9Sstevel@tonic-gate 		struct ssc_sbbc_regio sbbcregs;
11417c478bd9Sstevel@tonic-gate 		uint64_t offset;
11427c478bd9Sstevel@tonic-gate 
1143b8dc8477Sarutz 		if (sbbc_scmode == FALSE) {
1144b8dc8477Sarutz 			/* then we're executing on Domain; Writes not allowed */
1145b8dc8477Sarutz 			return (EINVAL);
1146b8dc8477Sarutz 		}
1147b8dc8477Sarutz 
1148*836be2feSToomas Soome 		if (arg == (intptr_t)NULL) {
11497c478bd9Sstevel@tonic-gate 			return (ENXIO);
11507c478bd9Sstevel@tonic-gate 		}
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&sbbcregs,
11537c478bd9Sstevel@tonic-gate 				    sizeof (struct ssc_sbbc_regio), mode)) {
11547c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl: copyin failed arg %p",
11557c478bd9Sstevel@tonic-gate 			    (void *)arg);
11567c478bd9Sstevel@tonic-gate 			return (EFAULT);
11577c478bd9Sstevel@tonic-gate 		}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 		/*
11607c478bd9Sstevel@tonic-gate 		 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
11617c478bd9Sstevel@tonic-gate 		 *		reads or writes
11627c478bd9Sstevel@tonic-gate 		 * Note that I've also added a check to make sure the offset is
11637c478bd9Sstevel@tonic-gate 		 * valid, since misaligned (i.e. not on 16-byte boundary)
11647c478bd9Sstevel@tonic-gate 		 * accesses or accesses to "Reserved" register offsets are
11657c478bd9Sstevel@tonic-gate 		 * treated as unmapped by the SBBC.
11667c478bd9Sstevel@tonic-gate 		 */
11677c478bd9Sstevel@tonic-gate 		if ((sbbcregs.len != 4) ||
11687c478bd9Sstevel@tonic-gate 		    !sbbc_offset_valid(sbbcregs.offset)) {
11697c478bd9Sstevel@tonic-gate 			return (EINVAL);
11707c478bd9Sstevel@tonic-gate 		}
11717c478bd9Sstevel@tonic-gate 
1172b8dc8477Sarutz 		offset = (uint64_t)sbbcsoftp->pci_sbbc_map;
11737c478bd9Sstevel@tonic-gate 		offset += sbbcregs.offset;
11747c478bd9Sstevel@tonic-gate 		ddi_put32(sbbcsoftp->pci_sbbc_map_handle, (uint32_t *)offset,
117519397407SSherry Moore 		    sbbcregs.value);
11767c478bd9Sstevel@tonic-gate 		}
11777c478bd9Sstevel@tonic-gate 		break;
11787c478bd9Sstevel@tonic-gate 	case SBBC_SBBCREG_RD:
11797c478bd9Sstevel@tonic-gate 		{
11807c478bd9Sstevel@tonic-gate 		struct ssc_sbbc_regio sbbcregs;
11817c478bd9Sstevel@tonic-gate 		uint64_t offset;
11827c478bd9Sstevel@tonic-gate 
1183b8dc8477Sarutz 		if (sbbc_scmode == FALSE) {
1184b8dc8477Sarutz 			/* then we're executing on Domain; Reads not allowed */
1185b8dc8477Sarutz 			return (EINVAL);
1186b8dc8477Sarutz 		}
1187b8dc8477Sarutz 
1188*836be2feSToomas Soome 		if (arg == (intptr_t)NULL) {
11897c478bd9Sstevel@tonic-gate 			return (ENXIO);
11907c478bd9Sstevel@tonic-gate 		}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&sbbcregs,
11937c478bd9Sstevel@tonic-gate 				    sizeof (struct ssc_sbbc_regio), mode)) {
11947c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl: copyin failed arg %p",
11957c478bd9Sstevel@tonic-gate 			    (void *)arg);
11967c478bd9Sstevel@tonic-gate 			return (EFAULT);
11977c478bd9Sstevel@tonic-gate 		}
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 		/*
12007c478bd9Sstevel@tonic-gate 		 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
12017c478bd9Sstevel@tonic-gate 		 *		reads or writes
12027c478bd9Sstevel@tonic-gate 		 * Note that I've also added a check to make sure the offset is
12037c478bd9Sstevel@tonic-gate 		 * valid, since misaligned (i.e. not on 16-byte boundary)
12047c478bd9Sstevel@tonic-gate 		 * accesses or accesses to "Reserved" register offsets are
12057c478bd9Sstevel@tonic-gate 		 * treated as unmapped by the SBBC.
12067c478bd9Sstevel@tonic-gate 		 */
12077c478bd9Sstevel@tonic-gate 		if ((sbbcregs.len != 4) ||
12087c478bd9Sstevel@tonic-gate 		    !sbbc_offset_valid(sbbcregs.offset)) {
12097c478bd9Sstevel@tonic-gate 			return (EINVAL);
12107c478bd9Sstevel@tonic-gate 		}
12117c478bd9Sstevel@tonic-gate 
1212b8dc8477Sarutz 		offset = (uint64_t)sbbcsoftp->pci_sbbc_map;
12137c478bd9Sstevel@tonic-gate 		offset += sbbcregs.offset;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 		sbbcregs.value = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
121619397407SSherry Moore 		    (uint32_t *)offset);
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&sbbcregs.value,
121919397407SSherry Moore 		    &((struct ssc_sbbc_regio *)arg)->value,
122019397407SSherry Moore 		    sbbcregs.len, mode)) {
12217c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl:copyout failed arg %p",
12227c478bd9Sstevel@tonic-gate 			    (void *)arg);
12237c478bd9Sstevel@tonic-gate 			return (EFAULT);
12247c478bd9Sstevel@tonic-gate 		}
12257c478bd9Sstevel@tonic-gate 		}
12267c478bd9Sstevel@tonic-gate 		break;
12277c478bd9Sstevel@tonic-gate 	default:
12287c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc_ioctl:Illegal command 0x%08x", cmd);
12297c478bd9Sstevel@tonic-gate 		return (ENOTTY);
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12337c478bd9Sstevel@tonic-gate }
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate static void
sbbc_remove_reg_maps(struct sbbcsoft * sbbcsoftp)12367c478bd9Sstevel@tonic-gate sbbc_remove_reg_maps(struct sbbcsoft *sbbcsoftp)
12377c478bd9Sstevel@tonic-gate {
12387c478bd9Sstevel@tonic-gate 	SBBCTRACE(sbbc_remove_reg_maps, 'RMAP', sbbcsoftp);
12397c478bd9Sstevel@tonic-gate 	if (sbbcsoftp->pci_sbbc_map_handle)
12407c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&sbbcsoftp->pci_sbbc_map_handle);
12417c478bd9Sstevel@tonic-gate }
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate static int
sbbc_init(struct sbbcsoft * sbbcsoftp)12457c478bd9Sstevel@tonic-gate sbbc_init(struct sbbcsoft *sbbcsoftp)
12467c478bd9Sstevel@tonic-gate {
1247b8dc8477Sarutz 	/* Mask all the interrupts until we are ready. */
12487c478bd9Sstevel@tonic-gate 	ddi_put32(sbbcsoftp->pci_sbbc_map_handle,
1249b8dc8477Sarutz 	    &sbbcsoftp->pci_sbbc_map->sys_intr_enable,
12507c478bd9Sstevel@tonic-gate 	    0x00000000);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	return (1);
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate /*
12567c478bd9Sstevel@tonic-gate  * The following routine is a generic routine to initialize any child of
12577c478bd9Sstevel@tonic-gate  * sbbc nexus driver information into parent private data structure.
12587c478bd9Sstevel@tonic-gate  */
12597c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
12607c478bd9Sstevel@tonic-gate static int
sbbc_initchild(dev_info_t * dip,dev_info_t * rdip,dev_info_t * child)12617c478bd9Sstevel@tonic-gate sbbc_initchild(dev_info_t *dip, dev_info_t *rdip, dev_info_t *child)
12627c478bd9Sstevel@tonic-gate {
12637c478bd9Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp;
12647c478bd9Sstevel@tonic-gate 	int reglen, slot;
12657c478bd9Sstevel@tonic-gate 	char name[10];
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_INITCHILD, dip, "Initializing %s\n",
12687c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip));
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * Initialize a child
12727c478bd9Sstevel@tonic-gate 	 * Set the address portion of the node name based on the
12737c478bd9Sstevel@tonic-gate 	 * address/offset.
12747c478bd9Sstevel@tonic-gate 	 */
1275a3282898Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
12767c478bd9Sstevel@tonic-gate 	    "reg", (caddr_t)&child_rp, &reglen) != DDI_SUCCESS) {
12777c478bd9Sstevel@tonic-gate 		if (strcmp(ddi_node_name(child), "hotplug-controller") == 0) {
12787c478bd9Sstevel@tonic-gate 			slot = 1;
12797c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%x", slot);
12807c478bd9Sstevel@tonic-gate 			ddi_set_name_addr(child, name);
12817c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
12827c478bd9Sstevel@tonic-gate 		}
12837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
12847c478bd9Sstevel@tonic-gate 	}
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	SBBC_DBG3(SBBC_DBG_INITCHILD, dip, "hi 0x%x, low 0x%x, size 0x%x\n",
12877c478bd9Sstevel@tonic-gate 	    child_rp->addr_hi, child_rp->addr_low, child_rp->size);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%x,%x", child_rp->addr_hi, child_rp->addr_low);
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	/*
12927c478bd9Sstevel@tonic-gate 	 * set child's addresses from the reg property into parent private
12937c478bd9Sstevel@tonic-gate 	 * data structure.
12947c478bd9Sstevel@tonic-gate 	 */
12957c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
12967c478bd9Sstevel@tonic-gate 	kmem_free(child_rp, reglen);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 	ddi_set_parent_data(child, NULL);
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13017c478bd9Sstevel@tonic-gate }
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate /* ARGSUSED0 */
13057c478bd9Sstevel@tonic-gate static int
sbbc_uninitchild(dev_info_t * rdip,dev_info_t * child)13067c478bd9Sstevel@tonic-gate sbbc_uninitchild(dev_info_t *rdip, dev_info_t *child)
13077c478bd9Sstevel@tonic-gate {
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_UNINITCHILD, rdip, "Uninitializing %s\n",
13107c478bd9Sstevel@tonic-gate 	    ddi_driver_name(rdip));
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
13137c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(child, NULL);
13147c478bd9Sstevel@tonic-gate 	impl_rem_dev_props(child);
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate /*
13227c478bd9Sstevel@tonic-gate  * The following routine is an interrupt service routine that is used
13237c478bd9Sstevel@tonic-gate  * as a wrapper to all the children requiring interrupt services.
13247c478bd9Sstevel@tonic-gate  */
13257c478bd9Sstevel@tonic-gate static uint_t
sbbc_intr_wrapper(caddr_t arg)13267c478bd9Sstevel@tonic-gate sbbc_intr_wrapper(caddr_t arg)
13277c478bd9Sstevel@tonic-gate {
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp = (struct sbbcsoft *)arg;
13307c478bd9Sstevel@tonic-gate 	int i, rval;
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_INTR, sbbcsoftp->dip, "Isr arg 0x%llx\n", arg);
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->sbbc_intr_mutex);
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
13377c478bd9Sstevel@tonic-gate 		/*
13387c478bd9Sstevel@tonic-gate 		 * Check the interrupt status reg. to determine the cause.
13397c478bd9Sstevel@tonic-gate 		 */
13407c478bd9Sstevel@tonic-gate 		/*
13417c478bd9Sstevel@tonic-gate 		 * Check the error status reg. to determine the cause.
13427c478bd9Sstevel@tonic-gate 		 */
13437c478bd9Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i] &&
13447c478bd9Sstevel@tonic-gate 		    sbbcsoftp->child_intr[i]->status ==
13457c478bd9Sstevel@tonic-gate 		    SBBC_INTR_STATE_ENABLE) {
13467c478bd9Sstevel@tonic-gate 			/*
13477c478bd9Sstevel@tonic-gate 			 * Dispatch the children interrupt service routines and
13487c478bd9Sstevel@tonic-gate 			 * look for someone to claim.
13497c478bd9Sstevel@tonic-gate 			 */
13507c478bd9Sstevel@tonic-gate 			rval = sbbcsoftp->child_intr[i]->intr_handler(
13517c478bd9Sstevel@tonic-gate 			    sbbcsoftp->child_intr[i]->arg1,
13527c478bd9Sstevel@tonic-gate 			    sbbcsoftp->child_intr[i]->arg2);
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 			if (rval == DDI_INTR_CLAIMED) {
13557c478bd9Sstevel@tonic-gate 				mutex_exit(&sbbcsoftp->sbbc_intr_mutex);
13567c478bd9Sstevel@tonic-gate 				return (rval);
13577c478bd9Sstevel@tonic-gate 			}
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 	}
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->sbbc_intr_mutex);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	/* for now do not claim since we know its not enabled */
13647c478bd9Sstevel@tonic-gate 	return (DDI_INTR_UNCLAIMED);
13657c478bd9Sstevel@tonic-gate }
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate /*
13697c478bd9Sstevel@tonic-gate  * This function checks an SBBC register offset to make sure that it is properly
13707c478bd9Sstevel@tonic-gate  * aligned (i.e. on a 16-byte boundary) and that it corresponds to an accessible
13717c478bd9Sstevel@tonic-gate  * register.  Since the SBBC treates accesses to unaligned or reserved addresses
13727c478bd9Sstevel@tonic-gate  * as unmapped, failing to check for these would leave a loophole that could be
13737c478bd9Sstevel@tonic-gate  * used to crash the system.
13747c478bd9Sstevel@tonic-gate  */
13757c478bd9Sstevel@tonic-gate static int
sbbc_offset_valid(uint32_t offset)1376*836be2feSToomas Soome sbbc_offset_valid(uint32_t offset)
1377*836be2feSToomas Soome {
13787c478bd9Sstevel@tonic-gate 	/*
13797c478bd9Sstevel@tonic-gate 	 * Check for proper alignment first.
13807c478bd9Sstevel@tonic-gate 	 */
13817c478bd9Sstevel@tonic-gate 	if ((offset % 16) != 0) {
13827c478bd9Sstevel@tonic-gate 		return (0);
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	/*
13867c478bd9Sstevel@tonic-gate 	 * Now start checking for the various reserved ranges.
13877c478bd9Sstevel@tonic-gate 	 * While sticking a bunch of constants in the code (rather than
13887c478bd9Sstevel@tonic-gate 	 * #define'd values) is usually best avoided, it would probably
13897c478bd9Sstevel@tonic-gate 	 * do more harm than good here.  These values were taken from the
13907c478bd9Sstevel@tonic-gate 	 * Serengeti Architecture Programmer's Reference Manual dated
13917c478bd9Sstevel@tonic-gate 	 * August 10, 1999, pages 2-99 through 2-103.  While there are
13927c478bd9Sstevel@tonic-gate 	 * various "clever" ways this check could be performed that would
13937c478bd9Sstevel@tonic-gate 	 * be slightly more efficient, arranging the code in this fashion
13947c478bd9Sstevel@tonic-gate 	 * should maximize maintainability.
13957c478bd9Sstevel@tonic-gate 	 */
13967c478bd9Sstevel@tonic-gate 	if (((offset >= 0x001a0) && (offset <= 0x001ff)) ||
13977c478bd9Sstevel@tonic-gate 	    ((offset >= 0x002a0) && (offset <= 0x002ff)) ||
13987c478bd9Sstevel@tonic-gate 	    ((offset >= 0x00350) && (offset <= 0x003ff)) ||
13997c478bd9Sstevel@tonic-gate 	    ((offset >= 0x00500) && (offset <= 0x00fff)) ||
14007c478bd9Sstevel@tonic-gate 	    ((offset >= 0x01160) && (offset <= 0x011ff)) ||
14017c478bd9Sstevel@tonic-gate 	    ((offset >= 0x01210) && (offset <= 0x017ff)) ||
14027c478bd9Sstevel@tonic-gate 	    ((offset >= 0x01810) && (offset <= 0x01fff)) ||
14037c478bd9Sstevel@tonic-gate 	    ((offset >= 0x02030) && (offset <= 0x022ff)) ||
14047c478bd9Sstevel@tonic-gate 	    ((offset >= 0x02340) && (offset <= 0x03fff)) ||
14057c478bd9Sstevel@tonic-gate 	    ((offset >= 0x04030) && (offset <= 0x05fff)) ||
14067c478bd9Sstevel@tonic-gate 	    ((offset >= 0x060a0) && (offset <= 0x060ff)) ||
14077c478bd9Sstevel@tonic-gate 	    (offset == 0x06120) ||
14087c478bd9Sstevel@tonic-gate 	    ((offset >= 0x06190) && (offset <= 0x061ff)) ||
14097c478bd9Sstevel@tonic-gate 	    ((offset >= 0x06230) && (offset <= 0x062f0)) ||
14107c478bd9Sstevel@tonic-gate 	    (offset > 0x06320)) {
14117c478bd9Sstevel@tonic-gate 		return (0);
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	return (1);
14157c478bd9Sstevel@tonic-gate }
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate #ifdef DEBUG
14187c478bd9Sstevel@tonic-gate void
sbbc_dbg(uint32_t flag,dev_info_t * dip,char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)14197c478bd9Sstevel@tonic-gate sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt,
1420*836be2feSToomas Soome     uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
14217c478bd9Sstevel@tonic-gate {
14227c478bd9Sstevel@tonic-gate 	char *s = NULL;
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	if (sbbc_dbg_flags && ((sbbc_dbg_flags & flag) == flag)) {
14257c478bd9Sstevel@tonic-gate 		switch (flag) {
14267c478bd9Sstevel@tonic-gate 		case SBBC_DBG_ATTACH:
14277c478bd9Sstevel@tonic-gate 			s = "attach";
14287c478bd9Sstevel@tonic-gate 			break;
14297c478bd9Sstevel@tonic-gate 		case SBBC_DBG_DETACH:
14307c478bd9Sstevel@tonic-gate 			s = "detach";
14317c478bd9Sstevel@tonic-gate 			break;
14327c478bd9Sstevel@tonic-gate 		case SBBC_DBG_CTLOPS:
14337c478bd9Sstevel@tonic-gate 			s = "ctlops";
14347c478bd9Sstevel@tonic-gate 			break;
14357c478bd9Sstevel@tonic-gate 		case SBBC_DBG_INITCHILD:
14367c478bd9Sstevel@tonic-gate 			s = "initchild";
14377c478bd9Sstevel@tonic-gate 			break;
14387c478bd9Sstevel@tonic-gate 		case SBBC_DBG_UNINITCHILD:
14397c478bd9Sstevel@tonic-gate 			s = "uninitchild";
14407c478bd9Sstevel@tonic-gate 			break;
14417c478bd9Sstevel@tonic-gate 		case SBBC_DBG_BUSMAP:
14427c478bd9Sstevel@tonic-gate 			s = "busmap";
14437c478bd9Sstevel@tonic-gate 			break;
14447c478bd9Sstevel@tonic-gate 		case SBBC_DBG_INTR:
14457c478bd9Sstevel@tonic-gate 			s = "intr";
14467c478bd9Sstevel@tonic-gate 			break;
14477c478bd9Sstevel@tonic-gate 		case SBBC_DBG_INTROPS:
14487c478bd9Sstevel@tonic-gate 			s = "intr_ops";
14497c478bd9Sstevel@tonic-gate 			break;
14507c478bd9Sstevel@tonic-gate 		case SBBC_DBG_PCICONF:
14517c478bd9Sstevel@tonic-gate 			s = "pciconfig";
14527c478bd9Sstevel@tonic-gate 			break;
14537c478bd9Sstevel@tonic-gate 		case SBBC_DBG_MAPRANGES:
14547c478bd9Sstevel@tonic-gate 			s = "mapranges";
14557c478bd9Sstevel@tonic-gate 			break;
14567c478bd9Sstevel@tonic-gate 		case SBBC_DBG_PROPERTIES:
14577c478bd9Sstevel@tonic-gate 			s = "properties";
14587c478bd9Sstevel@tonic-gate 			break;
14597c478bd9Sstevel@tonic-gate 		case SBBC_DBG_OPEN:
14607c478bd9Sstevel@tonic-gate 			s = "open";
14617c478bd9Sstevel@tonic-gate 			break;
14627c478bd9Sstevel@tonic-gate 		case SBBC_DBG_CLOSE:
14637c478bd9Sstevel@tonic-gate 			s = "close";
14647c478bd9Sstevel@tonic-gate 			break;
14657c478bd9Sstevel@tonic-gate 		case SBBC_DBG_IOCTL:
14667c478bd9Sstevel@tonic-gate 			s = "ioctl";
14677c478bd9Sstevel@tonic-gate 			break;
14687c478bd9Sstevel@tonic-gate 		default:
14697c478bd9Sstevel@tonic-gate 			s = "Unknown debug flag";
14707c478bd9Sstevel@tonic-gate 			break;
14717c478bd9Sstevel@tonic-gate 		}
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s_%s(%d): ", ddi_driver_name(dip), s,
147419397407SSherry Moore 		    ddi_get_instance(dip));
14757c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
14767c478bd9Sstevel@tonic-gate 	}
14777c478bd9Sstevel@tonic-gate }
14787c478bd9Sstevel@tonic-gate 
1479b8dc8477Sarutz /*
1480b8dc8477Sarutz  * Dump the SBBC chip's Device ID Register
1481b8dc8477Sarutz  */
sbbc_dump_devid(dev_info_t * dip,struct sbbcsoft * sbbcsoftp,int instance)1482b8dc8477Sarutz static void sbbc_dump_devid(dev_info_t *dip, struct sbbcsoft *sbbcsoftp,
1483b8dc8477Sarutz 	int instance)
1484b8dc8477Sarutz {
1485b8dc8477Sarutz 	uint32_t sbbc_id_reg;
1486b8dc8477Sarutz 	uint16_t sbbc_id_reg_partid;
1487b8dc8477Sarutz 	uint16_t sbbc_id_reg_manfid;
1488b8dc8477Sarutz 
1489b8dc8477Sarutz 	sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
1490b8dc8477Sarutz 	    (uint32_t *)&sbbcsoftp->pci_sbbc_map->devid);
1491b8dc8477Sarutz 
1492b8dc8477Sarutz 	sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16);
1493b8dc8477Sarutz 	sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21);
1494b8dc8477Sarutz 
1495b8dc8477Sarutz 	SBBC_DBG4(SBBC_DBG_ATTACH, dip,
1496b8dc8477Sarutz 	    "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n",
1497b8dc8477Sarutz 	    instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid,
1498b8dc8477Sarutz 	    sbbc_id_reg_manfid);
1499b8dc8477Sarutz }
1500b8dc8477Sarutz 
15017c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1502