xref: /onnv-gate/usr/src/uts/sun4u/io/sbbc.c (revision 7656:2621e50fdf4a)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52536Sarutz  * Common Development and Distribution License (the "License").
62536Sarutz  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
282536Sarutz  * Starcat PCI SBBC Nexus Driver.
292536Sarutz  *
302536Sarutz  * This source code's compiled binary runs on both a Starcat System
312536Sarutz  * Controller (SSC) and a Starcat Domain.  One of the SBBC hardware
322536Sarutz  * registers is read during attach(9e) in order to determine which
332536Sarutz  * environment the driver is executing on.
342536Sarutz  *
352536Sarutz  * On both the SSC and the Domain, this driver provides nexus driver
362536Sarutz  * services to its Device Tree children.  Note that the children in
372536Sarutz  * each environment are not necessarily the same.
382536Sarutz  *
392536Sarutz  * This driver allows one concurrent open(2) of its associated device
402536Sarutz  * (/dev/sbbc0).  The client uses the file descriptor to issue
412536Sarutz  * ioctl(2)'s in order to read and write from the 2MB (PCI) space
422536Sarutz  * reserved for "SBBC Internal Registers".  Among other things,
432536Sarutz  * these registers consist of command/control/status registers for
442536Sarutz  * devices such as Console Bus, I2C, EPLD, IOSRAM, and JTAG.  The 2MB
452536Sarutz  * space is very sparse; EINVAL is returned if a reserved or unaligned
462536Sarutz  * address is specified in the ioctl(2).
472536Sarutz  *
482536Sarutz  * Note that the 2MB region reserved for SBBC Internal Registers is
492536Sarutz  * a subset of the 128MB of PCI address space addressable by the SBBC
502536Sarutz  * ASIC.  Address space outside of the 2MB (such as the 64MB reserved
512536Sarutz  * for the Console Bus) is not accessible via this driver.
522536Sarutz  *
532536Sarutz  * Also, note that the SBBC Internal Registers are only read and
542536Sarutz  * written by the SSC; no process on the Domain accesses these
552536Sarutz  * registers.  As a result, the registers are unmapped (when running
562536Sarutz  * on the Domain) near the end of attach(9e) processing.  This conserves
572536Sarutz  * kernel virtual address space resources (as one instance of the driver
582536Sarutz  * is created for each Domain-side IO assembly).  (To be complete, only
592536Sarutz  * one instance of the driver is created on the SSC).
600Sstevel@tonic-gate  */
610Sstevel@tonic-gate 
620Sstevel@tonic-gate #include <sys/types.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
650Sstevel@tonic-gate #include <sys/ddi.h>
660Sstevel@tonic-gate #include <sys/sunddi.h>
670Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
680Sstevel@tonic-gate #include <sys/ddi_subrdefs.h>
690Sstevel@tonic-gate #include <sys/pci.h>
700Sstevel@tonic-gate #include <sys/pci/pci_nexus.h>
710Sstevel@tonic-gate #include <sys/autoconf.h>
720Sstevel@tonic-gate #include <sys/cmn_err.h>
730Sstevel@tonic-gate #include <sys/param.h>
740Sstevel@tonic-gate #include <sys/errno.h>
750Sstevel@tonic-gate #include <sys/kmem.h>
760Sstevel@tonic-gate #include <sys/debug.h>
770Sstevel@tonic-gate #include <sys/sysmacros.h>
780Sstevel@tonic-gate #include <sys/machsystm.h>
790Sstevel@tonic-gate #include <sys/modctl.h>
800Sstevel@tonic-gate #include <sys/stat.h>
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #include <sys/sbbcreg.h>	/* hw description */
840Sstevel@tonic-gate #include <sys/sbbcvar.h>	/* driver description */
850Sstevel@tonic-gate #include <sys/sbbcio.h>		/* ioctl description */
860Sstevel@tonic-gate 
870Sstevel@tonic-gate #define	getprop(dip, name, addr, intp)		\
88506Scth 		ddi_getlongprop(DDI_DEV_T_ANY, (dip), DDI_PROP_DONTPASS, \
890Sstevel@tonic-gate 				(name), (caddr_t)(addr), (intp))
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /* driver entry point fn definitions */
920Sstevel@tonic-gate static int sbbc_open(dev_t *, int, int, cred_t *);
930Sstevel@tonic-gate static int sbbc_close(dev_t, int, int, cred_t *);
940Sstevel@tonic-gate static int sbbc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /* configuration entry point fn definitions */
970Sstevel@tonic-gate static int sbbc_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
980Sstevel@tonic-gate static int sbbc_attach(dev_info_t *, ddi_attach_cmd_t);
990Sstevel@tonic-gate static int sbbc_detach(dev_info_t *, ddi_detach_cmd_t);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /* local utility routines */
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * NOTE - sbbc_offset_valid contains detailed address information taken from
1040Sstevel@tonic-gate  * the Serengeti Architecture Programmer's Reference Manual.  If any
1050Sstevel@tonic-gate  * changes are made to the SBBC registers, this routine may need to be
1060Sstevel@tonic-gate  * updated.
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate static int sbbc_offset_valid(uint32_t offset);
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate  * function prototypes for bus ops routines:
1120Sstevel@tonic-gate  */
1130Sstevel@tonic-gate static int sbbc_busmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
1140Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *addrp);
1150Sstevel@tonic-gate static int sbbc_ctlops(dev_info_t *dip, dev_info_t *rdip,
1160Sstevel@tonic-gate 	ddi_ctl_enum_t op, void *arg, void *result);
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate static int sbbc_intr_ops(dev_info_t *dip, dev_info_t *rdip,
1190Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1200Sstevel@tonic-gate static int sbbc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1210Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1220Sstevel@tonic-gate static int sbbc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip,
1230Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1240Sstevel@tonic-gate static int sbbc_update_intr_state(dev_info_t *dip, dev_info_t *rdip,
1250Sstevel@tonic-gate 	ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static int sbbc_apply_range(struct sbbcsoft *sbbc_p, dev_info_t *rdip,
1280Sstevel@tonic-gate     sbbc_child_regspec_t *child_rp, pci_regspec_t *rp);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate static int sbbc_init(struct sbbcsoft *);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate static uint_t sbbc_intr_wrapper(caddr_t arg);
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate static int sbbc_get_ranges(struct sbbcsoft *);
1350Sstevel@tonic-gate static int sbbc_config4pci(struct sbbcsoft *);
1360Sstevel@tonic-gate static int sbbc_initchild(dev_info_t *, dev_info_t *, dev_info_t *);
1370Sstevel@tonic-gate static int sbbc_uninitchild(dev_info_t *, dev_info_t *);
1380Sstevel@tonic-gate static void sbbc_remove_reg_maps(struct sbbcsoft *);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /* debugging functions */
1410Sstevel@tonic-gate #ifdef DEBUG
1420Sstevel@tonic-gate uint32_t sbbc_dbg_flags = 0x0;
1430Sstevel@tonic-gate static void sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt,
1440Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5);
1452536Sarutz static void sbbc_dump_devid(dev_info_t *, struct sbbcsoft *, int instance);
1460Sstevel@tonic-gate #endif
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * For tracing, allocate space for the trace buffer
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate #if defined(SBBC_TRACE)
1520Sstevel@tonic-gate struct sbbctrace sbbctrace_buffer[NSBBCTRACE+1];
1530Sstevel@tonic-gate struct sbbctrace *sbbctrace_ptr;
1540Sstevel@tonic-gate int sbbctrace_count;
1550Sstevel@tonic-gate #endif
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate /*
1580Sstevel@tonic-gate  * Local declarations and variables
1590Sstevel@tonic-gate  */
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static void *sbbcsoft_statep;
1622536Sarutz 
1632536Sarutz /* Determines whether driver is executing on System Controller or Domain */
1640Sstevel@tonic-gate int sbbc_scmode = FALSE;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * ops stuff.
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate static struct bus_ops sbbc_bus_ops = {
1700Sstevel@tonic-gate 	BUSO_REV,
1710Sstevel@tonic-gate 	sbbc_busmap,
1720Sstevel@tonic-gate 	0,
1730Sstevel@tonic-gate 	0,
1740Sstevel@tonic-gate 	0,
1750Sstevel@tonic-gate 	NULL, 			/* (*bus_map_fault)() */
1760Sstevel@tonic-gate 	ddi_no_dma_map,
1770Sstevel@tonic-gate 	ddi_no_dma_allochdl,
1780Sstevel@tonic-gate 	ddi_no_dma_freehdl, 	/* (*bus_dma_freehdl)() */
1790Sstevel@tonic-gate 	ddi_no_dma_bindhdl, 	/* (*bus_dma_bindhdl)() */
1800Sstevel@tonic-gate 	ddi_no_dma_unbindhdl, 	/* (*bus_dma_unbindhdl)() */
1810Sstevel@tonic-gate 	ddi_no_dma_flush, 	/* (*bus_dma_flush)() */
1820Sstevel@tonic-gate 	ddi_no_dma_win, 	/* (*bus_dma_win)() */
1830Sstevel@tonic-gate 	ddi_no_dma_mctl, 	/* (*bus_dma_ctl)() */
1840Sstevel@tonic-gate 	sbbc_ctlops,
1850Sstevel@tonic-gate 	ddi_bus_prop_op,
1860Sstevel@tonic-gate 	0,			/* (*bus_get_eventcookie)();	*/
1870Sstevel@tonic-gate 	0,			/* (*bus_add_eventcall)();	*/
1880Sstevel@tonic-gate 	0,			/* (*bus_remove_eventcall)();	*/
1890Sstevel@tonic-gate 	0,			/* (*bus_post_event)();		*/
1900Sstevel@tonic-gate 	0,			/* (*bus_intr_ctl)();	*/
1910Sstevel@tonic-gate 	0,			/* (*bus_config)();	*/
1920Sstevel@tonic-gate 	0,			/* (*bus_unconfig)();	*/
1930Sstevel@tonic-gate 	0,			/* (*bus_fm_init)();	*/
1940Sstevel@tonic-gate 	0,			/* (*bus_fm_fini)();	*/
1950Sstevel@tonic-gate 	0,			/* (*bus_fm_access_enter)();	*/
1960Sstevel@tonic-gate 	0,			/* (*bus_fm_access_exit)();	*/
1970Sstevel@tonic-gate 	0,			/* (*bus_power)();	*/
1980Sstevel@tonic-gate 	sbbc_intr_ops		/* (*bus_intr_op)();	*/
1990Sstevel@tonic-gate };
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate  * cb_ops
2030Sstevel@tonic-gate  */
2040Sstevel@tonic-gate static struct cb_ops sbbc_cb_ops = {
2050Sstevel@tonic-gate 	sbbc_open,		/* cb_open */
2060Sstevel@tonic-gate 	sbbc_close,		/* cb_close */
2070Sstevel@tonic-gate 	nodev,			/* cb_strategy */
2080Sstevel@tonic-gate 	nodev,			/* cb_print */
2090Sstevel@tonic-gate 	nodev,			/* cb_dump */
2100Sstevel@tonic-gate 	nodev,			/* cb_read */
2110Sstevel@tonic-gate 	nodev,			/* cb_write */
2120Sstevel@tonic-gate 	sbbc_ioctl,		/* cb_ioctl */
2130Sstevel@tonic-gate 	nodev,			/* cb_devmap */
2140Sstevel@tonic-gate 	nodev,			/* cb_mmap */
2150Sstevel@tonic-gate 	nodev,			/* cb_segmap */
2160Sstevel@tonic-gate 	nochpoll,		/* cb_chpoll */
2170Sstevel@tonic-gate 	ddi_prop_op,		/* cb_prop_op */
2180Sstevel@tonic-gate 	NULL,			/* cb_stream */
2190Sstevel@tonic-gate 	(int)(D_NEW | D_MP)	/* cb_flag */
2200Sstevel@tonic-gate };
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate /*
2230Sstevel@tonic-gate  * Declare ops vectors for auto configuration.
2240Sstevel@tonic-gate  */
2250Sstevel@tonic-gate struct dev_ops  sbbc_ops = {
2260Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev */
2270Sstevel@tonic-gate 	0,			/* devo_refcnt */
2280Sstevel@tonic-gate 	sbbc_getinfo,		/* devo_getinfo */
2290Sstevel@tonic-gate 	nulldev,		/* devo_identify */
2300Sstevel@tonic-gate 	nulldev,		/* devo_probe */
2310Sstevel@tonic-gate 	sbbc_attach,		/* devo_attach */
2320Sstevel@tonic-gate 	sbbc_detach,		/* devo_detach */
2330Sstevel@tonic-gate 	nodev,			/* devo_reset */
2340Sstevel@tonic-gate 	&sbbc_cb_ops,		/* devo_cb_ops */
2350Sstevel@tonic-gate 	&sbbc_bus_ops,		/* devo_bus_ops */
236*7656SSherry.Moore@Sun.COM 	nulldev,			/* devo_power */
237*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
2380Sstevel@tonic-gate };
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate  * Loadable module support.
2420Sstevel@tonic-gate  */
2430Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate static struct modldrv sbbcmodldrv = {
2460Sstevel@tonic-gate 	&mod_driverops,		/* type of module - driver */
247*7656SSherry.Moore@Sun.COM 	"PCI Sbbc Nexus Driver",
2480Sstevel@tonic-gate 	&sbbc_ops,
2490Sstevel@tonic-gate };
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate static struct modlinkage sbbcmodlinkage = {
2520Sstevel@tonic-gate 	MODREV_1,
2530Sstevel@tonic-gate 	&sbbcmodldrv,
2540Sstevel@tonic-gate 	NULL
2550Sstevel@tonic-gate };
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate int
_init(void)2580Sstevel@tonic-gate _init(void)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	int    error;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if ((error = ddi_soft_state_init(&sbbcsoft_statep,
263*7656SSherry.Moore@Sun.COM 	    sizeof (struct sbbcsoft), 1)) != 0)
2640Sstevel@tonic-gate 		return (error);
2650Sstevel@tonic-gate 	if ((error = mod_install(&sbbcmodlinkage)) != 0)
2660Sstevel@tonic-gate 		ddi_soft_state_fini(&sbbcsoft_statep);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	return (error);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate int
_fini(void)2720Sstevel@tonic-gate _fini(void)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate 	int    error;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if ((error = mod_remove(&sbbcmodlinkage)) == 0)
2770Sstevel@tonic-gate 		ddi_soft_state_fini(&sbbcsoft_statep);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	return (error);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2830Sstevel@tonic-gate _info(struct modinfo *modinfop)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate 	return (mod_info(&sbbcmodlinkage, modinfop));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate static int
sbbc_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2890Sstevel@tonic-gate sbbc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	int	instance;
2920Sstevel@tonic-gate 	char	name[32];
2930Sstevel@tonic-gate 	struct	sbbcsoft *sbbcsoftp;
2940Sstevel@tonic-gate 	struct ddi_device_acc_attr attr;
2952536Sarutz 	uint32_t sbbc_id_reg;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
2980Sstevel@tonic-gate 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
2990Sstevel@tonic-gate 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/* initialize tracing */
3020Sstevel@tonic-gate 	SBBCTRACEINIT();
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attaching\n");
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
3070Sstevel@tonic-gate 	switch (cmd) {
3080Sstevel@tonic-gate 	case DDI_ATTACH:
3090Sstevel@tonic-gate 		break;
3100Sstevel@tonic-gate 	case DDI_RESUME:
3110Sstevel@tonic-gate 		if (!(sbbcsoftp =
3120Sstevel@tonic-gate 		    ddi_get_soft_state(sbbcsoft_statep, instance))) {
3132536Sarutz 			cmn_err(CE_WARN, "sbbc_attach:resume: unable "
3142536Sarutz 			    "to acquire sbbcsoftp for instance %d",
3150Sstevel@tonic-gate 			    instance);
3160Sstevel@tonic-gate 			return (DDI_FAILURE);
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 		mutex_enter(&sbbcsoftp->umutex);
3190Sstevel@tonic-gate 		if (!sbbcsoftp->suspended) {
3200Sstevel@tonic-gate 			mutex_exit(&sbbcsoftp->umutex);
3210Sstevel@tonic-gate 			return (DDI_FAILURE);
3220Sstevel@tonic-gate 		}
3230Sstevel@tonic-gate 		sbbcsoftp->suspended = 0;
3240Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
3250Sstevel@tonic-gate 		return (DDI_SUCCESS);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	default:
3280Sstevel@tonic-gate 		return (DDI_FAILURE);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(sbbcsoft_statep, instance) != 0) {
3322536Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to allocate statep "
3332536Sarutz 		    "for instance %d", instance);
3340Sstevel@tonic-gate 		return (DDI_FAILURE);
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if (sbbcsoftp == NULL) {
3402536Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to acquire "
3412536Sarutz 		    "sbbcsoftp for instance %d", instance);
3420Sstevel@tonic-gate 		ddi_soft_state_free(sbbcsoft_statep, instance);
3430Sstevel@tonic-gate 		return (DDI_FAILURE);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	sbbcsoftp->instance = instance;
3470Sstevel@tonic-gate 	sbbcsoftp->dip = dip;
3480Sstevel@tonic-gate 	sbbcsoftp->oflag = FALSE;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	/*
3510Sstevel@tonic-gate 	 * Read our ranges property from OBP to map children space.
3520Sstevel@tonic-gate 	 * And setup the internal structure for a later use when
3530Sstevel@tonic-gate 	 * a child gets initialized.
3540Sstevel@tonic-gate 	 */
3550Sstevel@tonic-gate 	if (sbbc_get_ranges(sbbcsoftp)) {
3562536Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to read sbbc "
3572536Sarutz 		    "ranges from OBP %d", instance);
3582536Sarutz 		ddi_soft_state_free(sbbcsoft_statep, instance);
3590Sstevel@tonic-gate 		return (DDI_FAILURE);
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	if (sbbc_config4pci(sbbcsoftp)) {
3632536Sarutz 		cmn_err(CE_WARN, "sbbc_attach: Unable to configure "
3642536Sarutz 		    "sbbc on PCI %d", instance);
3652536Sarutz 		kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
3662536Sarutz 		ddi_soft_state_free(sbbcsoft_statep, instance);
3670Sstevel@tonic-gate 		return (DDI_FAILURE);
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	mutex_init(&sbbcsoftp->umutex, NULL, MUTEX_DRIVER, (void *)NULL);
3710Sstevel@tonic-gate 	mutex_init(&sbbcsoftp->sbbc_intr_mutex, NULL,
3720Sstevel@tonic-gate 	    MUTEX_DRIVER, (void *)NULL);
3730Sstevel@tonic-gate 
3742536Sarutz 	/* Map SBBC's Internal Registers */
3752536Sarutz 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&sbbcsoftp->pci_sbbc_map,
3762536Sarutz 	    offsetof(struct pci_sbbc, sbbc_internal_regs),
3772536Sarutz 	    sizeof (struct sbbc_regs_map), &attr,
3782536Sarutz 	    &sbbcsoftp->pci_sbbc_map_handle) != DDI_SUCCESS) {
3792536Sarutz 		cmn_err(CE_WARN, "(%d):sbbc_attach failed to map sbbc_reg",
3802536Sarutz 		    instance);
3812536Sarutz 		goto failed;
3822536Sarutz 	}
3832536Sarutz 
3842536Sarutz 	SBBC_DBG1(SBBC_DBG_ATTACH, dip, "Mapped sbbc at %lx\n",
3852536Sarutz 	    sbbcsoftp->pci_sbbc_map);
3862536Sarutz #ifdef DEBUG
3872536Sarutz 	sbbc_dump_devid(dip, sbbcsoftp, instance);
3882536Sarutz #endif
3892536Sarutz 	/*
3902536Sarutz 	 * Read a hardware register to determine if we are executing on
3912536Sarutz 	 * a Starcat System Controller or a Starcat Domain.
3922536Sarutz 	 */
3932536Sarutz 	sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
3942536Sarutz 	    &sbbcsoftp->pci_sbbc_map->device_conf);
3952536Sarutz 
3962536Sarutz 	if (sbbc_id_reg & SBBC_SC_MODE) {
3972536Sarutz 		sbbc_scmode = TRUE;
3982536Sarutz 		SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d) nexus running "
3992536Sarutz 		    "in System Controller Mode.\n", instance);
4002536Sarutz 
4012536Sarutz 		/* initialize SBBC ASIC */
4022536Sarutz 		if (!sbbc_init(sbbcsoftp)) {
4032536Sarutz 			goto failed;
4042536Sarutz 		}
4052536Sarutz 	} else {
4062536Sarutz 		sbbc_scmode = FALSE;
4072536Sarutz 		SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d) nexus "
4082536Sarutz 		    "running in Domain Mode.\n", instance);
4092536Sarutz 
4102536Sarutz 		/* initialize SBBC ASIC before we unmap registers */
4112536Sarutz 		if (!sbbc_init(sbbcsoftp)) {
4122536Sarutz 			goto failed;
4132536Sarutz 		}
4142536Sarutz 
4152536Sarutz 		/*
4162536Sarutz 		 * Access to SBBC registers is no longer needed.  Unmap
4172536Sarutz 		 * the registers to conserve kernel virtual address space.
4182536Sarutz 		 */
4192536Sarutz 		SBBC_DBG1(SBBC_DBG_ATTACH, dip, "SBBC(%d): unmap "
4202536Sarutz 		    "SBBC registers\n", instance);
4212536Sarutz 		sbbc_remove_reg_maps(sbbcsoftp);
4222536Sarutz 		sbbcsoftp->pci_sbbc_map = NULL;
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	(void) sprintf(name, "sbbc%d", instance);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, name, S_IFCHR, instance, NULL,
4280Sstevel@tonic-gate 	    NULL) == DDI_FAILURE) {
4290Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
4302536Sarutz 		goto failed;
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	ddi_report_dev(dip);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attached successfully\n");
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	return (DDI_SUCCESS);
4380Sstevel@tonic-gate 
4392536Sarutz failed:
4400Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->sbbc_intr_mutex);
4410Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->umutex);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	sbbc_remove_reg_maps(sbbcsoftp);
4440Sstevel@tonic-gate 	kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
4450Sstevel@tonic-gate 	ddi_soft_state_free(sbbcsoft_statep, instance);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_ATTACH, dip, "Attach failed\n");
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	return (DDI_FAILURE);
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate static int
sbbc_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4530Sstevel@tonic-gate sbbc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	int		instance;
4560Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	SBBCTRACE(sbbc_detach, 'DETA', dip);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	switch (cmd) {
4630Sstevel@tonic-gate 	case DDI_DETACH:
4640Sstevel@tonic-gate 		break;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	case DDI_SUSPEND:
4670Sstevel@tonic-gate 		if (!(sbbcsoftp =
4680Sstevel@tonic-gate 		    ddi_get_soft_state(sbbcsoft_statep, instance))) {
4690Sstevel@tonic-gate 			cmn_err(CE_WARN,
4700Sstevel@tonic-gate 			    "sbbc_detach: unable to get softstate %p",
4710Sstevel@tonic-gate 			    (void *)sbbcsoftp);
4720Sstevel@tonic-gate 			return (DDI_FAILURE);
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 		mutex_enter(&sbbcsoftp->umutex);
4750Sstevel@tonic-gate 		if (sbbcsoftp->suspended) {
476*7656SSherry.Moore@Sun.COM 			mutex_exit(&sbbcsoftp->umutex);
477*7656SSherry.Moore@Sun.COM 			return (DDI_FAILURE);
4780Sstevel@tonic-gate 		}
4790Sstevel@tonic-gate 		sbbcsoftp->suspended = 1;
4800Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
4810Sstevel@tonic-gate 		return (DDI_SUCCESS);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	default:
4840Sstevel@tonic-gate 		return (DDI_FAILURE);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance))) {
4880Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc_detach: unable to get softstate %p",
4890Sstevel@tonic-gate 		    (void *)sbbcsoftp);
490*7656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	ddi_remove_minor_node(dip, NULL);
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->sbbc_intr_mutex);
4960Sstevel@tonic-gate 	mutex_destroy(&sbbcsoftp->umutex);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	sbbc_remove_reg_maps(sbbcsoftp);
4990Sstevel@tonic-gate 	kmem_free(sbbcsoftp->rangep, sbbcsoftp->range_len);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	ddi_soft_state_free(sbbcsoft_statep, instance);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	return (DDI_SUCCESS);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate /*
5090Sstevel@tonic-gate  * Translate child's address into parents.
5100Sstevel@tonic-gate  */
5110Sstevel@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)5120Sstevel@tonic-gate sbbc_busmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
5130Sstevel@tonic-gate 	    off_t off, off_t len, caddr_t *addrp)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
5160Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp, *child_regs;
5170Sstevel@tonic-gate 	pci_regspec_t pci_reg;
5180Sstevel@tonic-gate 	ddi_map_req_t p_map_request;
5190Sstevel@tonic-gate 	int rnumber, i, n;
5200Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
5210Sstevel@tonic-gate 	int instance;
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	SBBC_DBG4(SBBC_DBG_BUSMAP, dip,
5240Sstevel@tonic-gate 	    "mapping child %s, type %llx, off %llx, len %llx\n",
5250Sstevel@tonic-gate 	    ddi_driver_name(rdip), mp->map_type, off, len);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	SBBCTRACE(sbbc_busmap, 'BMAP', mp);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/*
5300Sstevel@tonic-gate 	 * Handle the mapping according to its type.
5310Sstevel@tonic-gate 	 */
5320Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
5330Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
534*7656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	switch (mp->map_type) {
5370Sstevel@tonic-gate 	case DDI_MT_REGSPEC:
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		/*
5400Sstevel@tonic-gate 		 * We assume the register specification is in sbbc format.
5410Sstevel@tonic-gate 		 * We must convert it into a PCI format regspec and pass
5420Sstevel@tonic-gate 		 * the request to our parent.
5430Sstevel@tonic-gate 		 */
5440Sstevel@tonic-gate 		child_rp = (sbbc_child_regspec_t *)mp->map_obj.rp;
5450Sstevel@tonic-gate 		break;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	case DDI_MT_RNUMBER:
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 		/*
5500Sstevel@tonic-gate 		 * map_type 0
5510Sstevel@tonic-gate 		 * Get the "reg" property from the device node and convert
5520Sstevel@tonic-gate 		 * it to our parent's format.
5530Sstevel@tonic-gate 		 */
5540Sstevel@tonic-gate 		rnumber = mp->map_obj.rnumber;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		/* get the requester's reg property */
557506Scth 		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
5580Sstevel@tonic-gate 		    "reg", (caddr_t)&child_regs, &i) != DDI_SUCCESS) {
5590Sstevel@tonic-gate 			cmn_err(CE_WARN,
5600Sstevel@tonic-gate 			    "SBBC: couldn't get %s ranges property %d",
5610Sstevel@tonic-gate 			    ddi_get_name(sbbcsoftp->dip), instance);
5620Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
5630Sstevel@tonic-gate 		}
5640Sstevel@tonic-gate 		n = i / sizeof (sbbc_child_regspec_t);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 		if (rnumber < 0 || rnumber >= n) {
5670Sstevel@tonic-gate 			kmem_free(child_regs, i);
5680Sstevel@tonic-gate 			return (DDI_ME_RNUMBER_RANGE);
5690Sstevel@tonic-gate 		}
5700Sstevel@tonic-gate 		child_rp = &child_regs[rnumber];
5710Sstevel@tonic-gate 		break;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	default:
5740Sstevel@tonic-gate 		return (DDI_ME_INVAL);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	/* Adjust our reg property with offset and length */
5790Sstevel@tonic-gate 	child_rp->addr_low += off;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	if (len)
5820Sstevel@tonic-gate 		child_rp->size = len;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/*
5850Sstevel@tonic-gate 	 * Combine this reg prop. into our parents PCI address using the ranges
5860Sstevel@tonic-gate 	 * property.
5870Sstevel@tonic-gate 	 */
5880Sstevel@tonic-gate 	rval = sbbc_apply_range(sbbcsoftp, rdip, child_rp, &pci_reg);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
5910Sstevel@tonic-gate 		kmem_free(child_regs, i);
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	if (rval != DDI_SUCCESS)
5940Sstevel@tonic-gate 		return (rval);
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	p_map_request = *mp;
5970Sstevel@tonic-gate 	p_map_request.map_type = DDI_MT_REGSPEC;
5980Sstevel@tonic-gate 	p_map_request.map_obj.rp = (struct regspec *)&pci_reg;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	/* Send it to PCI nexus to map into the PCI space */
6010Sstevel@tonic-gate 	rval = ddi_map(dip, &p_map_request, 0, 0, addrp);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	return (rval);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate /* new intr_ops structure */
6090Sstevel@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)6100Sstevel@tonic-gate sbbc_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
6110Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
6120Sstevel@tonic-gate {
613693Sgovinda 	int	ret = DDI_SUCCESS;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	switch (intr_op) {
6160Sstevel@tonic-gate 	case DDI_INTROP_GETCAP:
617693Sgovinda 		*(int *)result = DDI_INTR_FLAG_LEVEL;
6180Sstevel@tonic-gate 		break;
6190Sstevel@tonic-gate 	case DDI_INTROP_ALLOC:
6200Sstevel@tonic-gate 		*(int *)result = hdlp->ih_scratch1;
6210Sstevel@tonic-gate 		break;
6220Sstevel@tonic-gate 	case DDI_INTROP_FREE:
6230Sstevel@tonic-gate 		break;
6240Sstevel@tonic-gate 	case DDI_INTROP_GETPRI:
625693Sgovinda 		if (hdlp->ih_pri == 0) {
626693Sgovinda 			hdlp->ih_pri = 0x1;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d assigning default interrupt "
629693Sgovinda 			    "level %d for device %s%d", ddi_driver_name(dip),
630693Sgovinda 			    ddi_get_instance(dip), hdlp->ih_pri,
631693Sgovinda 			    ddi_driver_name(rdip), ddi_get_instance(rdip));
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate 
634693Sgovinda 		*(int *)result = hdlp->ih_pri;
635693Sgovinda 
6360Sstevel@tonic-gate 		break;
6370Sstevel@tonic-gate 	case DDI_INTROP_ADDISR:
6380Sstevel@tonic-gate 		ret = sbbc_add_intr_impl(dip, rdip, intr_op, hdlp, result);
6390Sstevel@tonic-gate 		break;
6400Sstevel@tonic-gate 	case DDI_INTROP_REMISR:
6410Sstevel@tonic-gate 		ret = sbbc_remove_intr_impl(dip, rdip, intr_op, hdlp, result);
6420Sstevel@tonic-gate 		break;
6430Sstevel@tonic-gate 	case DDI_INTROP_ENABLE:
6440Sstevel@tonic-gate 		ret = sbbc_update_intr_state(dip, rdip, intr_op, hdlp, &result);
6450Sstevel@tonic-gate 		break;
6460Sstevel@tonic-gate 	case DDI_INTROP_DISABLE:
6470Sstevel@tonic-gate 		ret = sbbc_update_intr_state(dip, rdip, intr_op, hdlp, &result);
6480Sstevel@tonic-gate 		break;
6490Sstevel@tonic-gate 	case DDI_INTROP_NINTRS:
6500Sstevel@tonic-gate 	case DDI_INTROP_NAVAIL:
6512580Sanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip);
6520Sstevel@tonic-gate 		break;
6530Sstevel@tonic-gate 	case DDI_INTROP_SUPPORTED_TYPES:
6540Sstevel@tonic-gate 		/* PCI nexus driver supports only fixed interrupts */
6552580Sanish 		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
6560Sstevel@tonic-gate 		    DDI_INTR_TYPE_FIXED : 0;
6570Sstevel@tonic-gate 		break;
6580Sstevel@tonic-gate 	default:
6590Sstevel@tonic-gate 		ret = DDI_ENOTSUP;
6600Sstevel@tonic-gate 		break;
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	return (ret);
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 
6670Sstevel@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)6680Sstevel@tonic-gate sbbc_add_intr_impl(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
6690Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	sbbcsoft_t *sbbcsoftp;
6720Sstevel@tonic-gate 	sbbc_child_intr_t *childintr;
6730Sstevel@tonic-gate 	int instance, i, rval = DDI_SUCCESS;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip,
6760Sstevel@tonic-gate 	    "add: rdip 0x%llx hdlp 0x%llx\n", rdip, hdlp);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	/* insert the sbbc isr wrapper instead */
6790Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
6800Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
6810Sstevel@tonic-gate 		return (DDI_FAILURE);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	childintr = kmem_zalloc(sizeof (struct sbbc_child_intr), KM_SLEEP);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	childintr->name = ddi_get_name(rdip);
6860Sstevel@tonic-gate 	childintr->inum = hdlp->ih_inum;
6870Sstevel@tonic-gate 	childintr->intr_handler = hdlp->ih_cb_func;
6880Sstevel@tonic-gate 	childintr->arg1 = hdlp->ih_cb_arg1;
6890Sstevel@tonic-gate 	childintr->arg2 = hdlp->ih_cb_arg2;
6900Sstevel@tonic-gate 	childintr->status = SBBC_INTR_STATE_DISABLE;
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
6930Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i] == 0) {
6940Sstevel@tonic-gate 			sbbcsoftp->child_intr[i] = childintr;
6950Sstevel@tonic-gate 			break;
6960Sstevel@tonic-gate 		}
6970Sstevel@tonic-gate 	}
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp,
7000Sstevel@tonic-gate 	    (ddi_intr_handler_t *)sbbc_intr_wrapper,
7010Sstevel@tonic-gate 	    (caddr_t)sbbcsoftp, NULL);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if ((rval = i_ddi_intr_ops(dip, rdip, intr_op,
7040Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
7050Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to add intr for %s",
7060Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7070Sstevel@tonic-gate 		kmem_free(childintr, sizeof (struct sbbc_child_intr));
7080Sstevel@tonic-gate 		sbbcsoftp->child_intr[i] = NULL;
7090Sstevel@tonic-gate 	}
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/*
7120Sstevel@tonic-gate 	 * Restore original interrupt handler
7130Sstevel@tonic-gate 	 * and arguments in interrupt handle.
7140Sstevel@tonic-gate 	 */
7150Sstevel@tonic-gate 	DDI_INTR_ASSIGN_HDLR_N_ARGS(hdlp, childintr->intr_handler,
7160Sstevel@tonic-gate 	    childintr->arg1, childintr->arg2);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	return (rval);
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate 
7210Sstevel@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)7220Sstevel@tonic-gate sbbc_remove_intr_impl(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7230Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
7240Sstevel@tonic-gate {
7250Sstevel@tonic-gate 	sbbcsoft_t *sbbcsoftp;
7260Sstevel@tonic-gate 	sbbc_child_intr_t *childintr;
7270Sstevel@tonic-gate 	int instance, i, rval = DDI_SUCCESS;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip,
7300Sstevel@tonic-gate 	    "remove: rdip 0x%llx hdlp 0x%llx\n", rdip, hdlp);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
7330Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
7340Sstevel@tonic-gate 		return (DDI_FAILURE);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	/* remove the sbbc isr wrapper instead */
7370Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
7380Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i]) {
7390Sstevel@tonic-gate 			childintr = sbbcsoftp->child_intr[i];
7400Sstevel@tonic-gate 			if (childintr->status == SBBC_INTR_STATE_DISABLE &&
7410Sstevel@tonic-gate 			    childintr->name == ddi_get_name(rdip)) {
7420Sstevel@tonic-gate 				/* put back child's inum */
7430Sstevel@tonic-gate 				hdlp->ih_inum = childintr->inum;
7440Sstevel@tonic-gate 				break;
7450Sstevel@tonic-gate 			}
7460Sstevel@tonic-gate 		}
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (i >= MAX_SBBC_DEVICES) {
7500Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d:obound failed to remove intr for %s",
7510Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7520Sstevel@tonic-gate 		return (DDI_FAILURE);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	if ((rval = i_ddi_intr_ops(dip, rdip, intr_op,
7560Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
7570Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to remove intr for %s",
7580Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7590Sstevel@tonic-gate 		return (rval);
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	kmem_free(childintr, sizeof (struct sbbc_child_intr));
7630Sstevel@tonic-gate 	sbbcsoftp->child_intr[i] = NULL;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	return (rval);
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 
7690Sstevel@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)7700Sstevel@tonic-gate sbbc_update_intr_state(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
7710Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
7720Sstevel@tonic-gate {
7730Sstevel@tonic-gate 	sbbcsoft_t		*sbbcsoftp;
7740Sstevel@tonic-gate 	sbbc_child_intr_t	*childintr;
7750Sstevel@tonic-gate 	int			instance, i;
7760Sstevel@tonic-gate 	int			ret = DDI_SUCCESS;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	SBBC_DBG2(SBBC_DBG_INTR, dip, "sbbc_update_intr_state: "
7790Sstevel@tonic-gate 	    "rdip 0x%llx hdlp 0x%llx state 0x%x\n", rdip, hdlp);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
7820Sstevel@tonic-gate 	if (!(sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, instance)))
7830Sstevel@tonic-gate 		return (DDI_FAILURE);
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
7860Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i]) {
7870Sstevel@tonic-gate 			childintr = sbbcsoftp->child_intr[i];
7880Sstevel@tonic-gate 			if (childintr->name == ddi_get_name(rdip))
7890Sstevel@tonic-gate 				break;
7900Sstevel@tonic-gate 		}
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	if (i >= MAX_SBBC_DEVICES) {
7940Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to update intr state for %s",
7950Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
7960Sstevel@tonic-gate 		return (DDI_FAILURE);
7970Sstevel@tonic-gate 	}
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	if ((ret = i_ddi_intr_ops(dip, rdip, intr_op,
8000Sstevel@tonic-gate 	    hdlp, result)) != DDI_SUCCESS) {
8010Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc%d: failed to update intr state for %s",
8020Sstevel@tonic-gate 		    instance, ddi_get_name(rdip));
8030Sstevel@tonic-gate 		return (ret);
8040Sstevel@tonic-gate 	}
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	/* Update the interrupt state */
8070Sstevel@tonic-gate 	childintr->status = (intr_op == DDI_INTROP_ENABLE) ?
8080Sstevel@tonic-gate 	    SBBC_INTR_STATE_ENABLE : SBBC_INTR_STATE_DISABLE;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	return (ret);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate /*
8150Sstevel@tonic-gate  * This entry point is called before a child's probe or attach is called.
8160Sstevel@tonic-gate  * The arg pointer points to child's dev_info_t structure.
8170Sstevel@tonic-gate  */
8180Sstevel@tonic-gate static int
sbbc_ctlops(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t op,void * arg,void * result)8190Sstevel@tonic-gate sbbc_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op,
8200Sstevel@tonic-gate 	    void *arg, void *result)
8210Sstevel@tonic-gate {
8220Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp;
8230Sstevel@tonic-gate 	int i, n;
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	SBBC_DBG3(SBBC_DBG_CTLOPS, dip,
8260Sstevel@tonic-gate 	    "Initializing %s, arg %x, op %x\n",
8270Sstevel@tonic-gate 	    ddi_driver_name(rdip), arg, op);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	SBBCTRACE(sbbc_ctlops, 'CTLO', arg);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	switch (op) {
8320Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD: {
8330Sstevel@tonic-gate 		return (sbbc_initchild(dip, rdip, (dev_info_t *)arg));
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD: {
8370Sstevel@tonic-gate 		return (sbbc_uninitchild(rdip, (dev_info_t *)arg));
8380Sstevel@tonic-gate 	}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
8430Sstevel@tonic-gate 		    ddi_driver_name(rdip), ddi_get_instance(rdip),
8440Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
8450Sstevel@tonic-gate 		    ddi_get_name_addr(rdip));
8460Sstevel@tonic-gate 		return (DDI_SUCCESS);
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 		if (getprop(rdip, "reg", &child_rp, &i) != DDI_SUCCESS) {
8510Sstevel@tonic-gate 			return (DDI_FAILURE);
8520Sstevel@tonic-gate 		}
8530Sstevel@tonic-gate 		n = i / sizeof (sbbc_child_regspec_t);
8540Sstevel@tonic-gate 		if (*(int *)arg < 0 || *(int *)arg >= n) {
8550Sstevel@tonic-gate 			kmem_free(child_rp, i);
8560Sstevel@tonic-gate 			return (DDI_FAILURE);
8570Sstevel@tonic-gate 		}
8580Sstevel@tonic-gate 		*((off_t *)result) = child_rp[*(int *)arg].size;
8590Sstevel@tonic-gate 		kmem_free(child_rp, i);
8600Sstevel@tonic-gate 		return (DDI_SUCCESS);
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 		if (getprop(rdip, "reg", &child_rp, &i) != DDI_SUCCESS) {
8650Sstevel@tonic-gate 			return (DDI_FAILURE);
8660Sstevel@tonic-gate 		}
8670Sstevel@tonic-gate 		*((uint_t *)result) = i / sizeof (sbbc_child_regspec_t);
8680Sstevel@tonic-gate 		kmem_free(child_rp, i);
8690Sstevel@tonic-gate 		return (DDI_SUCCESS);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	/*
8730Sstevel@tonic-gate 	 * Now pass the request up to our parent.
8740Sstevel@tonic-gate 	 */
8750Sstevel@tonic-gate 	SBBC_DBG0(SBBC_DBG_CTLOPS, dip, "Calling ddi_ctlops\n");
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	return (ddi_ctlops(dip, rdip, op, arg, result));
8780Sstevel@tonic-gate }
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate  * The following routine uses ranges property, that was read earlier, and
8830Sstevel@tonic-gate  * takes child's reg property, and computes the complete address and size
8840Sstevel@tonic-gate  * for the PCI parent to map.
8850Sstevel@tonic-gate  */
8860Sstevel@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)8870Sstevel@tonic-gate sbbc_apply_range(struct sbbcsoft *sbbc_p, dev_info_t *rdip,
8880Sstevel@tonic-gate     sbbc_child_regspec_t *child_rp, pci_regspec_t *rp)
8890Sstevel@tonic-gate {
8900Sstevel@tonic-gate 	int b;
8910Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
8920Sstevel@tonic-gate 	struct sbbc_pci_rangespec *rangep = sbbc_p->rangep;
8930Sstevel@tonic-gate 	int nrange = sbbc_p->range_cnt;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	SBBC_DBG4(SBBC_DBG_MAPRANGES, rdip,
8960Sstevel@tonic-gate 	    "Applying ranges for %s, rangep %llx, child_rp %llx, range %x\n",
8970Sstevel@tonic-gate 	    ddi_driver_name(rdip), sbbc_p->rangep, child_rp, nrange);
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	SBBCTRACE(sbbc_apply_range, 'APPL', sbbc_p);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	for (b = 0; b < nrange; ++b, ++rangep) {
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		/* Make sure the correct range is being mapped */
9040Sstevel@tonic-gate 		if (child_rp->addr_hi == rangep->sbbc_phys_hi)
9050Sstevel@tonic-gate 			/* See if we fit in this range */
9060Sstevel@tonic-gate 			if ((child_rp->addr_low >=
9070Sstevel@tonic-gate 			    rangep->sbbc_phys_low) &&
9080Sstevel@tonic-gate 			    ((child_rp->addr_low + child_rp->size - 1)
909*7656SSherry.Moore@Sun.COM 			    <= (rangep->sbbc_phys_low +
910*7656SSherry.Moore@Sun.COM 			    rangep->rng_size - 1))) {
9110Sstevel@tonic-gate 				uint_t addr_offset = child_rp->addr_low -
9120Sstevel@tonic-gate 				    rangep->sbbc_phys_low;
9130Sstevel@tonic-gate 				/*
9140Sstevel@tonic-gate 				 * Use the range entry to translate
9150Sstevel@tonic-gate 				 * the SBBC physical address into the
9160Sstevel@tonic-gate 				 * parents PCI space.
9170Sstevel@tonic-gate 				 */
9180Sstevel@tonic-gate 				rp->pci_phys_hi =
9190Sstevel@tonic-gate 				    rangep->pci_phys_hi;
9200Sstevel@tonic-gate 				rp->pci_phys_mid = rangep->pci_phys_mid;
9210Sstevel@tonic-gate 				rp->pci_phys_low =
9220Sstevel@tonic-gate 				    rangep->pci_phys_low + addr_offset;
9230Sstevel@tonic-gate 				rp->pci_size_hi = 0;
9240Sstevel@tonic-gate 				rp->pci_size_low =
9250Sstevel@tonic-gate 				    min(child_rp->size, (rangep->rng_size -
926*7656SSherry.Moore@Sun.COM 				    addr_offset));
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 				break;
9290Sstevel@tonic-gate 			}
9300Sstevel@tonic-gate 	}
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	if (b == nrange)  {
9330Sstevel@tonic-gate 		cmn_err(CE_WARN, "out_of_range %s", ddi_get_name(rdip));
9340Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	return (rval);
9380Sstevel@tonic-gate }
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate  * The following routine reads sbbc's ranges property from OBP and sets up
9430Sstevel@tonic-gate  * its soft structure with it.
9440Sstevel@tonic-gate  */
9450Sstevel@tonic-gate static int
sbbc_get_ranges(struct sbbcsoft * sbbcsoftp)9460Sstevel@tonic-gate sbbc_get_ranges(struct sbbcsoft *sbbcsoftp)
9470Sstevel@tonic-gate {
9480Sstevel@tonic-gate 	struct sbbc_pci_rangespec *rangep;
9490Sstevel@tonic-gate 	int range_len, nrange;
9500Sstevel@tonic-gate 
951506Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, sbbcsoftp->dip, DDI_PROP_DONTPASS,
9520Sstevel@tonic-gate 	    "ranges", (caddr_t)&rangep, &range_len) != DDI_SUCCESS) {
9530Sstevel@tonic-gate 		cmn_err(CE_WARN, "SBBC: couldn't get %s ranges property %d",
9540Sstevel@tonic-gate 		    ddi_get_name(sbbcsoftp->dip), sbbcsoftp->instance);
9550Sstevel@tonic-gate 		return (DDI_ME_REGSPEC_RANGE);
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	nrange = range_len / sizeof (struct sbbc_pci_rangespec);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	if (!nrange) {
9610Sstevel@tonic-gate 		kmem_free(rangep, range_len);
9620Sstevel@tonic-gate 		return (DDI_FAILURE);
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 	/* setup the soft structure with ranges info. */
9660Sstevel@tonic-gate 	sbbcsoftp->rangep = rangep;
9670Sstevel@tonic-gate 	sbbcsoftp->range_cnt = nrange;
9680Sstevel@tonic-gate 	sbbcsoftp->range_len = range_len;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	return (DDI_SUCCESS);
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate /*
9750Sstevel@tonic-gate  * Configure the SBBC for PCI
9760Sstevel@tonic-gate  */
9770Sstevel@tonic-gate static int
sbbc_config4pci(struct sbbcsoft * sbbcsoftp)9780Sstevel@tonic-gate sbbc_config4pci(struct sbbcsoft *sbbcsoftp)
9790Sstevel@tonic-gate {
9800Sstevel@tonic-gate 	ddi_acc_handle_t conf_handle;
9810Sstevel@tonic-gate 	uint16_t comm, vendid, devid, stat;
9820Sstevel@tonic-gate 	uint8_t revid;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate #ifdef DEBUG
9850Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
9860Sstevel@tonic-gate 		cmn_err(CE_CONT,
9870Sstevel@tonic-gate 		    "sbbc_config4pci: sbbcsoftp %p\n", (void *)sbbcsoftp);
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate #endif
9900Sstevel@tonic-gate 	if (pci_config_setup(sbbcsoftp->dip, &conf_handle) != DDI_SUCCESS)
9910Sstevel@tonic-gate 		return (1);
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	vendid = pci_config_get16(conf_handle, PCI_CONF_VENID);
9940Sstevel@tonic-gate 	devid = pci_config_get16(conf_handle, PCI_CONF_DEVID);
9950Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM);
9960Sstevel@tonic-gate 	stat = pci_config_get16(conf_handle, PCI_CONF_STAT);
9970Sstevel@tonic-gate 	revid = pci_config_get8(conf_handle, PCI_CONF_REVID);
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate #ifdef DEBUG
10000Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
10010Sstevel@tonic-gate 		cmn_err(CE_CONT,
10020Sstevel@tonic-gate 		    "SBBC vendid %x, devid %x, comm %x, stat %x, revid %x\n",
10030Sstevel@tonic-gate 		    vendid, devid, comm, stat, revid);
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate #endif
10060Sstevel@tonic-gate 	comm = (PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_SERR_ENABLE |
1007*7656SSherry.Moore@Sun.COM 	    PCI_COMM_PARITY_DETECT);
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	pci_config_put16(conf_handle, PCI_CONF_COMM, comm);
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	comm = pci_config_get16(conf_handle, PCI_CONF_COMM);
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate #ifdef DEBUG
10140Sstevel@tonic-gate 	if (sbbc_dbg_flags & SBBC_DBG_PCICONF) {
10150Sstevel@tonic-gate 		cmn_err(CE_CONT, "comm %x\n", comm);
10160Sstevel@tonic-gate 	}
10170Sstevel@tonic-gate #endif
10180Sstevel@tonic-gate 	pci_config_teardown(&conf_handle);
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	return (0);
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate /* ARGSUSED0 */
10250Sstevel@tonic-gate int
sbbc_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)10260Sstevel@tonic-gate sbbc_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
10270Sstevel@tonic-gate {
10280Sstevel@tonic-gate 	dev_t	dev = (dev_t)arg;
10290Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
10300Sstevel@tonic-gate 	int	instance, ret;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	instance = getminor(dev);
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	SBBCTRACE(sbbc_getinfo, 'GINF', instance);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	switch (infocmd) {
10370Sstevel@tonic-gate 		case DDI_INFO_DEVT2DEVINFO:
10380Sstevel@tonic-gate 			sbbcsoftp = (struct sbbcsoft *)
10394207Szk194757 			    ddi_get_soft_state(sbbcsoft_statep, instance);
10404207Szk194757 			if (sbbcsoftp == NULL) {
10414207Szk194757 				*result = (void *) NULL;
10424207Szk194757 				ret = DDI_FAILURE;
10434207Szk194757 			} else {
10444207Szk194757 				*result = sbbcsoftp->dip;
10454207Szk194757 				ret = DDI_SUCCESS;
10464207Szk194757 			}
10470Sstevel@tonic-gate 			break;
10480Sstevel@tonic-gate 		case DDI_INFO_DEVT2INSTANCE:
1049931Smathue 			*result = (void *)(uintptr_t)instance;
10500Sstevel@tonic-gate 			ret = DDI_SUCCESS;
10510Sstevel@tonic-gate 			break;
10520Sstevel@tonic-gate 		default:
10530Sstevel@tonic-gate 			ret = DDI_FAILURE;
10540Sstevel@tonic-gate 			break;
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	return (ret);
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate /*ARGSUSED1*/
10610Sstevel@tonic-gate static int
sbbc_open(dev_t * dev,int flag,int otype,cred_t * credp)10620Sstevel@tonic-gate sbbc_open(dev_t *dev, int flag, int otype, cred_t *credp)
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
10650Sstevel@tonic-gate 	int		instance;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	/* check privilege of caller process */
10680Sstevel@tonic-gate 	if (drv_priv(credp)) {
10690Sstevel@tonic-gate 		return (EPERM);
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	instance = getminor(*dev);
10730Sstevel@tonic-gate 	if (instance < 0)
10740Sstevel@tonic-gate 		return (ENXIO);
10750Sstevel@tonic-gate 	sbbcsoftp = (struct sbbcsoft *)ddi_get_soft_state(sbbcsoft_statep,
1076*7656SSherry.Moore@Sun.COM 	    instance);
10770Sstevel@tonic-gate 	SBBCTRACE(sbbc_open, 'OPEN', sbbcsoftp);
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	if (sbbcsoftp == NULL)
10800Sstevel@tonic-gate 		return (ENXIO);
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->umutex);
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	/* check for exclusive access */
10850Sstevel@tonic-gate 	if ((sbbcsoftp->oflag == TRUE)) {
10860Sstevel@tonic-gate 		mutex_exit(&sbbcsoftp->umutex);
10870Sstevel@tonic-gate 		return (EBUSY);
10880Sstevel@tonic-gate 	}
10890Sstevel@tonic-gate 	sbbcsoftp->oflag = TRUE;
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->umutex);
10920Sstevel@tonic-gate 
10930Sstevel@tonic-gate 	return (0);
10940Sstevel@tonic-gate }
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate /*ARGSUSED1*/
10970Sstevel@tonic-gate static int
sbbc_close(dev_t dev,int flag,int otype,cred_t * credp)10980Sstevel@tonic-gate sbbc_close(dev_t dev, int flag, int otype, cred_t *credp)
10990Sstevel@tonic-gate {
11000Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
11010Sstevel@tonic-gate 	int		instance;
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	instance = getminor(dev);
11040Sstevel@tonic-gate 	if (instance < 0)
11050Sstevel@tonic-gate 		return (ENXIO);
11060Sstevel@tonic-gate 	sbbcsoftp = (struct sbbcsoft *)ddi_get_soft_state(sbbcsoft_statep,
1107*7656SSherry.Moore@Sun.COM 	    instance);
11080Sstevel@tonic-gate 	/* wait till all output activity has ceased */
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->umutex);
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	SBBCTRACE(sbbc_close, 'CLOS', sbbcsoftp);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	sbbcsoftp->oflag = FALSE;
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->umutex);
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	return (0);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate /*ARGSUSED2*/
11220Sstevel@tonic-gate static int
sbbc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)11230Sstevel@tonic-gate sbbc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
11240Sstevel@tonic-gate 		int *rvalp)
11250Sstevel@tonic-gate {
11260Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp;
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	SBBCTRACE(sbbc_ioctl, 'IOCT', arg);
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	sbbcsoftp = ddi_get_soft_state(sbbcsoft_statep, getminor(dev));
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	if (sbbcsoftp == NULL) {
11330Sstevel@tonic-gate 		return (ENXIO);
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	switch (cmd) {
11370Sstevel@tonic-gate 	case SBBC_SBBCREG_WR:
11380Sstevel@tonic-gate 		{
11390Sstevel@tonic-gate 		struct ssc_sbbc_regio sbbcregs;
11400Sstevel@tonic-gate 		uint64_t offset;
11410Sstevel@tonic-gate 
11422536Sarutz 		if (sbbc_scmode == FALSE) {
11432536Sarutz 			/* then we're executing on Domain; Writes not allowed */
11440Sstevel@tonic-gate 			return (EINVAL);
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 		if (arg == NULL) {
11480Sstevel@tonic-gate 			return (ENXIO);
11490Sstevel@tonic-gate 		}
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate 		if (ddi_copyin((caddr_t)arg, (caddr_t)&sbbcregs,
11520Sstevel@tonic-gate 				    sizeof (struct ssc_sbbc_regio), mode)) {
11530Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl: copyin failed arg %p",
11540Sstevel@tonic-gate 			    (void *)arg);
11550Sstevel@tonic-gate 			return (EFAULT);
11560Sstevel@tonic-gate 		}
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 		/*
11590Sstevel@tonic-gate 		 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
11600Sstevel@tonic-gate 		 *		reads or writes
11610Sstevel@tonic-gate 		 * Note that I've also added a check to make sure the offset is
11620Sstevel@tonic-gate 		 * valid, since misaligned (i.e. not on 16-byte boundary)
11630Sstevel@tonic-gate 		 * accesses or accesses to "Reserved" register offsets are
11640Sstevel@tonic-gate 		 * treated as unmapped by the SBBC.
11650Sstevel@tonic-gate 		 */
11660Sstevel@tonic-gate 		if ((sbbcregs.len != 4) ||
11670Sstevel@tonic-gate 		    !sbbc_offset_valid(sbbcregs.offset)) {
11680Sstevel@tonic-gate 			return (EINVAL);
11690Sstevel@tonic-gate 		}
11700Sstevel@tonic-gate 
11712536Sarutz 		offset = (uint64_t)sbbcsoftp->pci_sbbc_map;
11722536Sarutz 		offset += sbbcregs.offset;
11732536Sarutz 		ddi_put32(sbbcsoftp->pci_sbbc_map_handle, (uint32_t *)offset,
1174*7656SSherry.Moore@Sun.COM 		    sbbcregs.value);
11752536Sarutz 		}
11762536Sarutz 		break;
11772536Sarutz 	case SBBC_SBBCREG_RD:
11782536Sarutz 		{
11792536Sarutz 		struct ssc_sbbc_regio sbbcregs;
11802536Sarutz 		uint64_t offset;
11812536Sarutz 
11822536Sarutz 		if (sbbc_scmode == FALSE) {
11832536Sarutz 			/* then we're executing on Domain; Reads not allowed */
11842536Sarutz 			return (EINVAL);
11852536Sarutz 		}
11862536Sarutz 
11872536Sarutz 		if (arg == NULL) {
11882536Sarutz 			return (ENXIO);
11892536Sarutz 		}
11902536Sarutz 
11912536Sarutz 		if (ddi_copyin((caddr_t)arg, (caddr_t)&sbbcregs,
11922536Sarutz 				    sizeof (struct ssc_sbbc_regio), mode)) {
11932536Sarutz 			cmn_err(CE_WARN, "sbbc_ioctl: copyin failed arg %p",
11942536Sarutz 			    (void *)arg);
11952536Sarutz 			return (EFAULT);
11962536Sarutz 		}
11972536Sarutz 
11982536Sarutz 		/*
11992536Sarutz 		 * Bug #4287186: SBBC driver on cp1500 doesn't check length for
12002536Sarutz 		 *		reads or writes
12012536Sarutz 		 * Note that I've also added a check to make sure the offset is
12022536Sarutz 		 * valid, since misaligned (i.e. not on 16-byte boundary)
12032536Sarutz 		 * accesses or accesses to "Reserved" register offsets are
12042536Sarutz 		 * treated as unmapped by the SBBC.
12052536Sarutz 		 */
12062536Sarutz 		if ((sbbcregs.len != 4) ||
12072536Sarutz 		    !sbbc_offset_valid(sbbcregs.offset)) {
12082536Sarutz 			return (EINVAL);
12092536Sarutz 		}
12102536Sarutz 
12112536Sarutz 		offset = (uint64_t)sbbcsoftp->pci_sbbc_map;
12120Sstevel@tonic-gate 		offset += sbbcregs.offset;
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		sbbcregs.value = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
1215*7656SSherry.Moore@Sun.COM 		    (uint32_t *)offset);
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)&sbbcregs.value,
1218*7656SSherry.Moore@Sun.COM 		    &((struct ssc_sbbc_regio *)arg)->value,
1219*7656SSherry.Moore@Sun.COM 		    sbbcregs.len, mode)) {
12200Sstevel@tonic-gate 			cmn_err(CE_WARN, "sbbc_ioctl:copyout failed arg %p",
12210Sstevel@tonic-gate 			    (void *)arg);
12220Sstevel@tonic-gate 			return (EFAULT);
12230Sstevel@tonic-gate 		}
12240Sstevel@tonic-gate 		}
12250Sstevel@tonic-gate 		break;
12260Sstevel@tonic-gate 	default:
12270Sstevel@tonic-gate 		cmn_err(CE_WARN, "sbbc_ioctl:Illegal command 0x%08x", cmd);
12280Sstevel@tonic-gate 		return (ENOTTY);
12290Sstevel@tonic-gate 	}
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 	return (DDI_SUCCESS);
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate static void
sbbc_remove_reg_maps(struct sbbcsoft * sbbcsoftp)12350Sstevel@tonic-gate sbbc_remove_reg_maps(struct sbbcsoft *sbbcsoftp)
12360Sstevel@tonic-gate {
12370Sstevel@tonic-gate 	SBBCTRACE(sbbc_remove_reg_maps, 'RMAP', sbbcsoftp);
12380Sstevel@tonic-gate 	if (sbbcsoftp->pci_sbbc_map_handle)
12390Sstevel@tonic-gate 		ddi_regs_map_free(&sbbcsoftp->pci_sbbc_map_handle);
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 
12430Sstevel@tonic-gate static int
sbbc_init(struct sbbcsoft * sbbcsoftp)12440Sstevel@tonic-gate sbbc_init(struct sbbcsoft *sbbcsoftp)
12450Sstevel@tonic-gate {
12462536Sarutz 	/* Mask all the interrupts until we are ready. */
12470Sstevel@tonic-gate 	ddi_put32(sbbcsoftp->pci_sbbc_map_handle,
12482536Sarutz 	    &sbbcsoftp->pci_sbbc_map->sys_intr_enable,
12490Sstevel@tonic-gate 	    0x00000000);
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	return (1);
12520Sstevel@tonic-gate }
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate /*
12550Sstevel@tonic-gate  * The following routine is a generic routine to initialize any child of
12560Sstevel@tonic-gate  * sbbc nexus driver information into parent private data structure.
12570Sstevel@tonic-gate  */
12580Sstevel@tonic-gate /* ARGSUSED0 */
12590Sstevel@tonic-gate static int
sbbc_initchild(dev_info_t * dip,dev_info_t * rdip,dev_info_t * child)12600Sstevel@tonic-gate sbbc_initchild(dev_info_t *dip, dev_info_t *rdip, dev_info_t *child)
12610Sstevel@tonic-gate {
12620Sstevel@tonic-gate 	sbbc_child_regspec_t *child_rp;
12630Sstevel@tonic-gate 	int reglen, slot;
12640Sstevel@tonic-gate 	char name[10];
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_INITCHILD, dip, "Initializing %s\n",
12670Sstevel@tonic-gate 	    ddi_driver_name(rdip));
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	/*
12700Sstevel@tonic-gate 	 * Initialize a child
12710Sstevel@tonic-gate 	 * Set the address portion of the node name based on the
12720Sstevel@tonic-gate 	 * address/offset.
12730Sstevel@tonic-gate 	 */
1274506Scth 	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
12750Sstevel@tonic-gate 	    "reg", (caddr_t)&child_rp, &reglen) != DDI_SUCCESS) {
12760Sstevel@tonic-gate 		if (strcmp(ddi_node_name(child), "hotplug-controller") == 0) {
12770Sstevel@tonic-gate 			slot = 1;
12780Sstevel@tonic-gate 			(void) sprintf(name, "%x", slot);
12790Sstevel@tonic-gate 			ddi_set_name_addr(child, name);
12800Sstevel@tonic-gate 			return (DDI_SUCCESS);
12810Sstevel@tonic-gate 		}
12820Sstevel@tonic-gate 		return (DDI_FAILURE);
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	SBBC_DBG3(SBBC_DBG_INITCHILD, dip, "hi 0x%x, low 0x%x, size 0x%x\n",
12860Sstevel@tonic-gate 	    child_rp->addr_hi, child_rp->addr_low, child_rp->size);
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	(void) sprintf(name, "%x,%x", child_rp->addr_hi, child_rp->addr_low);
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	/*
12910Sstevel@tonic-gate 	 * set child's addresses from the reg property into parent private
12920Sstevel@tonic-gate 	 * data structure.
12930Sstevel@tonic-gate 	 */
12940Sstevel@tonic-gate 	ddi_set_name_addr(child, name);
12950Sstevel@tonic-gate 	kmem_free(child_rp, reglen);
12960Sstevel@tonic-gate 
12970Sstevel@tonic-gate 	ddi_set_parent_data(child, NULL);
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	return (DDI_SUCCESS);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 
13030Sstevel@tonic-gate /* ARGSUSED0 */
13040Sstevel@tonic-gate static int
sbbc_uninitchild(dev_info_t * rdip,dev_info_t * child)13050Sstevel@tonic-gate sbbc_uninitchild(dev_info_t *rdip, dev_info_t *child)
13060Sstevel@tonic-gate {
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_UNINITCHILD, rdip, "Uninitializing %s\n",
13090Sstevel@tonic-gate 	    ddi_driver_name(rdip));
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
13120Sstevel@tonic-gate 	ddi_remove_minor_node(child, NULL);
13130Sstevel@tonic-gate 	impl_rem_dev_props(child);
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate 	return (DDI_SUCCESS);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate /*
13210Sstevel@tonic-gate  * The following routine is an interrupt service routine that is used
13220Sstevel@tonic-gate  * as a wrapper to all the children requiring interrupt services.
13230Sstevel@tonic-gate  */
13240Sstevel@tonic-gate static uint_t
sbbc_intr_wrapper(caddr_t arg)13250Sstevel@tonic-gate sbbc_intr_wrapper(caddr_t arg)
13260Sstevel@tonic-gate {
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	struct sbbcsoft *sbbcsoftp = (struct sbbcsoft *)arg;
13290Sstevel@tonic-gate 	int i, rval;
13300Sstevel@tonic-gate 
13310Sstevel@tonic-gate 	SBBC_DBG1(SBBC_DBG_INTR, sbbcsoftp->dip, "Isr arg 0x%llx\n", arg);
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	mutex_enter(&sbbcsoftp->sbbc_intr_mutex);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	for (i = 0; i < MAX_SBBC_DEVICES; i++) {
13360Sstevel@tonic-gate 		/*
13370Sstevel@tonic-gate 		 * Check the interrupt status reg. to determine the cause.
13380Sstevel@tonic-gate 		 */
13390Sstevel@tonic-gate 		/*
13400Sstevel@tonic-gate 		 * Check the error status reg. to determine the cause.
13410Sstevel@tonic-gate 		 */
13420Sstevel@tonic-gate 		if (sbbcsoftp->child_intr[i] &&
13430Sstevel@tonic-gate 		    sbbcsoftp->child_intr[i]->status ==
13440Sstevel@tonic-gate 		    SBBC_INTR_STATE_ENABLE) {
13450Sstevel@tonic-gate 			/*
13460Sstevel@tonic-gate 			 * Dispatch the children interrupt service routines and
13470Sstevel@tonic-gate 			 * look for someone to claim.
13480Sstevel@tonic-gate 			 */
13490Sstevel@tonic-gate 			rval = sbbcsoftp->child_intr[i]->intr_handler(
13500Sstevel@tonic-gate 			    sbbcsoftp->child_intr[i]->arg1,
13510Sstevel@tonic-gate 			    sbbcsoftp->child_intr[i]->arg2);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 			if (rval == DDI_INTR_CLAIMED) {
13540Sstevel@tonic-gate 				mutex_exit(&sbbcsoftp->sbbc_intr_mutex);
13550Sstevel@tonic-gate 				return (rval);
13560Sstevel@tonic-gate 			}
13570Sstevel@tonic-gate 		}
13580Sstevel@tonic-gate 	}
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	mutex_exit(&sbbcsoftp->sbbc_intr_mutex);
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	/* for now do not claim since we know its not enabled */
13630Sstevel@tonic-gate 	return (DDI_INTR_UNCLAIMED);
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate /*
13680Sstevel@tonic-gate  * This function checks an SBBC register offset to make sure that it is properly
13690Sstevel@tonic-gate  * aligned (i.e. on a 16-byte boundary) and that it corresponds to an accessible
13700Sstevel@tonic-gate  * register.  Since the SBBC treates accesses to unaligned or reserved addresses
13710Sstevel@tonic-gate  * as unmapped, failing to check for these would leave a loophole that could be
13720Sstevel@tonic-gate  * used to crash the system.
13730Sstevel@tonic-gate  */
13740Sstevel@tonic-gate static int
sbbc_offset_valid(uint32_t offset)13750Sstevel@tonic-gate sbbc_offset_valid(uint32_t offset) {
13760Sstevel@tonic-gate 	/*
13770Sstevel@tonic-gate 	 * Check for proper alignment first.
13780Sstevel@tonic-gate 	 */
13790Sstevel@tonic-gate 	if ((offset % 16) != 0) {
13800Sstevel@tonic-gate 		return (0);
13810Sstevel@tonic-gate 	}
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	/*
13840Sstevel@tonic-gate 	 * Now start checking for the various reserved ranges.
13850Sstevel@tonic-gate 	 * While sticking a bunch of constants in the code (rather than
13860Sstevel@tonic-gate 	 * #define'd values) is usually best avoided, it would probably
13870Sstevel@tonic-gate 	 * do more harm than good here.  These values were taken from the
13880Sstevel@tonic-gate 	 * Serengeti Architecture Programmer's Reference Manual dated
13890Sstevel@tonic-gate 	 * August 10, 1999, pages 2-99 through 2-103.  While there are
13900Sstevel@tonic-gate 	 * various "clever" ways this check could be performed that would
13910Sstevel@tonic-gate 	 * be slightly more efficient, arranging the code in this fashion
13920Sstevel@tonic-gate 	 * should maximize maintainability.
13930Sstevel@tonic-gate 	 */
13940Sstevel@tonic-gate 	if (((offset >= 0x001a0) && (offset <= 0x001ff)) ||
13950Sstevel@tonic-gate 	    ((offset >= 0x002a0) && (offset <= 0x002ff)) ||
13960Sstevel@tonic-gate 	    ((offset >= 0x00350) && (offset <= 0x003ff)) ||
13970Sstevel@tonic-gate 	    ((offset >= 0x00500) && (offset <= 0x00fff)) ||
13980Sstevel@tonic-gate 	    ((offset >= 0x01160) && (offset <= 0x011ff)) ||
13990Sstevel@tonic-gate 	    ((offset >= 0x01210) && (offset <= 0x017ff)) ||
14000Sstevel@tonic-gate 	    ((offset >= 0x01810) && (offset <= 0x01fff)) ||
14010Sstevel@tonic-gate 	    ((offset >= 0x02030) && (offset <= 0x022ff)) ||
14020Sstevel@tonic-gate 	    ((offset >= 0x02340) && (offset <= 0x03fff)) ||
14030Sstevel@tonic-gate 	    ((offset >= 0x04030) && (offset <= 0x05fff)) ||
14040Sstevel@tonic-gate 	    ((offset >= 0x060a0) && (offset <= 0x060ff)) ||
14050Sstevel@tonic-gate 	    (offset == 0x06120) ||
14060Sstevel@tonic-gate 	    ((offset >= 0x06190) && (offset <= 0x061ff)) ||
14070Sstevel@tonic-gate 	    ((offset >= 0x06230) && (offset <= 0x062f0)) ||
14080Sstevel@tonic-gate 	    (offset > 0x06320)) {
14090Sstevel@tonic-gate 		return (0);
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 	return (1);
14130Sstevel@tonic-gate }
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate #ifdef DEBUG
14160Sstevel@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)14170Sstevel@tonic-gate sbbc_dbg(uint32_t flag, dev_info_t *dip, char *fmt,
14180Sstevel@tonic-gate 	uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5)
14190Sstevel@tonic-gate {
14200Sstevel@tonic-gate 	char *s = NULL;
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 	if (sbbc_dbg_flags && ((sbbc_dbg_flags & flag) == flag)) {
14230Sstevel@tonic-gate 		switch (flag) {
14240Sstevel@tonic-gate 		case SBBC_DBG_ATTACH:
14250Sstevel@tonic-gate 			s = "attach";
14260Sstevel@tonic-gate 			break;
14270Sstevel@tonic-gate 		case SBBC_DBG_DETACH:
14280Sstevel@tonic-gate 			s = "detach";
14290Sstevel@tonic-gate 			break;
14300Sstevel@tonic-gate 		case SBBC_DBG_CTLOPS:
14310Sstevel@tonic-gate 			s = "ctlops";
14320Sstevel@tonic-gate 			break;
14330Sstevel@tonic-gate 		case SBBC_DBG_INITCHILD:
14340Sstevel@tonic-gate 			s = "initchild";
14350Sstevel@tonic-gate 			break;
14360Sstevel@tonic-gate 		case SBBC_DBG_UNINITCHILD:
14370Sstevel@tonic-gate 			s = "uninitchild";
14380Sstevel@tonic-gate 			break;
14390Sstevel@tonic-gate 		case SBBC_DBG_BUSMAP:
14400Sstevel@tonic-gate 			s = "busmap";
14410Sstevel@tonic-gate 			break;
14420Sstevel@tonic-gate 		case SBBC_DBG_INTR:
14430Sstevel@tonic-gate 			s = "intr";
14440Sstevel@tonic-gate 			break;
14450Sstevel@tonic-gate 		case SBBC_DBG_INTROPS:
14460Sstevel@tonic-gate 			s = "intr_ops";
14470Sstevel@tonic-gate 			break;
14480Sstevel@tonic-gate 		case SBBC_DBG_PCICONF:
14490Sstevel@tonic-gate 			s = "pciconfig";
14500Sstevel@tonic-gate 			break;
14510Sstevel@tonic-gate 		case SBBC_DBG_MAPRANGES:
14520Sstevel@tonic-gate 			s = "mapranges";
14530Sstevel@tonic-gate 			break;
14540Sstevel@tonic-gate 		case SBBC_DBG_PROPERTIES:
14550Sstevel@tonic-gate 			s = "properties";
14560Sstevel@tonic-gate 			break;
14570Sstevel@tonic-gate 		case SBBC_DBG_OPEN:
14580Sstevel@tonic-gate 			s = "open";
14590Sstevel@tonic-gate 			break;
14600Sstevel@tonic-gate 		case SBBC_DBG_CLOSE:
14610Sstevel@tonic-gate 			s = "close";
14620Sstevel@tonic-gate 			break;
14630Sstevel@tonic-gate 		case SBBC_DBG_IOCTL:
14640Sstevel@tonic-gate 			s = "ioctl";
14650Sstevel@tonic-gate 			break;
14660Sstevel@tonic-gate 		default:
14670Sstevel@tonic-gate 			s = "Unknown debug flag";
14680Sstevel@tonic-gate 			break;
14690Sstevel@tonic-gate 		}
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s_%s(%d): ", ddi_driver_name(dip), s,
1472*7656SSherry.Moore@Sun.COM 		    ddi_get_instance(dip));
14730Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate 
14772536Sarutz /*
14782536Sarutz  * Dump the SBBC chip's Device ID Register
14792536Sarutz  */
sbbc_dump_devid(dev_info_t * dip,struct sbbcsoft * sbbcsoftp,int instance)14802536Sarutz static void sbbc_dump_devid(dev_info_t *dip, struct sbbcsoft *sbbcsoftp,
14812536Sarutz 	int instance)
14822536Sarutz {
14832536Sarutz 	uint32_t sbbc_id_reg;
14842536Sarutz 	uint16_t sbbc_id_reg_partid;
14852536Sarutz 	uint16_t sbbc_id_reg_manfid;
14862536Sarutz 
14872536Sarutz 	sbbc_id_reg = ddi_get32(sbbcsoftp->pci_sbbc_map_handle,
14882536Sarutz 	    (uint32_t *)&sbbcsoftp->pci_sbbc_map->devid);
14892536Sarutz 
14902536Sarutz 	sbbc_id_reg_partid = ((sbbc_id_reg << 4) >> 16);
14912536Sarutz 	sbbc_id_reg_manfid = ((sbbc_id_reg << 20) >> 21);
14922536Sarutz 
14932536Sarutz 	SBBC_DBG4(SBBC_DBG_ATTACH, dip,
14942536Sarutz 	    "FOUND SBBC(%d) Version %x, Partid %x, Manfid %x\n",
14952536Sarutz 	    instance, (sbbc_id_reg >> 28), sbbc_id_reg_partid,
14962536Sarutz 	    sbbc_id_reg_manfid);
14972536Sarutz }
14982536Sarutz 
14990Sstevel@tonic-gate #endif /* DEBUG */
1500