xref: /onnv-gate/usr/src/uts/common/io/pshot.c (revision 10702:ca0edf2daf1c)
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
52155Scth  * Common Development and Distribution License (the "License").
62155Scth  * 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 /*
228639SVikram.Hegde@Sun.COM  * Copyright 2009 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  * pseudo bus nexus driver
280Sstevel@tonic-gate  * hotplug framework test facility
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * The pshot driver can be used to exercise the i/o framework together
330Sstevel@tonic-gate  * with devfs by configuring an arbitrarily complex device tree.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * The pshot driver is rooted at /devices/pshot.  The following commands
360Sstevel@tonic-gate  * illustrate the operation of devfs together with pshot's bus_config.
370Sstevel@tonic-gate  * The first command demonstrates that, like the magician showing there's
380Sstevel@tonic-gate  * nothing up his sleeve, /devices/pshot is empty.  The second command
390Sstevel@tonic-gate  * conjures up a branch of pshot nodes.  Note that pshot's bus_config is
400Sstevel@tonic-gate  * called sequentially by devfs for each node, as part of the pathname
410Sstevel@tonic-gate  * resolution, and that each pshot node is fully configured and
420Sstevel@tonic-gate  * attached before that node's bus_config is called to configure the
430Sstevel@tonic-gate  * next child down the tree.  The final result is a "disk" node configured
440Sstevel@tonic-gate  * at the bottom of the named hierarchy of pshot nodes.
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  *	#
470Sstevel@tonic-gate  *	# ls /devices/pshot
480Sstevel@tonic-gate  *	#
490Sstevel@tonic-gate  *	# ls -ld /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
500Sstevel@tonic-gate  *	drwxr-xr-x   2 root     sys          512 Feb  6 15:10
510Sstevel@tonic-gate  *		/devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  * pshot supports some unique behaviors as aids for test error cases.
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * Match these special address formats to behavior:
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  *	err.*		- induce bus_config error
580Sstevel@tonic-gate  *	delay		- induce 1 second of bus_config delay time
590Sstevel@tonic-gate  *	delay,n		- induce n seconds of bus_config delay time
600Sstevel@tonic-gate  *	wait		- induce 1 second of bus_config wait time
610Sstevel@tonic-gate  *	wait,n		- induce n seconds of bus_config wait time
620Sstevel@tonic-gate  *	failinit.*	- induce error at INITCHILD
630Sstevel@tonic-gate  *	failprobe.*	- induce error at probe
640Sstevel@tonic-gate  *	failattach.*	- induce error at attach
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
680Sstevel@tonic-gate #define	DEBUG	1
690Sstevel@tonic-gate #endif
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #include <sys/types.h>
720Sstevel@tonic-gate #include <sys/cmn_err.h>
730Sstevel@tonic-gate #include <sys/conf.h>
740Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
750Sstevel@tonic-gate #include <sys/autoconf.h>
760Sstevel@tonic-gate #include <sys/open.h>
770Sstevel@tonic-gate #include <sys/stat.h>
780Sstevel@tonic-gate #include <sys/file.h>
790Sstevel@tonic-gate #include <sys/errno.h>
800Sstevel@tonic-gate #include <sys/systm.h>
810Sstevel@tonic-gate #include <sys/modctl.h>
820Sstevel@tonic-gate #include <sys/kmem.h>
830Sstevel@tonic-gate #include <sys/ddi.h>
840Sstevel@tonic-gate #include <sys/sunddi.h>
850Sstevel@tonic-gate #include <sys/sunndi.h>
860Sstevel@tonic-gate #include <sys/devctl.h>
870Sstevel@tonic-gate #include <sys/disp.h>
880Sstevel@tonic-gate #include <sys/utsname.h>
890Sstevel@tonic-gate #include <sys/pshot.h>
900Sstevel@tonic-gate #include <sys/debug.h>
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static int pshot_log		= 0;
930Sstevel@tonic-gate static int pshot_devctl_debug	= 0;
940Sstevel@tonic-gate static int pshot_debug_busy	= 0;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate static void *pshot_softstatep;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate static int pshot_prop_autoattach;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #define	MAXPWR	3
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate /*
1040Sstevel@tonic-gate  * device configuration data
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /* should keep in sync with current release */
1080Sstevel@tonic-gate static struct {
1090Sstevel@tonic-gate 	char *name;
1100Sstevel@tonic-gate 	char *val;
1110Sstevel@tonic-gate } pshot_nodetypes[] = {
1120Sstevel@tonic-gate 	{"DDI_NT_SERIAL", DDI_NT_SERIAL},
1130Sstevel@tonic-gate 	{"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB},
1140Sstevel@tonic-gate 	{"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO},
1150Sstevel@tonic-gate 	{"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO},
1160Sstevel@tonic-gate 	{"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON},
1170Sstevel@tonic-gate 	{"DDI_NT_BLOCK", DDI_NT_BLOCK},
1180Sstevel@tonic-gate 	{"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN},
1190Sstevel@tonic-gate 	{"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN},
120*9249SJaven.Wu@Sun.COM 	{"DDI_NT_BLOCK_SAS", DDI_NT_BLOCK_SAS},
1210Sstevel@tonic-gate 	{"DDI_NT_CD", DDI_NT_CD},
1220Sstevel@tonic-gate 	{"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN},
1230Sstevel@tonic-gate 	{"DDI_NT_FD", DDI_NT_FD},
1240Sstevel@tonic-gate 	{"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE},
1250Sstevel@tonic-gate 	{"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE},
1260Sstevel@tonic-gate 	{"DDI_NT_TAPE", DDI_NT_TAPE},
1270Sstevel@tonic-gate 	{"DDI_NT_NET", DDI_NT_NET},
1280Sstevel@tonic-gate 	{"DDI_NT_DISPLAY", DDI_NT_DISPLAY},
1290Sstevel@tonic-gate 	{"DDI_PSEUDO", DDI_PSEUDO},
1300Sstevel@tonic-gate 	{"DDI_NT_AUDIO", DDI_NT_AUDIO},
1310Sstevel@tonic-gate 	{"DDI_NT_MOUSE", DDI_NT_MOUSE},
1320Sstevel@tonic-gate 	{"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD},
1330Sstevel@tonic-gate 	{"DDI_NT_PARALLEL", DDI_NT_PARALLEL},
1340Sstevel@tonic-gate 	{"DDI_NT_PRINTER", DDI_NT_PRINTER},
1350Sstevel@tonic-gate 	{"DDI_NT_UGEN", DDI_NT_UGEN},
1360Sstevel@tonic-gate 	{"DDI_NT_NEXUS", DDI_NT_NEXUS},
1370Sstevel@tonic-gate 	{"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS},
1380Sstevel@tonic-gate 	{"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT},
1390Sstevel@tonic-gate 	{"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT},
1400Sstevel@tonic-gate 	{"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT},
1410Sstevel@tonic-gate 	{"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT},
1420Sstevel@tonic-gate 	{"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT},
1430Sstevel@tonic-gate 	{"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT},
1440Sstevel@tonic-gate 	{"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC},
1450Sstevel@tonic-gate 	{"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC},
1460Sstevel@tonic-gate 	{"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH},
1470Sstevel@tonic-gate 	{ NULL, NULL }
1480Sstevel@tonic-gate };
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate /* Node name */
1510Sstevel@tonic-gate static char *pshot_compat_diskname = "cdisk";
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /* Compatible names... */
1540Sstevel@tonic-gate static char *pshot_compat_psramdisks[] = {
1550Sstevel@tonic-gate 	"psramhead",
1560Sstevel@tonic-gate 	"psramrom",
1570Sstevel@tonic-gate 	"psramdisk",
1580Sstevel@tonic-gate 	"psramd",
1590Sstevel@tonic-gate 	"psramwhat"
1600Sstevel@tonic-gate };
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate /*
1630Sstevel@tonic-gate  * devices "natively" supported by pshot (i.e. included with SUNWiotu)
1640Sstevel@tonic-gate  * used to initialize pshot_devices with
1650Sstevel@tonic-gate  */
1660Sstevel@tonic-gate static pshot_device_t pshot_stock_devices[] = {
1670Sstevel@tonic-gate 	{"disk",	DDI_NT_BLOCK,		"gen_drv"},
1680Sstevel@tonic-gate 	{"disk_chan",	DDI_NT_BLOCK_CHAN,	"gen_drv"},
1690Sstevel@tonic-gate 	{"disk_wwn",	DDI_NT_BLOCK_WWN,	"gen_drv"},
1700Sstevel@tonic-gate 	{"disk_cdrom",	DDI_NT_CD,		"gen_drv"},
1710Sstevel@tonic-gate 	{"disk_cdrom.chan", DDI_NT_CD_CHAN,	"gen_drv"},
1720Sstevel@tonic-gate /* Note: use bad_drv to force attach errors */
1730Sstevel@tonic-gate 	{"disk_fd",	DDI_NT_FD,		"bad_drv"},
1740Sstevel@tonic-gate 	{"tape",	DDI_NT_TAPE,		"gen_drv"},
1750Sstevel@tonic-gate 	{"net",		DDI_NT_NET,		"gen_drv"},
1760Sstevel@tonic-gate 	{"display",	DDI_NT_DISPLAY,		"gen_drv"},
1770Sstevel@tonic-gate 	{"pseudo",	DDI_PSEUDO,		"gen_drv"},
1780Sstevel@tonic-gate 	{"audio",	DDI_NT_AUDIO,		"gen_drv"},
1790Sstevel@tonic-gate 	{"mouse",	DDI_NT_MOUSE,		"gen_drv"},
1800Sstevel@tonic-gate 	{"keyboard",	DDI_NT_KEYBOARD,	"gen_drv"},
1810Sstevel@tonic-gate 	{"nexus",	DDI_NT_NEXUS,		"pshot"}
1820Sstevel@tonic-gate };
1830Sstevel@tonic-gate #define	PSHOT_N_STOCK_DEVICES \
1840Sstevel@tonic-gate 	(sizeof (pshot_stock_devices) / sizeof (pshot_device_t))
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate static pshot_device_t *pshot_devices = NULL;
1870Sstevel@tonic-gate static size_t pshot_devices_len = 0;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /* protects <pshot_devices>, <pshot_devices_len> */
1900Sstevel@tonic-gate static kmutex_t pshot_devices_lock;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate  * event testing
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static ndi_event_definition_t pshot_ndi_event_defs[] = {
1980Sstevel@tonic-gate { PSHOT_EVENT_TAG_OFFLINE, PSHOT_EVENT_NAME_DEV_OFFLINE,
1990Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate { PSHOT_EVENT_TAG_DEV_RESET, PSHOT_EVENT_NAME_DEV_RESET,
2020Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_RESET, PSHOT_EVENT_NAME_BUS_RESET,
2050Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_QUIESCE, PSHOT_EVENT_NAME_BUS_QUIESCE,
2080Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_UNQUIESCE, PSHOT_EVENT_NAME_BUS_UNQUIESCE,
2110Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate { PSHOT_EVENT_TAG_TEST_POST, PSHOT_EVENT_NAME_BUS_TEST_POST,
2140Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }
2150Sstevel@tonic-gate };
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate #define	PSHOT_N_NDI_EVENTS \
2190Sstevel@tonic-gate 	(sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t))
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate #ifdef DEBUG
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events[] = {
2240Sstevel@tonic-gate { 10, "test event 0", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2250Sstevel@tonic-gate { 11, "test event 1", EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
2260Sstevel@tonic-gate { 12, "test event 2", EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
2270Sstevel@tonic-gate { 13, "test event 3", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2280Sstevel@tonic-gate { 14, "test event 4", EPL_KERNEL, NDI_EVENT_POST_TO_ALL},
2290Sstevel@tonic-gate { 15, "test event 5", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2300Sstevel@tonic-gate { 16, "test event 6", EPL_KERNEL, NDI_EVENT_POST_TO_ALL },
2310Sstevel@tonic-gate { 17, "test event 7", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }
2320Sstevel@tonic-gate };
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events_high[] = {
2350Sstevel@tonic-gate { 20, "test event high 0", EPL_HIGHLEVEL, NDI_EVENT_POST_TO_ALL}
2360Sstevel@tonic-gate };
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate #define	PSHOT_N_TEST_EVENTS \
2390Sstevel@tonic-gate 	(sizeof (pshot_test_events)/sizeof (ndi_event_definition_t))
2400Sstevel@tonic-gate #endif
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate struct register_events {
2430Sstevel@tonic-gate 	char		*event_name;
2440Sstevel@tonic-gate 	ddi_eventcookie_t event_cookie;
2450Sstevel@tonic-gate 	void	(*event_callback)
2460Sstevel@tonic-gate 			(dev_info_t *,
2470Sstevel@tonic-gate 			ddi_eventcookie_t,
2480Sstevel@tonic-gate 			void *arg,
2490Sstevel@tonic-gate 			void *impldata);
2500Sstevel@tonic-gate 	ddi_callback_id_t cb_id;
2510Sstevel@tonic-gate };
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate struct register_events pshot_register_events[] = {
2540Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 },
2550Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 },
2560Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 },
2570Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 },
2580Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 },
2590Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 }
2600Sstevel@tonic-gate };
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate #define	PSHOT_N_DDI_EVENTS \
2630Sstevel@tonic-gate 	(sizeof (pshot_register_events) / sizeof (struct register_events))
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate #ifdef DEBUG
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate static struct register_events pshot_register_test[] = {
2690Sstevel@tonic-gate { "test event 0", 0, pshot_event_cb_test, 0},
2700Sstevel@tonic-gate { "test event 1", 0, pshot_event_cb_test, 0},
2710Sstevel@tonic-gate { "test event 2", 0, pshot_event_cb_test, 0},
2720Sstevel@tonic-gate { "test event 3", 0, pshot_event_cb_test, 0},
2730Sstevel@tonic-gate { "test event 4", 0, pshot_event_cb_test, 0},
2740Sstevel@tonic-gate { "test event 5", 0, pshot_event_cb_test, 0},
2750Sstevel@tonic-gate { "test event 6", 0, pshot_event_cb_test, 0},
2760Sstevel@tonic-gate { "test event 7", 0, pshot_event_cb_test, 0}
2770Sstevel@tonic-gate };
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate static struct register_events pshot_register_high_test[] = {
2810Sstevel@tonic-gate 	{"test event high 0", 0, pshot_event_cb_test, 0}
2820Sstevel@tonic-gate };
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate #endif /* DEBUG */
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate static struct {
2870Sstevel@tonic-gate 	int ioctl_int;
2880Sstevel@tonic-gate 	char *ioctl_char;
2890Sstevel@tonic-gate } pshot_devctls[] = {
2900Sstevel@tonic-gate 	{DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"},
2910Sstevel@tonic-gate 	{DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"},
2920Sstevel@tonic-gate 	{DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"},
2930Sstevel@tonic-gate 	{DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"},
2940Sstevel@tonic-gate 	{DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"},
2950Sstevel@tonic-gate 	{DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"},
2960Sstevel@tonic-gate 	{DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"},
2970Sstevel@tonic-gate 	{DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"},
2980Sstevel@tonic-gate 	{0, NULL}
2990Sstevel@tonic-gate };
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate static struct bus_ops pshot_bus_ops = {
3020Sstevel@tonic-gate 	BUSO_REV,			/* busops_rev */
3030Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
3040Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
3050Sstevel@tonic-gate 	NULL,				/* bus_add_interspec */
3060Sstevel@tonic-gate 	NULL,				/* bus_remove_interspec */
3070Sstevel@tonic-gate 	i_ddi_map_fault,		/* bus_map_fault */
30885Scth 	ddi_dma_map,			/* bus_dma_map */
30985Scth 	ddi_dma_allochdl,		/* bus_dma_allochdl */
31085Scth 	ddi_dma_freehdl,		/* bus_dma_freehdl */
31185Scth 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
31285Scth 	ddi_dma_unbindhdl,		/* bus_dma_unbindhdl */
31385Scth 	ddi_dma_flush,			/* bus_dma_flush */
31485Scth 	ddi_dma_win,			/* bus_dma_win */
31585Scth 	ddi_dma_mctl,			/* bus_dma_ctl */
3160Sstevel@tonic-gate 	pshot_ctl,			/* bus_ctl */
3170Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
3180Sstevel@tonic-gate 	pshot_get_eventcookie,		/* bus_get_eventcookie */
3190Sstevel@tonic-gate 	pshot_add_eventcall,		/* bus_add_eventcall */
3200Sstevel@tonic-gate 	pshot_remove_eventcall,		/* bus_remove_event */
3210Sstevel@tonic-gate 	pshot_post_event,		/* bus_post_event */
3220Sstevel@tonic-gate 	NULL,				/* bus_intr_ctl */
3230Sstevel@tonic-gate 	pshot_bus_config,		/* bus_config */
3240Sstevel@tonic-gate 	pshot_bus_unconfig,		/* bus_unconfig */
3250Sstevel@tonic-gate 	NULL,				/* bus_fm_init */
3260Sstevel@tonic-gate 	NULL,				/* bus_fm_fini */
3270Sstevel@tonic-gate 	NULL,				/* bus_fm_access_enter */
3280Sstevel@tonic-gate 	NULL,				/* bus_fm_access_exit */
3290Sstevel@tonic-gate 	pshot_bus_power,		/* bus_power */
3300Sstevel@tonic-gate 	pshot_bus_introp		/* bus_intr_op */
3310Sstevel@tonic-gate };
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate static struct cb_ops pshot_cb_ops = {
3340Sstevel@tonic-gate 	pshot_open,			/* open */
3350Sstevel@tonic-gate 	pshot_close,			/* close */
3360Sstevel@tonic-gate 	nodev,				/* strategy */
3370Sstevel@tonic-gate 	nodev,				/* print */
3380Sstevel@tonic-gate 	nodev,				/* dump */
3390Sstevel@tonic-gate 	nodev,				/* read */
3400Sstevel@tonic-gate 	nodev,				/* write */
3410Sstevel@tonic-gate 	pshot_ioctl,			/* ioctl */
3420Sstevel@tonic-gate 	nodev,				/* devmap */
3430Sstevel@tonic-gate 	nodev,				/* mmap */
3440Sstevel@tonic-gate 	nodev,				/* segmap */
3450Sstevel@tonic-gate 	nochpoll,			/* poll */
3460Sstevel@tonic-gate 	ddi_prop_op,			/* prop_op */
3470Sstevel@tonic-gate 	NULL,				/* streamtab */
3480Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* flags */
3490Sstevel@tonic-gate 	CB_REV,				/* cb_rev */
3500Sstevel@tonic-gate 	nodev,				/* aread */
3510Sstevel@tonic-gate 	nodev,				/* awrite */
3520Sstevel@tonic-gate };
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate static struct dev_ops pshot_ops = {
3550Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
3560Sstevel@tonic-gate 	0,			/* refcnt  */
3570Sstevel@tonic-gate 	pshot_info,		/* getinfo */
3580Sstevel@tonic-gate 	nulldev,		/* identify */
3590Sstevel@tonic-gate 	pshot_probe,		/* probe */
3600Sstevel@tonic-gate 	pshot_attach,		/* attach */
3610Sstevel@tonic-gate 	pshot_detach,		/* detach */
3620Sstevel@tonic-gate 	nodev,			/* reset */
3630Sstevel@tonic-gate 	&pshot_cb_ops,		/* driver operations */
3640Sstevel@tonic-gate 	&pshot_bus_ops,		/* bus operations */
3657656SSherry.Moore@Sun.COM 	pshot_power,		/* power */
3667656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate };
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * Module linkage information for the kernel.
3730Sstevel@tonic-gate  */
3740Sstevel@tonic-gate static struct modldrv modldrv = {
3750Sstevel@tonic-gate 	&mod_driverops,
3767656SSherry.Moore@Sun.COM 	"pshotnex",
3770Sstevel@tonic-gate 	&pshot_ops,
3780Sstevel@tonic-gate };
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate static struct modlinkage modlinkage = {
3810Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
3820Sstevel@tonic-gate };
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate  * pshot_devices is set up on the first attach and destroyed on fini
3870Sstevel@tonic-gate  *
3880Sstevel@tonic-gate  * therefore PSHOT_PROP_DEV* properties may be set just for the root device,
3890Sstevel@tonic-gate  * instead of being set globably, in pshot.conf by specifying the properties
3900Sstevel@tonic-gate  * on a single line in the form:
3910Sstevel@tonic-gate  *	name="pshot" parent="/" <dev props ..>
3920Sstevel@tonic-gate  * to unclutter a device tree snapshot.
3930Sstevel@tonic-gate  * this of course produces a long single line that may wrap around several
3940Sstevel@tonic-gate  * times on screen
3950Sstevel@tonic-gate  */
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate int
_init(void)3980Sstevel@tonic-gate _init(void)
3990Sstevel@tonic-gate {
4000Sstevel@tonic-gate 	int rv;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	rv = ddi_soft_state_init(&pshot_softstatep, sizeof (pshot_t), 0);
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (rv != DDI_SUCCESS)
4050Sstevel@tonic-gate 		return (rv);
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	mutex_init(&pshot_devices_lock, NULL, MUTEX_DRIVER, NULL);
4080Sstevel@tonic-gate 	pshot_devices = NULL;
4090Sstevel@tonic-gate 	pshot_devices_len = 0;
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	if ((rv = mod_install(&modlinkage)) != 0) {
4120Sstevel@tonic-gate 		ddi_soft_state_fini(&pshot_softstatep);
4130Sstevel@tonic-gate 		mutex_destroy(&pshot_devices_lock);
4140Sstevel@tonic-gate 	}
4150Sstevel@tonic-gate 	return (rv);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate int
_fini(void)4190Sstevel@tonic-gate _fini(void)
4200Sstevel@tonic-gate {
4210Sstevel@tonic-gate 	int rv;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	if ((rv = mod_remove(&modlinkage)) != 0)
4240Sstevel@tonic-gate 		return (rv);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	ddi_soft_state_fini(&pshot_softstatep);
4270Sstevel@tonic-gate 	mutex_destroy(&pshot_devices_lock);
4280Sstevel@tonic-gate 	if (pshot_devices)
4290Sstevel@tonic-gate 		pshot_devices_free(pshot_devices, pshot_devices_len);
4300Sstevel@tonic-gate 	return (0);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4340Sstevel@tonic-gate _info(struct modinfo *modinfop)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate /*ARGSUSED*/
4410Sstevel@tonic-gate static int
pshot_probe(dev_info_t * devi)4420Sstevel@tonic-gate pshot_probe(dev_info_t *devi)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	int	instance = ddi_get_instance(devi);
4450Sstevel@tonic-gate 	char	*bus_addr;
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/*
4480Sstevel@tonic-gate 	 * Hook for tests to force probe fail
4490Sstevel@tonic-gate 	 */
4500Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
4510Sstevel@tonic-gate 	    &bus_addr) == DDI_PROP_SUCCESS) {
4520Sstevel@tonic-gate 		if (strncmp(bus_addr, "failprobe", 9) == 0) {
4530Sstevel@tonic-gate 			if (pshot_debug)
4540Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: "
4550Sstevel@tonic-gate 				    "%s forced probe failure\n",
4560Sstevel@tonic-gate 				    instance, bus_addr);
4570Sstevel@tonic-gate 			ddi_prop_free(bus_addr);
4580Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
4590Sstevel@tonic-gate 		}
4600Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate /*ARGSUSED*/
4680Sstevel@tonic-gate static int
pshot_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4690Sstevel@tonic-gate pshot_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
4700Sstevel@tonic-gate {
4710Sstevel@tonic-gate 	int instance;
4720Sstevel@tonic-gate 	minor_t minor;
4730Sstevel@tonic-gate 	pshot_t *pshot;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	minor = getminor((dev_t)arg);
4760Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(minor);
4770Sstevel@tonic-gate 	switch (infocmd) {
4780Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
4790Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
4800Sstevel@tonic-gate 		if (pshot == NULL) {
4810Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot_info: get soft state failed "
4820Sstevel@tonic-gate 			    "on minor %u, instance %d", minor, instance);
4830Sstevel@tonic-gate 			return (DDI_FAILURE);
4840Sstevel@tonic-gate 		}
4850Sstevel@tonic-gate 		*result = (void *)pshot->dip;
4860Sstevel@tonic-gate 		break;
4870Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
4880Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
4890Sstevel@tonic-gate 		break;
4900Sstevel@tonic-gate 	default:
4910Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_info: unrecognized cmd 0x%x on "
4920Sstevel@tonic-gate 		    "minor %u, instance %d", infocmd, minor, instance);
4930Sstevel@tonic-gate 		return (DDI_FAILURE);
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	return (DDI_SUCCESS);
4970Sstevel@tonic-gate }
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate static int
pshot_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)5010Sstevel@tonic-gate pshot_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	int instance = ddi_get_instance(devi);
5040Sstevel@tonic-gate 	pshot_t *pshot;
5050Sstevel@tonic-gate 	int rval, i;
5060Sstevel@tonic-gate 	int prop_flags = DDI_PROP_DONTPASS | DDI_PROP_NOTPROM;
5070Sstevel@tonic-gate 	char *bus_addr;
5080Sstevel@tonic-gate 	char *pm_comp[] = {
5090Sstevel@tonic-gate 		"NAME=bus",
5100Sstevel@tonic-gate 		"0=B3",
5110Sstevel@tonic-gate 		"1=B2",
5120Sstevel@tonic-gate 		"2=B1",
5130Sstevel@tonic-gate 		"3=B0"};
5140Sstevel@tonic-gate 	char *pm_hw_state = {"needs-suspend-resume"};
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	pshot_prop_autoattach = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
5170Sstevel@tonic-gate 	    prop_flags, "autoattach", 0);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	switch (cmd) {
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	case DDI_ATTACH:
5220Sstevel@tonic-gate 		if (pshot_debug)
5230Sstevel@tonic-gate 			cmn_err(CE_CONT, "attach: %s%d/pshot%d\n",
5247656SSherry.Moore@Sun.COM 			    ddi_get_name(ddi_get_parent(devi)),
5257656SSherry.Moore@Sun.COM 			    ddi_get_instance(ddi_get_parent(devi)),
5267656SSherry.Moore@Sun.COM 			    instance);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		/*
5290Sstevel@tonic-gate 		 * Hook for tests to force attach fail
5300Sstevel@tonic-gate 		 */
5310Sstevel@tonic-gate 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
5320Sstevel@tonic-gate 		    &bus_addr) == DDI_PROP_SUCCESS) && bus_addr != NULL) {
5330Sstevel@tonic-gate 			if (strncmp(bus_addr, "failattach", 10) == 0) {
5340Sstevel@tonic-gate 				if (pshot_debug)
5350Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: "
5360Sstevel@tonic-gate 					    "%s forced attach failure\n",
5370Sstevel@tonic-gate 					    instance, bus_addr);
5380Sstevel@tonic-gate 				ddi_prop_free(bus_addr);
5390Sstevel@tonic-gate 				return (DDI_FAILURE);
5400Sstevel@tonic-gate 			}
5410Sstevel@tonic-gate 			ddi_prop_free(bus_addr);
5420Sstevel@tonic-gate 		}
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		/*
5450Sstevel@tonic-gate 		 * minor nodes setup
5460Sstevel@tonic-gate 		 */
5470Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(pshot_softstatep, instance) !=
5480Sstevel@tonic-gate 		    DDI_SUCCESS) {
5490Sstevel@tonic-gate 			return (DDI_FAILURE);
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
5520Sstevel@tonic-gate 		pshot->dip = devi;
5530Sstevel@tonic-gate 		pshot->instance = instance;
5540Sstevel@tonic-gate 		mutex_init(&pshot->lock, NULL, MUTEX_DRIVER, NULL);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 		/* set each minor, then create on dip all together */
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 		i = PSHOT_NODENUM_DEVCTL;
5590Sstevel@tonic-gate 		pshot->nodes[i].pshot = pshot;
5600Sstevel@tonic-gate 		pshot->nodes[i].minor = pshot_minor_encode(instance, i);
5610Sstevel@tonic-gate 		(void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_DEVCTL,
5620Sstevel@tonic-gate 		    PSHOT_MAX_MINOR_NAMELEN);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 		i = PSHOT_NODENUM_TESTCTL;
5650Sstevel@tonic-gate 		pshot->nodes[i].pshot = pshot;
5660Sstevel@tonic-gate 		pshot->nodes[i].minor = pshot_minor_encode(instance, i);
5670Sstevel@tonic-gate 		(void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_TESTCTL,
5680Sstevel@tonic-gate 		    PSHOT_MAX_MINOR_NAMELEN);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 		/* this assumes contiguous a filling */
5710Sstevel@tonic-gate 		for (i = 0; i <= PSHOT_MAX_NODENUM; i++) {
5720Sstevel@tonic-gate 			if (ddi_create_minor_node(devi, pshot->nodes[i].name,
5730Sstevel@tonic-gate 			    S_IFCHR, pshot->nodes[i].minor, DDI_NT_NEXUS, 0) !=
5740Sstevel@tonic-gate 			    DDI_SUCCESS) {
5750Sstevel@tonic-gate 				cmn_err(CE_WARN, "attach: cannot create "
5760Sstevel@tonic-gate 				    "minor %s", pshot->nodes[i].name);
5770Sstevel@tonic-gate 				goto FAIL_ATTACH;
5780Sstevel@tonic-gate 			}
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 		/*
5820Sstevel@tonic-gate 		 * pshot_devices setup
5830Sstevel@tonic-gate 		 */
5840Sstevel@tonic-gate 		if (pshot_devices_setup(devi)) {
5850Sstevel@tonic-gate 			cmn_err(CE_WARN, "attach: pshot devices setup "
5860Sstevel@tonic-gate 			    "failed");
5870Sstevel@tonic-gate 			goto FAIL_ATTACH;
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		/*
5910Sstevel@tonic-gate 		 * events setup
5920Sstevel@tonic-gate 		 */
5930Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
5940Sstevel@tonic-gate 			rval =	ddi_get_eventcookie(devi,
5950Sstevel@tonic-gate 			    pshot_register_events[i].event_name,
5960Sstevel@tonic-gate 			    &pshot_register_events[i].event_cookie);
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 			if (pshot_debug)
5990Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: event=%s:"
6000Sstevel@tonic-gate 				    "ddi_get_eventcookie rval=%d\n",
6010Sstevel@tonic-gate 				    instance,
6020Sstevel@tonic-gate 				    pshot_register_events[i].event_name, rval);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 			if (rval == DDI_SUCCESS) {
6050Sstevel@tonic-gate 				rval = ddi_add_event_handler(devi,
6060Sstevel@tonic-gate 				    pshot_register_events[i].event_cookie,
6070Sstevel@tonic-gate 				    pshot_register_events[i].event_callback,
6080Sstevel@tonic-gate 				    (void *)pshot,
6090Sstevel@tonic-gate 				    &pshot->callback_cache[i]);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 				if (pshot_debug)
6120Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: event=%s: "
6130Sstevel@tonic-gate 					    "ddi_add_event_handler rval=%d\n",
6140Sstevel@tonic-gate 					    instance,
6150Sstevel@tonic-gate 					    pshot_register_events[i].event_name,
6160Sstevel@tonic-gate 					    rval);
6170Sstevel@tonic-gate 			}
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate #ifdef DEBUG
6210Sstevel@tonic-gate 		if (pshot_event_test_enable) {
6220Sstevel@tonic-gate 			pshot_event_test((void *)pshot);
6230Sstevel@tonic-gate 			(void) timeout(pshot_event_test_post_one, (void *)pshot,
6240Sstevel@tonic-gate 			    instance * drv_usectohz(60000000));
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate #endif
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 		/*
6290Sstevel@tonic-gate 		 * allocate an ndi event handle
6300Sstevel@tonic-gate 		 */
6310Sstevel@tonic-gate 		if (ndi_event_alloc_hdl(devi, NULL, &pshot->ndi_event_hdl,
6320Sstevel@tonic-gate 		    NDI_SLEEP) != NDI_SUCCESS) {
6330Sstevel@tonic-gate 			goto FAIL_ATTACH;
6340Sstevel@tonic-gate 		}
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 		pshot->ndi_events.ndi_events_version = NDI_EVENTS_REV1;
6370Sstevel@tonic-gate 		pshot->ndi_events.ndi_n_events = PSHOT_N_NDI_EVENTS;
6380Sstevel@tonic-gate 		pshot->ndi_events.ndi_event_defs = pshot_ndi_event_defs;
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 		if (ndi_event_bind_set(pshot->ndi_event_hdl, &pshot->ndi_events,
6410Sstevel@tonic-gate 		    NDI_SLEEP) != NDI_SUCCESS) {
6420Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d bind set failed\n",
6437656SSherry.Moore@Sun.COM 			    instance);
6440Sstevel@tonic-gate 		}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 		/*
6470Sstevel@tonic-gate 		 * setup a test for nexus auto-attach iff we are
6480Sstevel@tonic-gate 		 * a second level pshot node (parent == /SUNW,pshot)
6490Sstevel@tonic-gate 		 * enable by setting "autoattach=1" in pshot.conf
6500Sstevel@tonic-gate 		 */
6510Sstevel@tonic-gate 		if ((PARENT_IS_PSHOT(devi)) && (pshot_prop_autoattach != 0) &&
6520Sstevel@tonic-gate 		    (ddi_get_instance(ddi_get_parent(devi))) == 0)
6530Sstevel@tonic-gate 			pshot_setup_autoattach(devi);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		/*
6560Sstevel@tonic-gate 		 * initialize internal state to idle: busy = 0,
6570Sstevel@tonic-gate 		 * power level = -1
6580Sstevel@tonic-gate 		 */
6590Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
6600Sstevel@tonic-gate 		pshot->busy = 0;
6610Sstevel@tonic-gate 		pshot->busy_ioctl = 0;
6620Sstevel@tonic-gate 		pshot->level = -1;
6630Sstevel@tonic-gate 		pshot->state &= ~STRICT_PARENT;
6640Sstevel@tonic-gate 		pshot->state |= PM_SUPPORTED;
6650Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 		/*
6680Sstevel@tonic-gate 		 * Create the "pm-want-child-notification?" property
6690Sstevel@tonic-gate 		 * for the root node /devices/pshot
6700Sstevel@tonic-gate 		 */
6710Sstevel@tonic-gate 		if (instance == 0) {
6720Sstevel@tonic-gate 			if (pshot_debug) {
6730Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:\n\t"
6740Sstevel@tonic-gate 				    " create the"
6750Sstevel@tonic-gate 				    " \"pm-want-child-notification?\" property"
6760Sstevel@tonic-gate 				    " for the root node\n", instance);
6770Sstevel@tonic-gate 			}
6780Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, devi, 0,
6790Sstevel@tonic-gate 			    "pm-want-child-notification?", NULL, 0)
6800Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
6810Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d:\n\t"
6820Sstevel@tonic-gate 				    " unable to create the"
6830Sstevel@tonic-gate 				    " \"pm-want-child-notification?\""
6840Sstevel@tonic-gate 				    " property", ddi_get_name(devi),
6850Sstevel@tonic-gate 				    ddi_get_instance(devi));
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 				goto FAIL_ATTACH;
6880Sstevel@tonic-gate 			}
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		/*
6920Sstevel@tonic-gate 		 * Check if the pm-want-child-notification? property was
6930Sstevel@tonic-gate 		 * created in pshot_bus_config_setup_nexus() by the parent.
6940Sstevel@tonic-gate 		 * Set the STRICT_PARENT flag if not.
6950Sstevel@tonic-gate 		 */
6960Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
6970Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
6980Sstevel@tonic-gate 		    "pm-want-child-notification?") != 1) {
6990Sstevel@tonic-gate 			if (pshot_debug) {
7000Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7010Sstevel@tonic-gate 				    " STRICT PARENT\n", instance);
7020Sstevel@tonic-gate 			}
7030Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
7040Sstevel@tonic-gate 			pshot->state |= STRICT_PARENT;
7050Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
7060Sstevel@tonic-gate 		} else {
7070Sstevel@tonic-gate 			if (pshot_debug) {
7080Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7090Sstevel@tonic-gate 				    " INVOLVED PARENT\n", instance);
7100Sstevel@tonic-gate 			}
7110Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
7120Sstevel@tonic-gate 			pshot->state &= ~STRICT_PARENT;
7130Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
7140Sstevel@tonic-gate 		}
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		/*
7170Sstevel@tonic-gate 		 * create the pm-components property: one component
7180Sstevel@tonic-gate 		 * with 4 power levels.
7190Sstevel@tonic-gate 		 * - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict:
7200Sstevel@tonic-gate 		 * "no-pm-components" property
7210Sstevel@tonic-gate 		 */
7220Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
7230Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
7240Sstevel@tonic-gate 		    "no-pm-components") == 0) {
7250Sstevel@tonic-gate 			if (pshot_debug) {
7260Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7270Sstevel@tonic-gate 				    " create the \"pm_components\" property\n",
7280Sstevel@tonic-gate 				    instance);
7290Sstevel@tonic-gate 			}
7300Sstevel@tonic-gate 			if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
7310Sstevel@tonic-gate 			    "pm-components", pm_comp, 5) != DDI_PROP_SUCCESS) {
7320Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
7330Sstevel@tonic-gate 				    " unable to create the \"pm-components\""
7340Sstevel@tonic-gate 				    " property", ddi_get_name(devi),
7350Sstevel@tonic-gate 				    ddi_get_instance(devi));
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 				goto FAIL_ATTACH;
7380Sstevel@tonic-gate 			}
7390Sstevel@tonic-gate 		} else {
7400Sstevel@tonic-gate 			if (pshot_debug) {
7410Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7420Sstevel@tonic-gate 				    " NO-PM_COMPONENTS PARENT\n", instance);
7430Sstevel@tonic-gate 			}
7440Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
7450Sstevel@tonic-gate 			pshot->state &= ~PM_SUPPORTED;
7460Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
7470Sstevel@tonic-gate 		}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 		/*
7500Sstevel@tonic-gate 		 * create the property needed to get DDI_SUSPEND
7510Sstevel@tonic-gate 		 * and DDI_RESUME calls
7520Sstevel@tonic-gate 		 */
7530Sstevel@tonic-gate 		if (pshot_debug) {
7540Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7550Sstevel@tonic-gate 			    " create pm-hardware-state property\n",
7560Sstevel@tonic-gate 			    instance);
7570Sstevel@tonic-gate 		}
7580Sstevel@tonic-gate 		if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
7590Sstevel@tonic-gate 		    "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
7600Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
7610Sstevel@tonic-gate 			    " unable to create the \"pm-hardware-state\""
7620Sstevel@tonic-gate 			    " property", ddi_get_name(devi),
7630Sstevel@tonic-gate 			    ddi_get_instance(devi));
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 			goto FAIL_ATTACH;
7660Sstevel@tonic-gate 		}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		/*
7690Sstevel@tonic-gate 		 * set power level to max via pm_raise_power(),
7700Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
7710Sstevel@tonic-gate 		 */
7720Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
7730Sstevel@tonic-gate 			if (pshot_debug) {
7740Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7750Sstevel@tonic-gate 				    " raise power to MAXPWR\n", instance);
7760Sstevel@tonic-gate 			}
7770Sstevel@tonic-gate 			if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
7780Sstevel@tonic-gate 			    DDI_SUCCESS) {
7790Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:"
7800Sstevel@tonic-gate 				    " pm_raise_power failed",
7810Sstevel@tonic-gate 				    ddi_get_name(devi),
7820Sstevel@tonic-gate 				    ddi_get_instance(devi));
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 				goto FAIL_ATTACH;
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 			}
7870Sstevel@tonic-gate 		}
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 		if (pshot_log)
7900Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d attached\n", instance);
7910Sstevel@tonic-gate 		ddi_report_dev(devi);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		return (DDI_SUCCESS);
7940Sstevel@tonic-gate 		/*NOTREACHED*/
7950Sstevel@tonic-gate FAIL_ATTACH:
7960Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
7970Sstevel@tonic-gate 		mutex_destroy(&pshot->lock);
7980Sstevel@tonic-gate 		ddi_soft_state_free(pshot_softstatep, instance);
7990Sstevel@tonic-gate 		return (DDI_FAILURE);
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	case DDI_RESUME:
8020Sstevel@tonic-gate 		if (pshot_debug) {
8030Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resuming\n",
8040Sstevel@tonic-gate 			    instance);
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		/*
8090Sstevel@tonic-gate 		 * set power level to max via pm_raise_power(),
8100Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
8110Sstevel@tonic-gate 		 */
8120Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
8130Sstevel@tonic-gate 			if (pshot_debug) {
8140Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_RESUME:"
8150Sstevel@tonic-gate 				    " raise power to MAXPWR\n", instance);
8160Sstevel@tonic-gate 			}
8170Sstevel@tonic-gate 			if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
8180Sstevel@tonic-gate 			    DDI_SUCCESS) {
8190Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_RESUME:"
8200Sstevel@tonic-gate 				    " pm_raise_power failed",
8210Sstevel@tonic-gate 				    ddi_get_name(devi),
8220Sstevel@tonic-gate 				    ddi_get_instance(devi));
8230Sstevel@tonic-gate 			}
8240Sstevel@tonic-gate 		}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 		if (pshot_debug) {
8270Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resumed\n",
8280Sstevel@tonic-gate 			    instance);
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 		return (DDI_SUCCESS);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	default:
8330Sstevel@tonic-gate 		return (DDI_FAILURE);
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate static int
pshot_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)8380Sstevel@tonic-gate pshot_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate 	int instance = ddi_get_instance(devi);
8410Sstevel@tonic-gate 	int i, rval;
8420Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
8430Sstevel@tonic-gate 	int level_tmp;
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	if (pshot == NULL)
8460Sstevel@tonic-gate 		return (DDI_FAILURE);
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	switch (cmd) {
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	case DDI_DETACH:
8510Sstevel@tonic-gate 		if (pshot_debug)
8520Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_DETACH\n", instance);
8530Sstevel@tonic-gate 		/*
8540Sstevel@tonic-gate 		 * power off component 0
8550Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
8560Sstevel@tonic-gate 		 */
8570Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
8580Sstevel@tonic-gate 			if (pshot_debug) {
8590Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_DETACH:"
8600Sstevel@tonic-gate 				    " power off\n", instance);
8610Sstevel@tonic-gate 			}
8620Sstevel@tonic-gate 			if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
8630Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t"
8640Sstevel@tonic-gate 				    "pm_lower_power failed for comp 0 to"
8650Sstevel@tonic-gate 				    " level 0", ddi_get_name(devi),
8660Sstevel@tonic-gate 				    ddi_get_instance(devi));
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 				return (DDI_FAILURE);
8690Sstevel@tonic-gate 			}
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 			/*
8720Sstevel@tonic-gate 			 * Check if the power level is actually OFF.
8730Sstevel@tonic-gate 			 * Issue pm_power_has_changed if not.
8740Sstevel@tonic-gate 			 */
8750Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
8760Sstevel@tonic-gate 			if (pshot->level != 0) {
8770Sstevel@tonic-gate 				if (pshot_debug) {
8780Sstevel@tonic-gate 					cmn_err(CE_NOTE, "pshot%d:"
8790Sstevel@tonic-gate 					    " DDI_DETACH: power off via"
8800Sstevel@tonic-gate 					    " pm_power_has_changed instead\n",
8810Sstevel@tonic-gate 					    instance);
8820Sstevel@tonic-gate 				}
8830Sstevel@tonic-gate 				level_tmp = pshot->level;
8840Sstevel@tonic-gate 				pshot->level = 0;
8850Sstevel@tonic-gate 				if (pm_power_has_changed(pshot->dip, 0, 0) !=
8860Sstevel@tonic-gate 				    DDI_SUCCESS) {
8870Sstevel@tonic-gate 					if (pshot_debug) {
8880Sstevel@tonic-gate 						cmn_err(CE_NOTE, "pshot%d:"
8890Sstevel@tonic-gate 						    " DDI_DETACH:"
8900Sstevel@tonic-gate 						    " pm_power_has_changed"
8910Sstevel@tonic-gate 						    " failed\n", instance);
8920Sstevel@tonic-gate 					}
8930Sstevel@tonic-gate 					pshot->level = level_tmp;
8940Sstevel@tonic-gate 					mutex_exit(&pshot->lock);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 					return (DDI_FAILURE);
8970Sstevel@tonic-gate 				}
8980Sstevel@tonic-gate 			}
8990Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
9000Sstevel@tonic-gate 		}
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
9030Sstevel@tonic-gate 			if (pshot->callback_cache[i] != NULL) {
9040Sstevel@tonic-gate 				rval = ddi_remove_event_handler(
9050Sstevel@tonic-gate 				    pshot->callback_cache[i]);
9060Sstevel@tonic-gate 				ASSERT(rval == DDI_SUCCESS);
9070Sstevel@tonic-gate 			}
9080Sstevel@tonic-gate 		}
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate #ifdef DEBUG
9110Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) {
9120Sstevel@tonic-gate 			if (pshot->test_callback_cache[i] != NULL) {
9130Sstevel@tonic-gate 				rval = ddi_remove_event_handler(
9140Sstevel@tonic-gate 				    pshot->test_callback_cache[i]);
9150Sstevel@tonic-gate 				ASSERT(rval == DDI_SUCCESS);
9160Sstevel@tonic-gate 			}
9170Sstevel@tonic-gate 		}
9180Sstevel@tonic-gate #endif
9190Sstevel@tonic-gate 		rval = ndi_event_free_hdl(pshot->ndi_event_hdl);
9200Sstevel@tonic-gate 		ASSERT(rval == DDI_SUCCESS);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 		if (pshot_log)
9230Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d detached\n", instance);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
9260Sstevel@tonic-gate 		mutex_destroy(&pshot->lock);
9270Sstevel@tonic-gate 		ddi_soft_state_free(pshot_softstatep, instance);
9280Sstevel@tonic-gate 		break;
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	case DDI_SUSPEND:
9310Sstevel@tonic-gate 		if (pshot_debug)
9320Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND\n", instance);
9330Sstevel@tonic-gate 		/*
9340Sstevel@tonic-gate 		 * fail the suspend if FAIL_SUSPEND_FLAG is set.
9350Sstevel@tonic-gate 		 * clear the FAIL_SUSPEND_FLAG flag
9360Sstevel@tonic-gate 		 */
9370Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
9380Sstevel@tonic-gate 		if (pshot->state & FAIL_SUSPEND_FLAG) {
9390Sstevel@tonic-gate 			if (pshot_debug) {
9400Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
9417656SSherry.Moore@Sun.COM 				    " FAIL_SUSPEND_FLAG set, fail suspend\n",
9427656SSherry.Moore@Sun.COM 				    ddi_get_instance(devi));
9430Sstevel@tonic-gate 			}
9440Sstevel@tonic-gate 			pshot->state &= ~FAIL_SUSPEND_FLAG;
9450Sstevel@tonic-gate 			rval = DDI_FAILURE;
9460Sstevel@tonic-gate 		} else {
9470Sstevel@tonic-gate 			rval = DDI_SUCCESS;
9480Sstevel@tonic-gate 		}
9490Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		/*
9520Sstevel@tonic-gate 		 * power OFF via pm_power_has_changed
9530Sstevel@tonic-gate 		 */
9540Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
9550Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
9560Sstevel@tonic-gate 			if (pshot_debug) {
9570Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND:"
9580Sstevel@tonic-gate 				    " power off via pm_power_has_changed\n",
9590Sstevel@tonic-gate 				    instance);
9600Sstevel@tonic-gate 			}
9610Sstevel@tonic-gate 			level_tmp = pshot->level;
9620Sstevel@tonic-gate 			pshot->level = 0;
9630Sstevel@tonic-gate 			if (pm_power_has_changed(pshot->dip, 0, 0) !=
9640Sstevel@tonic-gate 			    DDI_SUCCESS) {
9650Sstevel@tonic-gate 				if (pshot_debug) {
9660Sstevel@tonic-gate 					cmn_err(CE_NOTE, "pshot%d:"
9670Sstevel@tonic-gate 					    " DDI_SUSPEND:"
9680Sstevel@tonic-gate 					    " pm_power_has_changed failed\n",
9690Sstevel@tonic-gate 					    instance);
9700Sstevel@tonic-gate 				}
9710Sstevel@tonic-gate 				pshot->level = level_tmp;
9720Sstevel@tonic-gate 				rval = DDI_FAILURE;
9730Sstevel@tonic-gate 			}
9740Sstevel@tonic-gate 		}
9750Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
9760Sstevel@tonic-gate 		return (rval);
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	default:
9790Sstevel@tonic-gate 		break;
9800Sstevel@tonic-gate 	}
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	return (DDI_SUCCESS);
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * returns number of bits to represent <val>
9880Sstevel@tonic-gate  */
9890Sstevel@tonic-gate static size_t
pshot_numbits(size_t val)9900Sstevel@tonic-gate pshot_numbits(size_t val)
9910Sstevel@tonic-gate {
9920Sstevel@tonic-gate 	size_t bitcnt;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	if (val == 0)
9950Sstevel@tonic-gate 		return (0);
9960Sstevel@tonic-gate 	for (bitcnt = 1; 1 << bitcnt < val; bitcnt++)
9970Sstevel@tonic-gate 		;
9980Sstevel@tonic-gate 	return (bitcnt);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate /*
10020Sstevel@tonic-gate  * returns a minor number encoded with instance <inst> and an index <nodenum>
10030Sstevel@tonic-gate  * that identifies the minor node for this instance
10040Sstevel@tonic-gate  */
10050Sstevel@tonic-gate static minor_t
pshot_minor_encode(int inst,minor_t nodenum)10060Sstevel@tonic-gate pshot_minor_encode(int inst, minor_t nodenum)
10070Sstevel@tonic-gate {
10080Sstevel@tonic-gate 	return (((minor_t)inst << PSHOT_NODENUM_BITS()) |
10090Sstevel@tonic-gate 	    (((1 << PSHOT_NODENUM_BITS()) - 1) & nodenum));
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate /*
10130Sstevel@tonic-gate  * returns instance of <minor>
10140Sstevel@tonic-gate  */
10150Sstevel@tonic-gate static int
pshot_minor_decode_inst(minor_t minor)10160Sstevel@tonic-gate pshot_minor_decode_inst(minor_t minor)
10170Sstevel@tonic-gate {
10180Sstevel@tonic-gate 	return (minor >> PSHOT_NODENUM_BITS());
10190Sstevel@tonic-gate }
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate /*
10220Sstevel@tonic-gate  * returns node number indexing a minor node for the instance in <minor>
10230Sstevel@tonic-gate  */
10240Sstevel@tonic-gate static minor_t
pshot_minor_decode_nodenum(minor_t minor)10250Sstevel@tonic-gate pshot_minor_decode_nodenum(minor_t minor)
10260Sstevel@tonic-gate {
10270Sstevel@tonic-gate 	return (minor & ((1 << PSHOT_NODENUM_BITS()) - 1));
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate /*
10320Sstevel@tonic-gate  * pshot_bus_introp: pshot convert an interrupt number to an
10330Sstevel@tonic-gate  *			   interrupt. NO OP for pseudo drivers.
10340Sstevel@tonic-gate  */
10350Sstevel@tonic-gate /*ARGSUSED*/
10360Sstevel@tonic-gate static int
pshot_bus_introp(dev_info_t * dip,dev_info_t * rdip,ddi_intr_op_t intr_op,ddi_intr_handle_impl_t * hdlp,void * result)10370Sstevel@tonic-gate pshot_bus_introp(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
10380Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate 	return (DDI_FAILURE);
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate static int
pshot_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)10430Sstevel@tonic-gate pshot_ctl(dev_info_t *dip, dev_info_t *rdip,
10440Sstevel@tonic-gate     ddi_ctl_enum_t ctlop, void *arg, void *result)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	int instance;
10470Sstevel@tonic-gate 	pshot_t *pshot;
10480Sstevel@tonic-gate 	char *childname;
10490Sstevel@tonic-gate 	int childinstance;
10500Sstevel@tonic-gate 	char *name;
10510Sstevel@tonic-gate 	int circ;
10520Sstevel@tonic-gate 	struct attachspec *as;
10530Sstevel@tonic-gate 	struct detachspec *ds;
10540Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
10550Sstevel@tonic-gate 	int no_pm_components_child;
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	name = ddi_get_name(dip);
10580Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
10590Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
10600Sstevel@tonic-gate 	if (pshot == NULL) {
10610Sstevel@tonic-gate 		return (ENXIO);
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	switch (ctlop) {
10650Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
10660Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
10670Sstevel@tonic-gate 			return (DDI_FAILURE);
10680Sstevel@tonic-gate 		cmn_err(CE_CONT, "?pshot-device: %s%d\n",
10690Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
10700Sstevel@tonic-gate 		return (DDI_SUCCESS);
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
10730Sstevel@tonic-gate 	{
10740Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 		if (pshot_debug) {
10770Sstevel@tonic-gate 			cmn_err(CE_CONT, "initchild %s%d/%s%d state 0x%x\n",
10780Sstevel@tonic-gate 			    ddi_get_name(dip), ddi_get_instance(dip),
10790Sstevel@tonic-gate 			    ddi_node_name(child), ddi_get_instance(child),
10800Sstevel@tonic-gate 			    DEVI(child)->devi_state);
10810Sstevel@tonic-gate 		}
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 		return (pshot_initchild(dip, child));
10840Sstevel@tonic-gate 	}
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
10870Sstevel@tonic-gate 	{
10880Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 		if (pshot_debug) {
10910Sstevel@tonic-gate 			cmn_err(CE_CONT, "uninitchild %s%d/%s%d state 0x%x\n",
10920Sstevel@tonic-gate 			    ddi_get_name(dip), ddi_get_instance(dip),
10930Sstevel@tonic-gate 			    ddi_node_name(child), ddi_get_instance(child),
10940Sstevel@tonic-gate 			    DEVI(child)->devi_state);
10950Sstevel@tonic-gate 		}
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 		return (pshot_uninitchild(dip, child));
10980Sstevel@tonic-gate 	}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
11010Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
11020Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
11030Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
11040Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
11050Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
11060Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
11070Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
11080Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
11090Sstevel@tonic-gate 		/*
11100Sstevel@tonic-gate 		 * These ops correspond to functions that "shouldn't" be called
11110Sstevel@tonic-gate 		 * by a pseudo driver.  So we whine when we're called.
11120Sstevel@tonic-gate 		 */
11130Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
11147656SSherry.Moore@Sun.COM 		    ddi_get_name(dip), ddi_get_instance(dip),
11157656SSherry.Moore@Sun.COM 		    ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
11160Sstevel@tonic-gate 		return (DDI_FAILURE);
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	case DDI_CTLOPS_ATTACH:
11190Sstevel@tonic-gate 	{
11200Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)rdip;
11210Sstevel@tonic-gate 		childname = ddi_node_name(child);
11220Sstevel@tonic-gate 		childinstance = ddi_get_instance(child);
11230Sstevel@tonic-gate 		as = (struct attachspec *)arg;
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		no_pm_components_child = 0;
11260Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
11270Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
11280Sstevel@tonic-gate 		    "no-pm-components") == 1) {
11290Sstevel@tonic-gate 			no_pm_components_child = 1;
11300Sstevel@tonic-gate 		}
11310Sstevel@tonic-gate 		if (pshot_debug) {
11320Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n",
11330Sstevel@tonic-gate 			    name, instance, childname, childinstance,
11340Sstevel@tonic-gate 			    no_pm_components_child);
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		ndi_devi_enter(dip, &circ);
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 		switch (as->when) {
11400Sstevel@tonic-gate 		case DDI_PRE:
11410Sstevel@tonic-gate 			/*
11420Sstevel@tonic-gate 			 * Mark nexus busy before a child attaches.
11430Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
11440Sstevel@tonic-gate 			 * - pshot@XXX,nopm_strict)
11450Sstevel@tonic-gate 			 */
11460Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED))
11470Sstevel@tonic-gate 				break;
11480Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
11490Sstevel@tonic-gate 			++(pshot->busy);
11500Sstevel@tonic-gate 			if (pshot_debug_busy) {
11510Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
11520Sstevel@tonic-gate 				    " ctl_attach_pre: busy for %s%d:"
11530Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
11540Sstevel@tonic-gate 				    childname, childinstance,
11550Sstevel@tonic-gate 				    pshot->busy);
11560Sstevel@tonic-gate 			}
11570Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
11580Sstevel@tonic-gate 			rval = pm_busy_component(dip, 0);
11590Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
11600Sstevel@tonic-gate 			break;
11610Sstevel@tonic-gate 		case DDI_POST:
11620Sstevel@tonic-gate 			/*
11630Sstevel@tonic-gate 			 * Mark nexus idle after a child attaches.
11640Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
11650Sstevel@tonic-gate 			 * - also skip if this is not a stict parent and
11660Sstevel@tonic-gate 			 * - the child is a tape device or a no-pm-components
11670Sstevel@tonic-gate 			 * - nexus node.
11680Sstevel@tonic-gate 			 */
11690Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED) ||
11700Sstevel@tonic-gate 			    (strcmp(childname, "tape") == 0 &&
11710Sstevel@tonic-gate 			    !(pshot->state & STRICT_PARENT)) ||
11720Sstevel@tonic-gate 			    no_pm_components_child)
11730Sstevel@tonic-gate 				break;
11740Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
11750Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
11760Sstevel@tonic-gate 			--pshot->busy;
11770Sstevel@tonic-gate 			if (pshot_debug_busy) {
11780Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
11790Sstevel@tonic-gate 				    " ctl_attach_post: idle for %s%d:"
11800Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
11810Sstevel@tonic-gate 				    childname, childinstance,
11820Sstevel@tonic-gate 				    pshot->busy);
11830Sstevel@tonic-gate 			}
11840Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
11850Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
11860Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
11870Sstevel@tonic-gate 			break;
11880Sstevel@tonic-gate 		}
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 		ndi_devi_exit(dip, circ);
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		return (rval);
11930Sstevel@tonic-gate 	}
11940Sstevel@tonic-gate 	case DDI_CTLOPS_DETACH:
11950Sstevel@tonic-gate 		{
11960Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)rdip;
11970Sstevel@tonic-gate 		childname = ddi_node_name(child);
11980Sstevel@tonic-gate 		childinstance = ddi_get_instance(child);
11990Sstevel@tonic-gate 		ds = (struct detachspec *)arg;
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate 		no_pm_components_child = 0;
12020Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
12030Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
12040Sstevel@tonic-gate 		    "no-pm-components") == 1) {
12050Sstevel@tonic-gate 			no_pm_components_child = 1;
12060Sstevel@tonic-gate 		}
12070Sstevel@tonic-gate 		if (pshot_debug) {
12080Sstevel@tonic-gate 			cmn_err(CE_CONT,
12090Sstevel@tonic-gate 			    "%s%d: ctl_detach %s%d [%d]\n",
12100Sstevel@tonic-gate 			    name, instance, childname, childinstance,
12110Sstevel@tonic-gate 			    no_pm_components_child);
12120Sstevel@tonic-gate 		}
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		ndi_devi_enter(dip, &circ);
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 		switch (ds->when) {
12170Sstevel@tonic-gate 		case DDI_PRE:
12180Sstevel@tonic-gate 			/*
12190Sstevel@tonic-gate 			 * Mark nexus busy before a child detaches.
12200Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
12210Sstevel@tonic-gate 			 * - pshot@XXX,nopm_strict), or if the child is a
12220Sstevel@tonic-gate 			 * - no-pm-components nexus node.
12230Sstevel@tonic-gate 			 */
12240Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED) ||
12250Sstevel@tonic-gate 			    (strcmp(childname, "tape") == 0 &&
12260Sstevel@tonic-gate 			    !(pshot->state & STRICT_PARENT)) ||
12270Sstevel@tonic-gate 			    no_pm_components_child)
12280Sstevel@tonic-gate 				break;
12290Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
12300Sstevel@tonic-gate 			++(pshot->busy);
12310Sstevel@tonic-gate 			if (pshot_debug_busy) {
12320Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
12330Sstevel@tonic-gate 				    " ctl_detach_pre: busy for %s%d:"
12340Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
12350Sstevel@tonic-gate 				    childname, childinstance,
12360Sstevel@tonic-gate 				    pshot->busy);
12370Sstevel@tonic-gate 			}
12380Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
12390Sstevel@tonic-gate 			rval = pm_busy_component(dip, 0);
12400Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 			break;
12430Sstevel@tonic-gate 		case DDI_POST:
12440Sstevel@tonic-gate 			/*
12450Sstevel@tonic-gate 			 * Mark nexus idle after a child detaches.
12460Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
12470Sstevel@tonic-gate 			 */
12480Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED))
12490Sstevel@tonic-gate 				break;
12500Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
12510Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
12520Sstevel@tonic-gate 			--pshot->busy;
12530Sstevel@tonic-gate 			if (pshot_debug_busy) {
12540Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
12550Sstevel@tonic-gate 				    " ctl_detach_post: idle for %s%d:"
12560Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
12570Sstevel@tonic-gate 				    childname, childinstance,
12580Sstevel@tonic-gate 				    pshot->busy);
12590Sstevel@tonic-gate 			}
12600Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
12610Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
12620Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 			/*
12650Sstevel@tonic-gate 			 * Mark the driver idle if the NO_INVOL_FLAG
12660Sstevel@tonic-gate 			 * is set. This is needed to make sure the
12670Sstevel@tonic-gate 			 * parent is idle after the child detaches
12680Sstevel@tonic-gate 			 * without calling pm_lower_power().
12690Sstevel@tonic-gate 			 * Clear the NO_INVOL_FLAG.
12700Sstevel@tonic-gate 			 * - also mark idle if a tape device has detached
12710Sstevel@tonic-gate 			 */
12720Sstevel@tonic-gate 			if (!(pshot->state & NO_INVOL_FLAG))
12730Sstevel@tonic-gate 				break;
12740Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
12750Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
12760Sstevel@tonic-gate 			--pshot->busy;
12770Sstevel@tonic-gate 			if (pshot_debug_busy) {
12780Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
12790Sstevel@tonic-gate 				    " ctl_detach_post: NO_INVOL:"
12800Sstevel@tonic-gate 				    " idle for %s%d: busy = %d\n",
12810Sstevel@tonic-gate 				    name, instance, childname,
12820Sstevel@tonic-gate 				    childinstance, pshot->busy);
12830Sstevel@tonic-gate 			}
12840Sstevel@tonic-gate 			pshot->state &= ~NO_INVOL_FLAG;
12850Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
12860Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
12870Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 			break;
12900Sstevel@tonic-gate 		}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 		ndi_devi_exit(dip, circ);
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 		return (rval);
12950Sstevel@tonic-gate 	}
12960Sstevel@tonic-gate 
12972155Scth 	case DDI_CTLOPS_BTOP:
12982155Scth 	case DDI_CTLOPS_BTOPR:
12990Sstevel@tonic-gate 	case DDI_CTLOPS_DVMAPAGESIZE:
13000Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
13010Sstevel@tonic-gate 	case DDI_CTLOPS_PTOB:
13020Sstevel@tonic-gate 	default:
13030Sstevel@tonic-gate 		/*
13040Sstevel@tonic-gate 		 * The ops that we pass up (default).  We pass up memory
13050Sstevel@tonic-gate 		 * allocation oriented ops that we receive - these may be
13060Sstevel@tonic-gate 		 * associated with pseudo HBA drivers below us with target
13070Sstevel@tonic-gate 		 * drivers below them that use ddi memory allocation
13080Sstevel@tonic-gate 		 * interfaces like scsi_alloc_consistent_buf.
13090Sstevel@tonic-gate 		 */
13100Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate /*ARGSUSED0*/
13150Sstevel@tonic-gate static int
pshot_power(dev_info_t * dip,int cmpt,int level)13160Sstevel@tonic-gate pshot_power(dev_info_t *dip, int cmpt, int level)
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate 	pshot_t *pshot;
13190Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
13200Sstevel@tonic-gate 	char *name = ddi_node_name(dip);
13210Sstevel@tonic-gate 	int circ;
13220Sstevel@tonic-gate 	int rv;
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
13250Sstevel@tonic-gate 	if (pshot == NULL) {
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		return (DDI_FAILURE);
13280Sstevel@tonic-gate 	}
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	/*
13330Sstevel@tonic-gate 	 * set POWER_FLAG when power() is called.
13340Sstevel@tonic-gate 	 * ioctl(DEVCT_PM_POWER) is a clear on read call.
13350Sstevel@tonic-gate 	 */
13360Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
13370Sstevel@tonic-gate 	pshot->state |= POWER_FLAG;
13380Sstevel@tonic-gate 	/*
13390Sstevel@tonic-gate 	 * refuse to power OFF if the component is busy
13400Sstevel@tonic-gate 	 */
13410Sstevel@tonic-gate 	if (pshot->busy != 0 && pshot->level > level) {
13420Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE"
13430Sstevel@tonic-gate 		    " (%d->%d), DEVICE NOT IDLE: busy = %d",
13440Sstevel@tonic-gate 		    name, instance, pshot->level, level, pshot->busy);
13450Sstevel@tonic-gate 		rv = DDI_FAILURE;
13460Sstevel@tonic-gate 	} else {
13470Sstevel@tonic-gate 		if (pshot_debug) {
13480Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n",
13490Sstevel@tonic-gate 			    name, instance, cmpt, pshot->level, level);
13500Sstevel@tonic-gate 		}
13510Sstevel@tonic-gate 		pshot->level = level;
13520Sstevel@tonic-gate 		rv = DDI_SUCCESS;
13530Sstevel@tonic-gate 	}
13540Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	return (rv);
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate /*ARGSUSED0*/
13620Sstevel@tonic-gate static int
pshot_bus_power(dev_info_t * dip,void * impl_arg,pm_bus_power_op_t op,void * arg,void * result)13630Sstevel@tonic-gate pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
13640Sstevel@tonic-gate     void *arg, void *result)
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate {
13670Sstevel@tonic-gate 	int 				ret;
13680Sstevel@tonic-gate 	int 				instance = ddi_get_instance(dip);
13690Sstevel@tonic-gate 	char				*name = ddi_node_name(dip);
13700Sstevel@tonic-gate 	pshot_t 			*pshot;
13710Sstevel@tonic-gate 	pm_bp_child_pwrchg_t		*bpc;
13720Sstevel@tonic-gate 	pm_bp_nexus_pwrup_t		bpn;
13730Sstevel@tonic-gate 	pm_bp_has_changed_t		*bphc;
13740Sstevel@tonic-gate 	int				pwrup_res;
13750Sstevel@tonic-gate 	int				ret_failed = 0;
13760Sstevel@tonic-gate 	int				pwrup_res_failed = 0;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
13790Sstevel@tonic-gate 	if (pshot == NULL) {
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 		return (DDI_FAILURE);
13820Sstevel@tonic-gate 	}
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 	switch (op) {
13850Sstevel@tonic-gate 	case BUS_POWER_PRE_NOTIFICATION:
13860Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
13870Sstevel@tonic-gate 		if (pshot_debug) {
13880Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: pre_bus_power:"
13890Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d)\n",
13900Sstevel@tonic-gate 			    name, instance, ddi_node_name(bpc->bpc_dip),
13910Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
13920Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_olevel,
13930Sstevel@tonic-gate 			    bpc->bpc_nlevel);
13940Sstevel@tonic-gate 		}
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 		/*
13970Sstevel@tonic-gate 		 * mark parent busy if old_level is either -1 or 0,
13980Sstevel@tonic-gate 		 * and new level is == MAXPWR
13990Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
14000Sstevel@tonic-gate 		 */
14010Sstevel@tonic-gate 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
14020Sstevel@tonic-gate 		    bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) {
14030Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
14040Sstevel@tonic-gate 			++(pshot->busy);
14050Sstevel@tonic-gate 			if (pshot_debug_busy) {
14060Sstevel@tonic-gate 				cmn_err(CE_CONT,
14070Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
14080Sstevel@tonic-gate 				    " busy parent for %s%d (%d->%d): "
14090Sstevel@tonic-gate 				    " busy = %d\n",
14100Sstevel@tonic-gate 				    name, instance,
14110Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14120Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14130Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel,
14140Sstevel@tonic-gate 				    pshot->busy);
14150Sstevel@tonic-gate 			}
14160Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
14170Sstevel@tonic-gate 			ret = pm_busy_component(dip, 0);
14180Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
14190Sstevel@tonic-gate 		}
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 		/*
14220Sstevel@tonic-gate 		 * if new_level > 0, power up parent, if not already at
14230Sstevel@tonic-gate 		 * MAXPWR, via pm_busop_bus_power
14240Sstevel@tonic-gate 		 * - skip for the no-pm nexus (pshot@XXX,nopm)
14250Sstevel@tonic-gate 		 */
14260Sstevel@tonic-gate 		if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 &&
14270Sstevel@tonic-gate 		    pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) {
14280Sstevel@tonic-gate 			/*
14290Sstevel@tonic-gate 			 * stuff the bpn struct
14300Sstevel@tonic-gate 			 */
14310Sstevel@tonic-gate 			bpn.bpn_comp = 0;
14320Sstevel@tonic-gate 			bpn.bpn_level = MAXPWR;
14330Sstevel@tonic-gate 			bpn.bpn_private = bpc->bpc_private;
14340Sstevel@tonic-gate 			bpn.bpn_dip = dip;
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 			/*
14370Sstevel@tonic-gate 			 * ask pm to power parent up
14380Sstevel@tonic-gate 			 */
14390Sstevel@tonic-gate 			if (pshot_debug) {
14400Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d: pre_bus_power:"
14410Sstevel@tonic-gate 				    " pm_busop_bus_power on parent for %s%d"
14420Sstevel@tonic-gate 				    " (%d->%d): enter", name, instance,
14430Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14440Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14450Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
14460Sstevel@tonic-gate 			}
14470Sstevel@tonic-gate 			ret = pm_busop_bus_power(dip, impl_arg,
14480Sstevel@tonic-gate 			    BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
14490Sstevel@tonic-gate 			    (void *)&pwrup_res);
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 			/*
14520Sstevel@tonic-gate 			 * check the return status individually,
14530Sstevel@tonic-gate 			 * idle parent and exit if either failed.
14540Sstevel@tonic-gate 			 */
14550Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
14560Sstevel@tonic-gate 				cmn_err(CE_WARN,
14570Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
14580Sstevel@tonic-gate 				    " pm_busop_bus_power FAILED (ret) FOR"
14590Sstevel@tonic-gate 				    " %s%d (%d->%d)",
14600Sstevel@tonic-gate 				    name, instance,
14610Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14620Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14630Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
14640Sstevel@tonic-gate 				ret_failed = 1;
14650Sstevel@tonic-gate 			}
14660Sstevel@tonic-gate 			if (pwrup_res != DDI_SUCCESS) {
14670Sstevel@tonic-gate 				cmn_err(CE_WARN,
14680Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
14690Sstevel@tonic-gate 				    " pm_busop_bus_power FAILED (pwrup_res)"
14700Sstevel@tonic-gate 				    " FOR %s%d (%d->%d)",
14710Sstevel@tonic-gate 				    name, instance,
14720Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14730Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14740Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
14750Sstevel@tonic-gate 				pwrup_res_failed = 1;
14760Sstevel@tonic-gate 			}
14770Sstevel@tonic-gate 			if (ret_failed || pwrup_res_failed) {
14780Sstevel@tonic-gate 				/*
14790Sstevel@tonic-gate 				 * decrement the busy count if it
14800Sstevel@tonic-gate 				 * had been incremented.
14810Sstevel@tonic-gate 				 */
14820Sstevel@tonic-gate 				if ((bpc->bpc_comp == 0 &&
14830Sstevel@tonic-gate 				    bpc->bpc_nlevel == MAXPWR &&
14840Sstevel@tonic-gate 				    bpc->bpc_olevel <= 0) &&
14850Sstevel@tonic-gate 				    (pshot->state & PM_SUPPORTED)) {
14860Sstevel@tonic-gate 					mutex_enter(&pshot->lock);
14870Sstevel@tonic-gate 					ASSERT(pshot->busy > 0);
14880Sstevel@tonic-gate 					--(pshot->busy);
14890Sstevel@tonic-gate 					if (pshot_debug_busy) {
14900Sstevel@tonic-gate 						cmn_err(CE_CONT, "%s%d:"
14910Sstevel@tonic-gate 						    " pm_busop_bus_power"
14920Sstevel@tonic-gate 						    " failed: idle parent for"
14930Sstevel@tonic-gate 						    " %s%d (%d->%d):"
14940Sstevel@tonic-gate 						    " busy = %d\n",
14950Sstevel@tonic-gate 						    name, instance,
14960Sstevel@tonic-gate 						    ddi_node_name(
14970Sstevel@tonic-gate 						    bpc->bpc_dip),
14980Sstevel@tonic-gate 						    ddi_get_instance(
14990Sstevel@tonic-gate 						    bpc->bpc_dip),
15000Sstevel@tonic-gate 						    bpc->bpc_olevel,
15010Sstevel@tonic-gate 						    bpc->bpc_nlevel,
15020Sstevel@tonic-gate 						    pshot->busy);
15030Sstevel@tonic-gate 					}
15040Sstevel@tonic-gate 					mutex_exit(&pshot->lock);
15050Sstevel@tonic-gate 					ret = pm_idle_component(dip, 0);
15060Sstevel@tonic-gate 					ASSERT(ret == DDI_SUCCESS);
15070Sstevel@tonic-gate 				}
15080Sstevel@tonic-gate 				return (DDI_FAILURE);
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 			} else {
15110Sstevel@tonic-gate 				if (pshot_debug) {
15120Sstevel@tonic-gate 					cmn_err(CE_CONT,
15130Sstevel@tonic-gate 					    "%s%d: pre_bus_power:"
15140Sstevel@tonic-gate 					    " pm_busop_bus_power on parent"
15150Sstevel@tonic-gate 					    " for %s%d (%d->%d)\n",
15160Sstevel@tonic-gate 					    name, instance,
15170Sstevel@tonic-gate 					    ddi_node_name(bpc->bpc_dip),
15180Sstevel@tonic-gate 					    ddi_get_instance(bpc->bpc_dip),
15190Sstevel@tonic-gate 					    bpc->bpc_olevel, bpc->bpc_nlevel);
15200Sstevel@tonic-gate 				}
15210Sstevel@tonic-gate 			}
15220Sstevel@tonic-gate 		}
15230Sstevel@tonic-gate 		break;
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 	case BUS_POWER_POST_NOTIFICATION:
15260Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
15270Sstevel@tonic-gate 		if (pshot_debug) {
15280Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: post_bus_power:"
15290Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d) result %d\n",
15300Sstevel@tonic-gate 			    name, instance, ddi_node_name(bpc->bpc_dip),
15310Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
15320Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_olevel,
15330Sstevel@tonic-gate 			    bpc->bpc_nlevel, *(int *)result);
15340Sstevel@tonic-gate 		}
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 		/*
15370Sstevel@tonic-gate 		 * handle pm_busop_bus_power() failure case.
15380Sstevel@tonic-gate 		 * mark parent idle if had been marked busy.
15390Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
15400Sstevel@tonic-gate 		 */
15410Sstevel@tonic-gate 		if (*(int *)result != DDI_SUCCESS) {
15420Sstevel@tonic-gate 			cmn_err(CE_WARN,
15430Sstevel@tonic-gate 			    "pshot%d: post_bus_power_failed:"
15440Sstevel@tonic-gate 			    " pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
15450Sstevel@tonic-gate 			    instance, ddi_node_name(bpc->bpc_dip),
15460Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
15470Sstevel@tonic-gate 			    bpc->bpc_olevel, bpc->bpc_nlevel);
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 			if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
15500Sstevel@tonic-gate 			    bpc->bpc_olevel <= 0) &&
15510Sstevel@tonic-gate 			    (pshot->state & PM_SUPPORTED)) {
15520Sstevel@tonic-gate 				mutex_enter(&pshot->lock);
15530Sstevel@tonic-gate 				ASSERT(pshot->busy > 0);
15540Sstevel@tonic-gate 				--(pshot->busy);
15550Sstevel@tonic-gate 				if (pshot_debug_busy) {
15560Sstevel@tonic-gate 					cmn_err(CE_CONT, "%s%d:"
15570Sstevel@tonic-gate 					    " post_bus_power_failed:"
15580Sstevel@tonic-gate 					    " idle parent for %s%d"
15590Sstevel@tonic-gate 					    " (%d->%d): busy = %d\n",
15600Sstevel@tonic-gate 					    name, instance,
15610Sstevel@tonic-gate 					    ddi_node_name(bpc->bpc_dip),
15620Sstevel@tonic-gate 					    ddi_get_instance(bpc->bpc_dip),
15630Sstevel@tonic-gate 					    bpc->bpc_olevel, bpc->bpc_nlevel,
15640Sstevel@tonic-gate 					    pshot->busy);
15650Sstevel@tonic-gate 				}
15660Sstevel@tonic-gate 				mutex_exit(&pshot->lock);
15670Sstevel@tonic-gate 				ret = pm_idle_component(dip, 0);
15680Sstevel@tonic-gate 				ASSERT(ret == DDI_SUCCESS);
15690Sstevel@tonic-gate 			}
15700Sstevel@tonic-gate 		}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 		/*
15730Sstevel@tonic-gate 		 * Mark nexus idle when a child's comp 0
15740Sstevel@tonic-gate 		 * is set to level 0 from level 1, 2, or 3 only.
15750Sstevel@tonic-gate 		 * And only if result arg == DDI_SUCCESS.
15760Sstevel@tonic-gate 		 * This will leave the parent busy when the child
15770Sstevel@tonic-gate 		 * does not call pm_lower_power() on detach after
15780Sstevel@tonic-gate 		 * unsetting the NO_LOWER_POWER flag.
15790Sstevel@tonic-gate 		 * If so, need to notify the parent to mark itself
15800Sstevel@tonic-gate 		 * idle anyway, else the no-involumtary-power-cycles
15810Sstevel@tonic-gate 		 * test cases will report false passes!
15820Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
15830Sstevel@tonic-gate 		 */
15840Sstevel@tonic-gate 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 &&
15850Sstevel@tonic-gate 		    !(bpc->bpc_olevel <= 0) &&
15860Sstevel@tonic-gate 		    *(int *)result == DDI_SUCCESS) &&
15870Sstevel@tonic-gate 		    (pshot->state & PM_SUPPORTED)) {
15880Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
15890Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
15900Sstevel@tonic-gate 			--(pshot->busy);
15910Sstevel@tonic-gate 			if (pshot_debug_busy) {
15920Sstevel@tonic-gate 				cmn_err(CE_CONT,
15930Sstevel@tonic-gate 				    "%s%d: post_bus_power:"
15940Sstevel@tonic-gate 				    " idle parent for %s%d (%d->%d):"
15950Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
15960Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
15970Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
15980Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel,
15990Sstevel@tonic-gate 				    pshot->busy);
16000Sstevel@tonic-gate 			}
16010Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
16020Sstevel@tonic-gate 			ret = pm_idle_component(dip, 0);
16030Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
16040Sstevel@tonic-gate 		}
16050Sstevel@tonic-gate 		break;
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	case BUS_POWER_HAS_CHANGED:
16080Sstevel@tonic-gate 		bphc = (pm_bp_has_changed_t *)arg;
16090Sstevel@tonic-gate 		if (pshot_debug) {
16100Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: has_changed_bus_power:"
16110Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d) result %d\n",
16120Sstevel@tonic-gate 			    name, instance, ddi_node_name(bphc->bphc_dip),
16130Sstevel@tonic-gate 			    ddi_get_instance(bphc->bphc_dip),
16140Sstevel@tonic-gate 			    bphc->bphc_comp, bphc->bphc_olevel,
16150Sstevel@tonic-gate 			    bphc->bphc_nlevel, *(int *)result);
16160Sstevel@tonic-gate 		}
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 		/*
16190Sstevel@tonic-gate 		 * Mark nexus idle when a child's comp 0
16200Sstevel@tonic-gate 		 * is set to level 0 from levels 1, 2, or 3 only.
16210Sstevel@tonic-gate 		 *
16220Sstevel@tonic-gate 		 * If powering up child leaf/nexus nodes via
16230Sstevel@tonic-gate 		 * pm_power_has_changed() calls, first issue
16240Sstevel@tonic-gate 		 * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
16250Sstevel@tonic-gate 		 * before powering the parent up, then power up the
16260Sstevel@tonic-gate 		 * child node.
16270Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
16280Sstevel@tonic-gate 		 */
16290Sstevel@tonic-gate 		if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 &&
16300Sstevel@tonic-gate 		    !(bphc->bphc_olevel <= 0)) &&
16310Sstevel@tonic-gate 		    pshot->state & PM_SUPPORTED) {
16320Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
16330Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
16340Sstevel@tonic-gate 			--(pshot->busy);
16350Sstevel@tonic-gate 			if (pshot_debug_busy) {
16360Sstevel@tonic-gate 				cmn_err(CE_CONT,
16370Sstevel@tonic-gate 				    "%s%d: has_changed_bus_power:"
16380Sstevel@tonic-gate 				    " idle parent for %s%d (%d->%d):"
16390Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
16400Sstevel@tonic-gate 				    ddi_node_name(bphc->bphc_dip),
16410Sstevel@tonic-gate 				    ddi_get_instance(bphc->bphc_dip),
16420Sstevel@tonic-gate 				    bphc->bphc_olevel,
16430Sstevel@tonic-gate 				    bphc->bphc_nlevel, pshot->busy);
16440Sstevel@tonic-gate 			}
16450Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
16460Sstevel@tonic-gate 			ret = pm_idle_component(dip, 0);
16470Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
16480Sstevel@tonic-gate 		}
16490Sstevel@tonic-gate 		break;
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 	default:
16520Sstevel@tonic-gate 		return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	}
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	return (DDI_SUCCESS);
16570Sstevel@tonic-gate }
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate static int
pshot_initchild(dev_info_t * dip,dev_info_t * child)16600Sstevel@tonic-gate pshot_initchild(dev_info_t *dip, dev_info_t *child)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate 	char	name[64];
16630Sstevel@tonic-gate 	char	*bus_addr;
16640Sstevel@tonic-gate 	char	*c_nodename;
16650Sstevel@tonic-gate 	int	bus_id;
16660Sstevel@tonic-gate 	dev_info_t *enum_child;
16670Sstevel@tonic-gate 	int	enum_base;
16680Sstevel@tonic-gate 	int	enum_extent;
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 
16710Sstevel@tonic-gate 	/* check for bus_enum node */
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate #ifdef	NOT_USED
16740Sstevel@tonic-gate 	if (impl_ddi_merge_child(child) != DDI_SUCCESS)
16750Sstevel@tonic-gate 		return (DDI_FAILURE);
16760Sstevel@tonic-gate #endif
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 	enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
16790Sstevel@tonic-gate 	    "busid_ebase", 0);
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 	enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child,
16820Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "busid_range", 0);
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	/*
16850Sstevel@tonic-gate 	 * bus enumeration node
16860Sstevel@tonic-gate 	 */
16870Sstevel@tonic-gate 	if ((enum_base != 0) && (enum_extent != 0))	{
16880Sstevel@tonic-gate 		c_nodename = ddi_node_name(child);
16890Sstevel@tonic-gate 		bus_id = enum_base;
16900Sstevel@tonic-gate 		for (; bus_id < enum_extent; bus_id++) {
16910Sstevel@tonic-gate 			if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID,
16920Sstevel@tonic-gate 			    &enum_child) != NDI_SUCCESS)
16930Sstevel@tonic-gate 				return (DDI_FAILURE);
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 			(void) sprintf(name, "%d", bus_id);
16960Sstevel@tonic-gate 			if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child,
16970Sstevel@tonic-gate 			    "bus-addr", name) != DDI_PROP_SUCCESS) {
16980Sstevel@tonic-gate 				(void) ndi_devi_free(enum_child);
16990Sstevel@tonic-gate 				return (DDI_FAILURE);
17000Sstevel@tonic-gate 			}
17010Sstevel@tonic-gate 
17020Sstevel@tonic-gate 			if (ndi_devi_online(enum_child, 0) !=
17030Sstevel@tonic-gate 			    DDI_SUCCESS) {
17040Sstevel@tonic-gate 				(void) ndi_devi_free(enum_child);
17050Sstevel@tonic-gate 				return (DDI_FAILURE);
17060Sstevel@tonic-gate 			}
17070Sstevel@tonic-gate 		}
17080Sstevel@tonic-gate 		/*
17090Sstevel@tonic-gate 		 * fail the enumeration node itself
17100Sstevel@tonic-gate 		 */
17110Sstevel@tonic-gate 		return (DDI_FAILURE);
17120Sstevel@tonic-gate 	}
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr",
17150Sstevel@tonic-gate 	    &bus_addr) != DDI_PROP_SUCCESS) {
17160Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)",
17170Sstevel@tonic-gate 		    ddi_node_name(child));
17180Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
17190Sstevel@tonic-gate 	}
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	if (strlen(bus_addr) == 0) {
17220Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)",
17230Sstevel@tonic-gate 		    ddi_node_name(child));
17240Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
17250Sstevel@tonic-gate 		return (DDI_FAILURE);
17260Sstevel@tonic-gate 	}
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 	if (strncmp(bus_addr, "failinit", 8) == 0) {
17290Sstevel@tonic-gate 		if (pshot_debug)
17300Sstevel@tonic-gate 			cmn_err(CE_CONT,
17310Sstevel@tonic-gate 			    "pshot%d: %s forced INITCHILD failure\n",
17327656SSherry.Moore@Sun.COM 			    ddi_get_instance(dip), bus_addr);
17330Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
17340Sstevel@tonic-gate 		return (DDI_FAILURE);
17350Sstevel@tonic-gate 	}
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 	if (pshot_log) {
17380Sstevel@tonic-gate 		cmn_err(CE_CONT, "initchild %s%d/%s@%s\n",
17397656SSherry.Moore@Sun.COM 		    ddi_get_name(dip), ddi_get_instance(dip),
17407656SSherry.Moore@Sun.COM 		    ddi_node_name(child), bus_addr);
17410Sstevel@tonic-gate 	}
17420Sstevel@tonic-gate 
17430Sstevel@tonic-gate 	ddi_set_name_addr(child, bus_addr);
17440Sstevel@tonic-gate 	ddi_prop_free(bus_addr);
17450Sstevel@tonic-gate 	return (DDI_SUCCESS);
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate /*ARGSUSED*/
17490Sstevel@tonic-gate static int
pshot_uninitchild(dev_info_t * dip,dev_info_t * child)17500Sstevel@tonic-gate pshot_uninitchild(dev_info_t *dip, dev_info_t *child)
17510Sstevel@tonic-gate {
17520Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
17530Sstevel@tonic-gate 	return (DDI_SUCCESS);
17540Sstevel@tonic-gate }
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate /*
17580Sstevel@tonic-gate  * devctl IOCTL support
17590Sstevel@tonic-gate  */
17600Sstevel@tonic-gate /* ARGSUSED */
17610Sstevel@tonic-gate static int
pshot_open(dev_t * devp,int flags,int otyp,cred_t * credp)17620Sstevel@tonic-gate pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp)
17630Sstevel@tonic-gate {
17640Sstevel@tonic-gate 	int instance;
17650Sstevel@tonic-gate 	pshot_t *pshot;
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
17680Sstevel@tonic-gate 		return (EINVAL);
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(*devp));
17710Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
17720Sstevel@tonic-gate 		return (ENXIO);
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	/*
17750Sstevel@tonic-gate 	 * Access is currently determined on a per-instance basis.
17760Sstevel@tonic-gate 	 * If we want per-node, then need to add state and lock members to
17770Sstevel@tonic-gate 	 * pshot_minor_t
17780Sstevel@tonic-gate 	 */
17790Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
17800Sstevel@tonic-gate 	if (((flags & FEXCL) && (pshot->state & IS_OPEN)) ||
17810Sstevel@tonic-gate 	    (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) {
17820Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
17830Sstevel@tonic-gate 		return (EBUSY);
17840Sstevel@tonic-gate 	}
17850Sstevel@tonic-gate 	pshot->state |= IS_OPEN;
17860Sstevel@tonic-gate 	if (flags & FEXCL)
17870Sstevel@tonic-gate 		pshot->state |= IS_OPEN_EXCL;
17880Sstevel@tonic-gate 
17890Sstevel@tonic-gate 	if (pshot_debug)
17900Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d open\n", instance);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
17930Sstevel@tonic-gate 	return (0);
17940Sstevel@tonic-gate }
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate /*
17970Sstevel@tonic-gate  * pshot_close
17980Sstevel@tonic-gate  */
17990Sstevel@tonic-gate /* ARGSUSED */
18000Sstevel@tonic-gate static int
pshot_close(dev_t dev,int flag,int otyp,cred_t * credp)18010Sstevel@tonic-gate pshot_close(dev_t dev, int flag, int otyp, cred_t *credp)
18020Sstevel@tonic-gate {
18030Sstevel@tonic-gate 	int instance;
18040Sstevel@tonic-gate 	pshot_t *pshot;
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
18070Sstevel@tonic-gate 		return (EINVAL);
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(dev));
18100Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
18110Sstevel@tonic-gate 		return (ENXIO);
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
18140Sstevel@tonic-gate 	pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL);
18150Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
18160Sstevel@tonic-gate 	if (pshot_debug)
18170Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d closed\n", instance);
18180Sstevel@tonic-gate 	return (0);
18190Sstevel@tonic-gate }
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate /*
18230Sstevel@tonic-gate  * pshot_ioctl: redirects to appropriate command handler based on various
18240Sstevel@tonic-gate  * 	criteria
18250Sstevel@tonic-gate  */
18260Sstevel@tonic-gate /* ARGSUSED */
18270Sstevel@tonic-gate static int
pshot_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)18280Sstevel@tonic-gate pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
18290Sstevel@tonic-gate     int *rvalp)
18300Sstevel@tonic-gate {
18310Sstevel@tonic-gate 	pshot_t *pshot;
18320Sstevel@tonic-gate 	int instance;
18330Sstevel@tonic-gate 	minor_t nodenum;
18340Sstevel@tonic-gate 	char *nodename;
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(dev));
18370Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
18380Sstevel@tonic-gate 		return (ENXIO);
18390Sstevel@tonic-gate 
18400Sstevel@tonic-gate 	nodenum = pshot_minor_decode_nodenum(getminor(dev));
18410Sstevel@tonic-gate 	nodename = pshot->nodes[nodenum].name;
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 	if (pshot_debug)
18440Sstevel@tonic-gate 		cmn_err(CE_CONT,
18450Sstevel@tonic-gate 		    "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
18460Sstevel@tonic-gate 		    instance, (void *)dev, cmd, (void *)arg, mode);
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0)
18490Sstevel@tonic-gate 		return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp,
18500Sstevel@tonic-gate 		    rvalp));
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0)
18530Sstevel@tonic-gate 		return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp,
18540Sstevel@tonic-gate 		    rvalp));
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 	cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u",
18570Sstevel@tonic-gate 	    pshot->nodes[nodenum].minor);
18580Sstevel@tonic-gate 	return (ENXIO);
18590Sstevel@tonic-gate }
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate /*
18630Sstevel@tonic-gate  * pshot_devctl: handle DEVCTL operations
18640Sstevel@tonic-gate  */
18650Sstevel@tonic-gate /* ARGSUSED */
18660Sstevel@tonic-gate static int
pshot_devctl(pshot_t * pshot,minor_t nodenum,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)18670Sstevel@tonic-gate pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
18680Sstevel@tonic-gate     cred_t *credp, int *rvalp)
18690Sstevel@tonic-gate {
18700Sstevel@tonic-gate 	dev_info_t *self;
18710Sstevel@tonic-gate 	dev_info_t *child = NULL;
18720Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
18730Sstevel@tonic-gate 	uint_t state;
18740Sstevel@tonic-gate 	int rv = 0;
18750Sstevel@tonic-gate 	uint_t flags;
18760Sstevel@tonic-gate 	int instance;
18770Sstevel@tonic-gate 	int i;
18780Sstevel@tonic-gate 	int ret;
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	self = pshot->dip;
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 	flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0;
18830Sstevel@tonic-gate 	instance = pshot->instance;
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 	/*
18860Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
18870Sstevel@tonic-gate 	 */
18880Sstevel@tonic-gate 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
18890Sstevel@tonic-gate 		if (pshot_devctls[i].ioctl_int == cmd) {
18900Sstevel@tonic-gate 			if (pshot_debug)
18910Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d devctl: %s",
18920Sstevel@tonic-gate 				    instance, pshot_devctls[i].ioctl_char);
18930Sstevel@tonic-gate 		}
18940Sstevel@tonic-gate 	}
18950Sstevel@tonic-gate 	switch (cmd) {
18960Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
18970Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
18980Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
18990Sstevel@tonic-gate 	case DEVCTL_DEVICE_REMOVE:
19000Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
19010Sstevel@tonic-gate 	case DEVCTL_BUS_DEV_CREATE:
19020Sstevel@tonic-gate 		rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags);
19030Sstevel@tonic-gate 		if (pshot_debug && rv != 0) {
19040Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:"
19050Sstevel@tonic-gate 			    " failed, rv = %d", instance, rv);
19060Sstevel@tonic-gate 		}
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 		return (rv);
19090Sstevel@tonic-gate 	}
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	/*
19120Sstevel@tonic-gate 	 * read devctl ioctl data
19130Sstevel@tonic-gate 	 */
19140Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
19150Sstevel@tonic-gate 		return (EFAULT);
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	switch (cmd) {
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
19200Sstevel@tonic-gate 		if (pshot_debug)
19210Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19220Sstevel@tonic-gate 			    " DEVCTL_DEVICE_RESET\n", instance);
19230Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
19240Sstevel@tonic-gate 		    child, (void *)self);
19250Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19260Sstevel@tonic-gate 		break;
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
19290Sstevel@tonic-gate 		if (pshot_debug)
19300Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19310Sstevel@tonic-gate 			    " DEVCTL_BUS_QUIESCE\n", instance);
19320Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
19330Sstevel@tonic-gate 			if (state == BUS_QUIESCED) {
19340Sstevel@tonic-gate 				break;
19350Sstevel@tonic-gate 			}
19360Sstevel@tonic-gate 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
19370Sstevel@tonic-gate 		}
19380Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
19390Sstevel@tonic-gate 		    child, (void *)self);
19400Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19410Sstevel@tonic-gate 
19420Sstevel@tonic-gate 		break;
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
19450Sstevel@tonic-gate 		if (pshot_debug)
19460Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19470Sstevel@tonic-gate 			    " DEVCTL_BUS_UNQUIESCE\n", instance);
19480Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
19490Sstevel@tonic-gate 			if (state == BUS_ACTIVE) {
19500Sstevel@tonic-gate 				break;
19510Sstevel@tonic-gate 			}
19520Sstevel@tonic-gate 		}
19530Sstevel@tonic-gate 
19540Sstevel@tonic-gate 		/*
19550Sstevel@tonic-gate 		 * quiesce the bus through bus-specific means
19560Sstevel@tonic-gate 		 */
19570Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
19580Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
19590Sstevel@tonic-gate 		    child, (void *)self);
19600Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19610Sstevel@tonic-gate 		break;
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
19640Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
19650Sstevel@tonic-gate 		/*
19660Sstevel@tonic-gate 		 * no reset support for the pseudo bus
19670Sstevel@tonic-gate 		 * but if there were....
19680Sstevel@tonic-gate 		 */
19690Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
19707656SSherry.Moore@Sun.COM 		    child, (void *)self);
19710Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19720Sstevel@tonic-gate 		break;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	/*
19750Sstevel@tonic-gate 	 * PM related ioctls
19760Sstevel@tonic-gate 	 */
19770Sstevel@tonic-gate 	case DEVCTL_PM_BUSY_COMP:
19780Sstevel@tonic-gate 		/*
19790Sstevel@tonic-gate 		 * mark component 0 busy.
19800Sstevel@tonic-gate 		 * Keep track of ioctl updates to the busy count
19810Sstevel@tonic-gate 		 * via pshot->busy_ioctl.
19820Sstevel@tonic-gate 		 */
19830Sstevel@tonic-gate 		if (pshot_debug) {
19840Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19850Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP\n", instance);
19860Sstevel@tonic-gate 		}
19870Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
19880Sstevel@tonic-gate 		++(pshot->busy);
19890Sstevel@tonic-gate 		++(pshot->busy_ioctl);
19900Sstevel@tonic-gate 		if (pshot_debug_busy) {
19910Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d:"
19920Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP comp 0 busy"
19930Sstevel@tonic-gate 			    " %d busy_ioctl %d\n", instance, pshot->busy,
19940Sstevel@tonic-gate 			    pshot->busy_ioctl);
19950Sstevel@tonic-gate 		}
19960Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
19970Sstevel@tonic-gate 		ret = pm_busy_component(pshot->dip, 0);
19980Sstevel@tonic-gate 		ASSERT(ret == DDI_SUCCESS);
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 		break;
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate 	case DEVCTL_PM_BUSY_COMP_TEST:
20030Sstevel@tonic-gate 		/*
20040Sstevel@tonic-gate 		 * test bus's busy state
20050Sstevel@tonic-gate 		 */
20060Sstevel@tonic-gate 		if (pshot_debug) {
20070Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20080Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP_TEST\n", instance);
20090Sstevel@tonic-gate 		}
20100Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
20110Sstevel@tonic-gate 		state = pshot->busy;
20120Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
20130Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
20140Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
20150Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
20160Sstevel@tonic-gate 			    instance);
20170Sstevel@tonic-gate 			rv = EINVAL;
20180Sstevel@tonic-gate 		}
20190Sstevel@tonic-gate 		if (pshot_debug_busy) {
20200Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:"
20210Sstevel@tonic-gate 			    " comp 0 busy %d busy_ioctl %d\n", instance,
20220Sstevel@tonic-gate 			    state, pshot->busy_ioctl);
20230Sstevel@tonic-gate 		}
20240Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
20250Sstevel@tonic-gate 		break;
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 	case DEVCTL_PM_IDLE_COMP:
20280Sstevel@tonic-gate 		/*
20290Sstevel@tonic-gate 		 * mark component 0 idle.
20300Sstevel@tonic-gate 		 * NOP if pshot->busy_ioctl <= 0.
20310Sstevel@tonic-gate 		 */
20320Sstevel@tonic-gate 		if (pshot_debug) {
20330Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20340Sstevel@tonic-gate 			    " DEVCTL_PM_IDLE_COMP\n", instance);
20350Sstevel@tonic-gate 		}
20360Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
20370Sstevel@tonic-gate 		if (pshot->busy_ioctl > 0) {
20380Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
20390Sstevel@tonic-gate 			--(pshot->busy);
20400Sstevel@tonic-gate 			--(pshot->busy_ioctl);
20410Sstevel@tonic-gate 			if (pshot_debug_busy) {
20420Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
20430Sstevel@tonic-gate 				    " DEVCTL_PM_IDLE_COM: comp 0"
20440Sstevel@tonic-gate 				    " busy %d busy_ioctl %d\n", instance,
20450Sstevel@tonic-gate 				    pshot->busy, pshot->busy_ioctl);
20460Sstevel@tonic-gate 			}
20470Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20480Sstevel@tonic-gate 			ret = pm_idle_component(pshot->dip, 0);
20490Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 		} else {
20520Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20530Sstevel@tonic-gate 		}
20540Sstevel@tonic-gate 		break;
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 	case DEVCTL_PM_RAISE_PWR:
20570Sstevel@tonic-gate 		/*
20580Sstevel@tonic-gate 		 * raise component 0 to full power level MAXPWR via a
20590Sstevel@tonic-gate 		 * pm_raise_power() call
20600Sstevel@tonic-gate 		 */
20610Sstevel@tonic-gate 		if (pshot_debug) {
20620Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20630Sstevel@tonic-gate 			    " DEVCTL_PM_RAISE_PWR\n", instance);
20640Sstevel@tonic-gate 		}
20650Sstevel@tonic-gate 		if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) {
20660Sstevel@tonic-gate 			rv = EINVAL;
20670Sstevel@tonic-gate 		} else {
20680Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
20690Sstevel@tonic-gate 			if (pshot_debug) {
20700Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
20710Sstevel@tonic-gate 				    " DEVCTL_PM_RAISE_POWER: comp 0"
20720Sstevel@tonic-gate 				    " to level %d\n", instance, pshot->level);
20730Sstevel@tonic-gate 			}
20740Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20750Sstevel@tonic-gate 		}
20760Sstevel@tonic-gate 		break;
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	case DEVCTL_PM_LOWER_PWR:
20790Sstevel@tonic-gate 		/*
20800Sstevel@tonic-gate 		 * pm_lower_power() call for negative testing
20810Sstevel@tonic-gate 		 * expected to fail.
20820Sstevel@tonic-gate 		 */
20830Sstevel@tonic-gate 		if (pshot_debug) {
20840Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20850Sstevel@tonic-gate 			    " DEVCTL_PM_LOWER_PWR\n", instance);
20860Sstevel@tonic-gate 		}
20870Sstevel@tonic-gate 		if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
20880Sstevel@tonic-gate 			rv = EINVAL;
20890Sstevel@tonic-gate 		} else {
20900Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
20910Sstevel@tonic-gate 			if (pshot_debug) {
20920Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
20930Sstevel@tonic-gate 				    " DEVCTL_PM_LOWER_POWER comp 0"
20940Sstevel@tonic-gate 				    " to level %d\n", instance, pshot->level);
20950Sstevel@tonic-gate 			}
20960Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20970Sstevel@tonic-gate 		}
20980Sstevel@tonic-gate 		break;
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate 	case DEVCTL_PM_CHANGE_PWR_LOW:
21010Sstevel@tonic-gate 		/*
21020Sstevel@tonic-gate 		 * inform the PM framework that component 0 has changed
21030Sstevel@tonic-gate 		 * power level to 0 via a pm_power_has_changed() call
21040Sstevel@tonic-gate 		 */
21050Sstevel@tonic-gate 		if (pshot_debug) {
21060Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21070Sstevel@tonic-gate 			    " DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
21080Sstevel@tonic-gate 		}
21090Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21100Sstevel@tonic-gate 		pshot->level = 0;
21110Sstevel@tonic-gate 		if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) {
21120Sstevel@tonic-gate 			rv = EINVAL;
21130Sstevel@tonic-gate 		} else {
21140Sstevel@tonic-gate 			if (pshot_debug) {
21150Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
21160Sstevel@tonic-gate 				    " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
21170Sstevel@tonic-gate 				    " level %d\n", instance, pshot->level);
21180Sstevel@tonic-gate 			}
21190Sstevel@tonic-gate 		}
21200Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21210Sstevel@tonic-gate 		break;
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate 	case DEVCTL_PM_CHANGE_PWR_HIGH:
21240Sstevel@tonic-gate 		/*
21250Sstevel@tonic-gate 		 * inform the PM framework that component 0 has changed
21260Sstevel@tonic-gate 		 * power level to MAXPWR via a pm_power_has_changed() call
21270Sstevel@tonic-gate 		 */
21280Sstevel@tonic-gate 		if (pshot_debug) {
21290Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21300Sstevel@tonic-gate 			    " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
21310Sstevel@tonic-gate 		}
21320Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21330Sstevel@tonic-gate 		pshot->level = MAXPWR;
21340Sstevel@tonic-gate 		if (pm_power_has_changed(pshot->dip, 0, MAXPWR)
21350Sstevel@tonic-gate 		    != DDI_SUCCESS) {
21360Sstevel@tonic-gate 			rv = EINVAL;
21370Sstevel@tonic-gate 		} else {
21380Sstevel@tonic-gate 			if (pshot_debug) {
21390Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
21400Sstevel@tonic-gate 				    " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
21410Sstevel@tonic-gate 				    " level %d\n", instance, pshot->level);
21420Sstevel@tonic-gate 			}
21430Sstevel@tonic-gate 		}
21440Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21450Sstevel@tonic-gate 		break;
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate 	case DEVCTL_PM_POWER:
21480Sstevel@tonic-gate 		/*
21490Sstevel@tonic-gate 		 * test if the pshot_power() routine has been called,
21500Sstevel@tonic-gate 		 * then clear
21510Sstevel@tonic-gate 		 */
21520Sstevel@tonic-gate 		if (pshot_debug) {
21530Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21540Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
21550Sstevel@tonic-gate 		}
21560Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21570Sstevel@tonic-gate 		state = (pshot->state & POWER_FLAG) ? 1 : 0;
21580Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
21590Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
21600Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
21610Sstevel@tonic-gate 			    " DEVCTL_PM_POWER: copyout failed",
21620Sstevel@tonic-gate 			    instance);
21630Sstevel@tonic-gate 			rv = EINVAL;
21640Sstevel@tonic-gate 		}
21650Sstevel@tonic-gate 		if (pshot_debug) {
21660Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:"
21670Sstevel@tonic-gate 			    " POWER_FLAG = %d\n", instance, state);
21680Sstevel@tonic-gate 		}
21690Sstevel@tonic-gate 		pshot->state &= ~POWER_FLAG;
21700Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21710Sstevel@tonic-gate 		break;
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	case DEVCTL_PM_FAIL_SUSPEND:
21740Sstevel@tonic-gate 		/*
21750Sstevel@tonic-gate 		 * fail DDI_SUSPEND
21760Sstevel@tonic-gate 		 */
21770Sstevel@tonic-gate 		if (pshot_debug) {
21780Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21790Sstevel@tonic-gate 			    " DEVCTL_PM_FAIL_SUSPEND\n", instance);
21800Sstevel@tonic-gate 		}
21810Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21820Sstevel@tonic-gate 		pshot->state |= FAIL_SUSPEND_FLAG;
21830Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21840Sstevel@tonic-gate 		if (pshot_debug) {
21850Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n",
21860Sstevel@tonic-gate 			    instance);
21870Sstevel@tonic-gate 		}
21880Sstevel@tonic-gate 		break;
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	case DEVCTL_PM_BUS_STRICT_TEST:
21910Sstevel@tonic-gate 		/*
21920Sstevel@tonic-gate 		 * test the STRICT_PARENT flag:
21930Sstevel@tonic-gate 		 *	set => STRICT PARENT
21940Sstevel@tonic-gate 		 *	not set => INVOLVED PARENT
21950Sstevel@tonic-gate 		 */
21960Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21970Sstevel@tonic-gate 		state = (pshot->state & STRICT_PARENT) ? 1 : 0;
21980Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
21990Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
22000Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
22010Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
22020Sstevel@tonic-gate 			    instance);
22030Sstevel@tonic-gate 			rv = EINVAL;
22040Sstevel@tonic-gate 		}
22050Sstevel@tonic-gate 		if (pshot_debug) {
22060Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
22070Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
22080Sstevel@tonic-gate 			    instance, ((state == 0) ? "INVOLVED" : "STRICT"));
22090Sstevel@tonic-gate 		}
22100Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
22110Sstevel@tonic-gate 		break;
22120Sstevel@tonic-gate 
22130Sstevel@tonic-gate 	case DEVCTL_PM_BUS_NO_INVOL:
22140Sstevel@tonic-gate 		/*
22150Sstevel@tonic-gate 		 * Set the NO_INVOL_FLAG flag to
22160Sstevel@tonic-gate 		 * notify the driver that the child will not
22170Sstevel@tonic-gate 		 * call pm_lower_power() on detach.
22180Sstevel@tonic-gate 		 * The driver needs to mark itself idle twice
22190Sstevel@tonic-gate 		 * during DDI_CTLOPS_DETACH (post).
22200Sstevel@tonic-gate 		 */
22210Sstevel@tonic-gate 		if (pshot_debug) {
22220Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
22230Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_NO_INVOL\n", instance);
22240Sstevel@tonic-gate 		}
22250Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
22260Sstevel@tonic-gate 		pshot->state |= NO_INVOL_FLAG;
22270Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
22280Sstevel@tonic-gate 		break;
22290Sstevel@tonic-gate 
22300Sstevel@tonic-gate 	default:
22310Sstevel@tonic-gate 		rv = ENOTTY;
22320Sstevel@tonic-gate 	}
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
22350Sstevel@tonic-gate 	return (rv);
22360Sstevel@tonic-gate }
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate /*
22400Sstevel@tonic-gate  * pshot_testctl: handle other test operations
22410Sstevel@tonic-gate  *	- If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
22420Sstevel@tonic-gate  *	  child to direct the DEVCTL to, if applicable;
22430Sstevel@tonic-gate  *	  furthermore, any cmd here can be sent by layered ioctls (unlike
22440Sstevel@tonic-gate  *	  those to pshot_devctl() which must come from userland)
22450Sstevel@tonic-gate  */
22460Sstevel@tonic-gate /* ARGSUSED */
22470Sstevel@tonic-gate static int
pshot_testctl(pshot_t * pshot,minor_t nodenum,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)22480Sstevel@tonic-gate pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
22490Sstevel@tonic-gate     cred_t *credp, int *rvalp)
22500Sstevel@tonic-gate {
22510Sstevel@tonic-gate 	dev_info_t *self;
22520Sstevel@tonic-gate 	dev_info_t *child = NULL;
22530Sstevel@tonic-gate 	uint_t state;
22540Sstevel@tonic-gate 	int rv = 0;
22550Sstevel@tonic-gate 	int instance;
22560Sstevel@tonic-gate 	int i;
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 	/* uint_t flags; */
22590Sstevel@tonic-gate 
22600Sstevel@tonic-gate 	/* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
22610Sstevel@tonic-gate 	self = pshot->dip;
22620Sstevel@tonic-gate 	instance = pshot->instance;
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	if (cmd & DEVCTL_IOC) {
22650Sstevel@tonic-gate 		child = e_ddi_hold_devi_by_dev((dev_t)arg, 0);
22660Sstevel@tonic-gate 	}
22670Sstevel@tonic-gate 
22680Sstevel@tonic-gate 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
22690Sstevel@tonic-gate 		if (pshot_devctls[i].ioctl_int == cmd) {
22700Sstevel@tonic-gate 			if (pshot_debug)
22710Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d devctl: %s",
22720Sstevel@tonic-gate 				    instance, pshot_devctls[i].ioctl_char);
22730Sstevel@tonic-gate 		}
22740Sstevel@tonic-gate 	}
22750Sstevel@tonic-gate 	switch (cmd) {
22760Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
22770Sstevel@tonic-gate 		if (pshot_debug)
22780Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
22790Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
22800Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
22810Sstevel@tonic-gate 		    child, (void *)self);
22820Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
22830Sstevel@tonic-gate 		break;
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
22860Sstevel@tonic-gate 		if (pshot_debug)
22870Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
22880Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
22890Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
22900Sstevel@tonic-gate 			if (state == BUS_QUIESCED) {
22910Sstevel@tonic-gate 				break;
22920Sstevel@tonic-gate 			}
22930Sstevel@tonic-gate 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
22940Sstevel@tonic-gate 		}
22950Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
22960Sstevel@tonic-gate 		    child, (void *)self);
22970Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 		break;
23000Sstevel@tonic-gate 
23010Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
23020Sstevel@tonic-gate 		if (pshot_debug)
23030Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
23040Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
23050Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
23060Sstevel@tonic-gate 			if (state == BUS_ACTIVE) {
23070Sstevel@tonic-gate 				break;
23080Sstevel@tonic-gate 			}
23090Sstevel@tonic-gate 		}
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 		/*
23120Sstevel@tonic-gate 		 * quiesce the bus through bus-specific means
23130Sstevel@tonic-gate 		 */
23140Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
23150Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
23160Sstevel@tonic-gate 		    child, (void *)self);
23170Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
23180Sstevel@tonic-gate 		break;
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
23210Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
23220Sstevel@tonic-gate 		/*
23230Sstevel@tonic-gate 		 * no reset support for the pseudo bus
23240Sstevel@tonic-gate 		 * but if there were....
23250Sstevel@tonic-gate 		 */
23260Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
23277656SSherry.Moore@Sun.COM 		    child, (void *)self);
23280Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
23290Sstevel@tonic-gate 		break;
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 	default:
23320Sstevel@tonic-gate 		rv = ENOTTY;
23330Sstevel@tonic-gate 	}
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate 	if (child != NULL)
23360Sstevel@tonic-gate 		ddi_release_devi(child);
23370Sstevel@tonic-gate 	return (rv);
23380Sstevel@tonic-gate }
23390Sstevel@tonic-gate 
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate static int
pshot_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * event_cookiep)23420Sstevel@tonic-gate pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
23430Sstevel@tonic-gate 	char *eventname, ddi_eventcookie_t *event_cookiep)
23440Sstevel@tonic-gate {
23450Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
23460Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	if (pshot_debug)
23497656SSherry.Moore@Sun.COM 		cmn_err(CE_CONT, "pshot%d: "
23507656SSherry.Moore@Sun.COM 		    "pshot_get_eventcookie:\n\t"
23517656SSherry.Moore@Sun.COM 		    "dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
23527656SSherry.Moore@Sun.COM 		    instance, (void *)dip, (void *)rdip,
23537656SSherry.Moore@Sun.COM 		    ddi_node_name(rdip), ddi_get_instance(rdip),
23547656SSherry.Moore@Sun.COM 		    eventname);
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 
23570Sstevel@tonic-gate 	return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl,
23587656SSherry.Moore@Sun.COM 	    rdip, eventname, event_cookiep, NDI_EVENT_NOPASS));
23590Sstevel@tonic-gate }
23600Sstevel@tonic-gate 
23610Sstevel@tonic-gate static int
pshot_add_eventcall(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void (* callback)(),void * arg,ddi_callback_id_t * cb_id)23620Sstevel@tonic-gate pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
23630Sstevel@tonic-gate 	ddi_eventcookie_t cookie,
23640Sstevel@tonic-gate 	void (*callback)(), void *arg, ddi_callback_id_t *cb_id)
23650Sstevel@tonic-gate {
23660Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
23670Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 	if (pshot_debug)
23707656SSherry.Moore@Sun.COM 		cmn_err(CE_CONT, "pshot%d: "
23717656SSherry.Moore@Sun.COM 		    "pshot_add_eventcall:\n\t"
23727656SSherry.Moore@Sun.COM 		    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
23737656SSherry.Moore@Sun.COM 		    "cb = 0x%p, arg = 0x%p\n",
23747656SSherry.Moore@Sun.COM 		    instance, (void *)dip, (void *)rdip,
23757656SSherry.Moore@Sun.COM 		    ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
23767656SSherry.Moore@Sun.COM 		    NDI_EVENT_NAME(cookie), (void *)callback, arg);
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 	/* add callback to our event handle */
23790Sstevel@tonic-gate 	return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip,
23807656SSherry.Moore@Sun.COM 	    cookie, callback, arg, NDI_SLEEP, cb_id));
23810Sstevel@tonic-gate }
23820Sstevel@tonic-gate 
23830Sstevel@tonic-gate static int
pshot_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)23840Sstevel@tonic-gate pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
23850Sstevel@tonic-gate {
23860Sstevel@tonic-gate 
23870Sstevel@tonic-gate 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
23900Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
23910Sstevel@tonic-gate 
23920Sstevel@tonic-gate 	ASSERT(cb);
23930Sstevel@tonic-gate 
23940Sstevel@tonic-gate 	if (pshot_debug)
23957656SSherry.Moore@Sun.COM 		cmn_err(CE_CONT, "pshot%d: "
23967656SSherry.Moore@Sun.COM 		    "pshot_remove_eventcall:\n\t"
23977656SSherry.Moore@Sun.COM 		    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
23987656SSherry.Moore@Sun.COM 		    instance, (void *)dip, (void *)cb->ndi_evtcb_dip,
23997656SSherry.Moore@Sun.COM 		    ddi_node_name(cb->ndi_evtcb_dip),
24007656SSherry.Moore@Sun.COM 		    ddi_get_instance(cb->ndi_evtcb_dip),
24017656SSherry.Moore@Sun.COM 		    (void *)cb->ndi_evtcb_cookie,
24027656SSherry.Moore@Sun.COM 		    NDI_EVENT_NAME(cb->ndi_evtcb_cookie));
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id));
24050Sstevel@tonic-gate }
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate static int
pshot_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * impl_data)24080Sstevel@tonic-gate pshot_post_event(dev_info_t *dip, dev_info_t *rdip,
24090Sstevel@tonic-gate 	ddi_eventcookie_t cookie, void *impl_data)
24100Sstevel@tonic-gate {
24110Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
24120Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
24130Sstevel@tonic-gate 
24140Sstevel@tonic-gate 	if (pshot_debug) {
24157656SSherry.Moore@Sun.COM 		if (rdip) {
24167656SSherry.Moore@Sun.COM 			cmn_err(CE_CONT, "pshot%d: "
24177656SSherry.Moore@Sun.COM 			    "pshot_post_event:\n\t"
24187656SSherry.Moore@Sun.COM 			    "dip = 0x%p rdip = 0x%p (%s%d\n\t"
24197656SSherry.Moore@Sun.COM 			    "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
24207656SSherry.Moore@Sun.COM 			    instance, (void *)dip, (void *)rdip,
24217656SSherry.Moore@Sun.COM 			    ddi_node_name(rdip), ddi_get_instance(rdip),
24227656SSherry.Moore@Sun.COM 			    (void *)cookie,
24237656SSherry.Moore@Sun.COM 			    NDI_EVENT_NAME(cookie), impl_data);
24247656SSherry.Moore@Sun.COM 		} else {
24257656SSherry.Moore@Sun.COM 			cmn_err(CE_CONT, "pshot%d: "
24267656SSherry.Moore@Sun.COM 			    "pshot_post_event:\n\t"
24277656SSherry.Moore@Sun.COM 			    "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
24287656SSherry.Moore@Sun.COM 			    instance, (void *)dip, (void *)cookie,
24297656SSherry.Moore@Sun.COM 			    NDI_EVENT_NAME(cookie), impl_data);
24307656SSherry.Moore@Sun.COM 		}
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	/*  run callbacks for this event */
24340Sstevel@tonic-gate 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip,
24350Sstevel@tonic-gate 	    cookie, impl_data));
24360Sstevel@tonic-gate }
24370Sstevel@tonic-gate 
24380Sstevel@tonic-gate /*
24390Sstevel@tonic-gate  * the nexus driver will generate events
24400Sstevel@tonic-gate  * that need to go to children
24410Sstevel@tonic-gate  */
24420Sstevel@tonic-gate static int
pshot_event(pshot_t * pshot,int event_tag,dev_info_t * child,void * bus_impldata)24430Sstevel@tonic-gate pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child,
24440Sstevel@tonic-gate 	void *bus_impldata)
24450Sstevel@tonic-gate {
24460Sstevel@tonic-gate 	ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(
24477656SSherry.Moore@Sun.COM 	    pshot->ndi_event_hdl, event_tag);
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate 	if (pshot_debug) {
24500Sstevel@tonic-gate 		if (child) {
24517656SSherry.Moore@Sun.COM 			cmn_err(CE_CONT, "pshot%d: "
24527656SSherry.Moore@Sun.COM 			    "pshot_event: event_tag = 0x%x (%s)\n\t"
24537656SSherry.Moore@Sun.COM 			    "child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
24547656SSherry.Moore@Sun.COM 			    pshot->instance, event_tag,
24557656SSherry.Moore@Sun.COM 			    ndi_event_tag_to_name(pshot->ndi_event_hdl,
24567656SSherry.Moore@Sun.COM 			    event_tag),
24577656SSherry.Moore@Sun.COM 			    (void *)child, ddi_node_name(child),
24587656SSherry.Moore@Sun.COM 			    ddi_get_instance(child), bus_impldata,
24597656SSherry.Moore@Sun.COM 			    ddi_node_name((dev_info_t *)bus_impldata),
24607656SSherry.Moore@Sun.COM 			    ddi_get_instance((dev_info_t *)bus_impldata));
24610Sstevel@tonic-gate 		} else {
24627656SSherry.Moore@Sun.COM 			cmn_err(CE_CONT, "pshot%d: "
24637656SSherry.Moore@Sun.COM 			    "pshot_event: event_tag = 0x%x (%s)\n\t"
24647656SSherry.Moore@Sun.COM 			    "child = NULL,  bus_impl = 0x%p (%s%d)\n",
24657656SSherry.Moore@Sun.COM 			    pshot->instance, event_tag,
24667656SSherry.Moore@Sun.COM 			    ndi_event_tag_to_name(pshot->ndi_event_hdl,
24677656SSherry.Moore@Sun.COM 			    event_tag),
24687656SSherry.Moore@Sun.COM 			    bus_impldata,
24697656SSherry.Moore@Sun.COM 			    ddi_node_name((dev_info_t *)bus_impldata),
24707656SSherry.Moore@Sun.COM 			    ddi_get_instance((dev_info_t *)bus_impldata));
24710Sstevel@tonic-gate 		}
24720Sstevel@tonic-gate 	}
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl,
24757656SSherry.Moore@Sun.COM 	    child, cookie, bus_impldata));
24760Sstevel@tonic-gate }
24770Sstevel@tonic-gate 
24780Sstevel@tonic-gate 
24790Sstevel@tonic-gate /*
24800Sstevel@tonic-gate  * the pshot driver event notification callback
24810Sstevel@tonic-gate  */
24820Sstevel@tonic-gate static void
pshot_event_cb(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata)24830Sstevel@tonic-gate pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
24840Sstevel@tonic-gate 	void *arg, void *bus_impldata)
24850Sstevel@tonic-gate {
24860Sstevel@tonic-gate 	pshot_t *pshot = (pshot_t *)arg;
24870Sstevel@tonic-gate 	int event_tag;
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate 	/* look up the event */
24900Sstevel@tonic-gate 	event_tag = NDI_EVENT_TAG(cookie);
24910Sstevel@tonic-gate 
24920Sstevel@tonic-gate 	if (pshot_debug) {
24930Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: "
24940Sstevel@tonic-gate 		    "pshot_event_cb:\n\t"
24950Sstevel@tonic-gate 		    "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
24960Sstevel@tonic-gate 		    "arg = 0x%p bus_impl = 0x%p (%s%d)\n",
24970Sstevel@tonic-gate 		    pshot->instance, (void *)dip, (void *)cookie,
24980Sstevel@tonic-gate 		    NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata,
24990Sstevel@tonic-gate 		    ddi_node_name((dev_info_t *)bus_impldata),
25000Sstevel@tonic-gate 		    ddi_get_instance((dev_info_t *)bus_impldata));
25010Sstevel@tonic-gate 	}
25020Sstevel@tonic-gate 
25030Sstevel@tonic-gate 	switch (event_tag) {
25040Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_OFFLINE:
25050Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_RESET:
25060Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_QUIESCE:
25070Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_UNQUIESCE:
25080Sstevel@tonic-gate 		/* notify all subscribers of the this event */
25090Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(pshot->ndi_event_hdl,
25107656SSherry.Moore@Sun.COM 		    NULL, cookie, bus_impldata);
25110Sstevel@tonic-gate 		if (pshot_debug) {
25120Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: event=%s\n\t"
25137656SSherry.Moore@Sun.COM 			    "pshot_event_cb\n", pshot->instance,
25147656SSherry.Moore@Sun.COM 			    NDI_EVENT_NAME(cookie));
25150Sstevel@tonic-gate 		}
25160Sstevel@tonic-gate 		/*FALLTHRU*/
25170Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_TEST_POST:
25180Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_DEV_RESET:
25190Sstevel@tonic-gate 	default:
25200Sstevel@tonic-gate 		return;
25210Sstevel@tonic-gate 	}
25220Sstevel@tonic-gate }
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate static int
pshot_bus_config(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg,dev_info_t ** childp)25250Sstevel@tonic-gate pshot_bus_config(dev_info_t *parent, uint_t flags,
25260Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
25270Sstevel@tonic-gate {
25280Sstevel@tonic-gate 	int		rval;
25290Sstevel@tonic-gate 	char		*devname;
25300Sstevel@tonic-gate 	char		*devstr, *cname, *caddr;
25310Sstevel@tonic-gate 	int		devstrlen;
25320Sstevel@tonic-gate 	int		circ;
25330Sstevel@tonic-gate 	pshot_t		*pshot;
25340Sstevel@tonic-gate 	int		instance = ddi_get_instance(parent);
25350Sstevel@tonic-gate 
25360Sstevel@tonic-gate 	if (pshot_debug) {
25370Sstevel@tonic-gate 		flags |= NDI_DEVI_DEBUG;
25380Sstevel@tonic-gate 		cmn_err(CE_CONT,
25390Sstevel@tonic-gate 		    "pshot%d: bus_config %s flags=0x%x\n",
25400Sstevel@tonic-gate 		    ddi_get_instance(parent),
25410Sstevel@tonic-gate 		    (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags);
25420Sstevel@tonic-gate 	}
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
25450Sstevel@tonic-gate 	if (pshot == NULL) {
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate 		return (NDI_FAILURE);
25480Sstevel@tonic-gate 	}
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate 	/*
25510Sstevel@tonic-gate 	 * Hold the nexus across the bus_config
25520Sstevel@tonic-gate 	 */
25530Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
25540Sstevel@tonic-gate 
25550Sstevel@tonic-gate 	switch (op) {
25560Sstevel@tonic-gate 	case BUS_CONFIG_ONE:
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate 		/*
25590Sstevel@tonic-gate 		 * lookup and hold child device, create if not found
25600Sstevel@tonic-gate 		 */
25610Sstevel@tonic-gate 		devname = (char *)arg;
25620Sstevel@tonic-gate 		devstrlen = strlen(devname) + 1;
25630Sstevel@tonic-gate 		devstr = i_ddi_strdup(devname, KM_SLEEP);
25640Sstevel@tonic-gate 		i_ddi_parse_name(devstr, &cname, &caddr, NULL);
25650Sstevel@tonic-gate 
25660Sstevel@tonic-gate 		/*
25670Sstevel@tonic-gate 		 * The framework ensures that the node has
25680Sstevel@tonic-gate 		 * a name but each nexus is responsible for
25690Sstevel@tonic-gate 		 * the bus address name space.  This driver
25700Sstevel@tonic-gate 		 * requires that a bus address be specified,
25710Sstevel@tonic-gate 		 * as will most nexus drivers.
25720Sstevel@tonic-gate 		 */
25730Sstevel@tonic-gate 		ASSERT(cname && strlen(cname) > 0);
25740Sstevel@tonic-gate 		if (caddr == NULL || strlen(caddr) == 0) {
25750Sstevel@tonic-gate 			cmn_err(CE_WARN,
25760Sstevel@tonic-gate 			    "pshot%d: malformed name %s (no bus address)",
25770Sstevel@tonic-gate 			    ddi_get_instance(parent), devname);
25780Sstevel@tonic-gate 			kmem_free(devstr, devstrlen);
25790Sstevel@tonic-gate 			ndi_devi_exit(parent, circ);
25800Sstevel@tonic-gate 			return (NDI_FAILURE);
25810Sstevel@tonic-gate 		}
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 		/*
25840Sstevel@tonic-gate 		 * Handle a few special cases for testing purposes
25850Sstevel@tonic-gate 		 */
25860Sstevel@tonic-gate 		rval = pshot_bus_config_test_specials(parent,
25877656SSherry.Moore@Sun.COM 		    devname, cname, caddr);
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 		if (rval == NDI_SUCCESS) {
25900Sstevel@tonic-gate 			/*
25910Sstevel@tonic-gate 			 * Set up either a leaf or nexus device
25920Sstevel@tonic-gate 			 */
25930Sstevel@tonic-gate 			if (strcmp(cname, "pshot") == 0) {
25940Sstevel@tonic-gate 				rval = pshot_bus_config_setup_nexus(parent,
25950Sstevel@tonic-gate 				    cname, caddr);
25960Sstevel@tonic-gate 			} else {
25970Sstevel@tonic-gate 				rval = pshot_bus_config_setup_leaf(parent,
25980Sstevel@tonic-gate 				    cname, caddr);
25990Sstevel@tonic-gate 			}
26000Sstevel@tonic-gate 		}
26010Sstevel@tonic-gate 
26020Sstevel@tonic-gate 		kmem_free(devstr, devstrlen);
26030Sstevel@tonic-gate 		break;
26040Sstevel@tonic-gate 
26050Sstevel@tonic-gate 	case BUS_CONFIG_DRIVER:
26060Sstevel@tonic-gate 	case BUS_CONFIG_ALL:
26070Sstevel@tonic-gate 		rval = NDI_SUCCESS;
26080Sstevel@tonic-gate 		break;
26090Sstevel@tonic-gate 
26100Sstevel@tonic-gate 	default:
26110Sstevel@tonic-gate 		rval = NDI_FAILURE;
26120Sstevel@tonic-gate 		break;
26130Sstevel@tonic-gate 	}
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 	if (rval == NDI_SUCCESS)
26160Sstevel@tonic-gate 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
26190Sstevel@tonic-gate 
26200Sstevel@tonic-gate 	if (pshot_debug)
26210Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: bus_config %s\n",
26220Sstevel@tonic-gate 		    ddi_get_instance(parent),
26230Sstevel@tonic-gate 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate 	return (rval);
26260Sstevel@tonic-gate }
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate static int
pshot_bus_unconfig(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg)26290Sstevel@tonic-gate pshot_bus_unconfig(dev_info_t *parent, uint_t flags,
26300Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg)
26310Sstevel@tonic-gate {
26320Sstevel@tonic-gate 	major_t		major;
26330Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
26340Sstevel@tonic-gate 	int		circ;
26350Sstevel@tonic-gate 
26360Sstevel@tonic-gate 	if (pshot_debug) {
26370Sstevel@tonic-gate 		flags |= NDI_DEVI_DEBUG;
26380Sstevel@tonic-gate 		cmn_err(CE_CONT,
26390Sstevel@tonic-gate 		    "pshot%d: bus_unconfig %s flags=0x%x\n",
26400Sstevel@tonic-gate 		    ddi_get_instance(parent),
26410Sstevel@tonic-gate 		    (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags);
26420Sstevel@tonic-gate 	}
26430Sstevel@tonic-gate 
26440Sstevel@tonic-gate 	/*
26450Sstevel@tonic-gate 	 * Hold the nexus across the bus_unconfig
26460Sstevel@tonic-gate 	 */
26470Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
26480Sstevel@tonic-gate 
26490Sstevel@tonic-gate 	switch (op) {
26500Sstevel@tonic-gate 	case BUS_UNCONFIG_ONE:
26510Sstevel@tonic-gate 		/*
26520Sstevel@tonic-gate 		 * Nothing special required here
26530Sstevel@tonic-gate 		 */
26540Sstevel@tonic-gate 		if (pshot_debug) {
26550Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
26560Sstevel@tonic-gate 			    " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent));
26570Sstevel@tonic-gate 		}
26580Sstevel@tonic-gate 		break;
26590Sstevel@tonic-gate 
26600Sstevel@tonic-gate 	case BUS_UNCONFIG_DRIVER:
26610Sstevel@tonic-gate 		if (pshot_debug > 0) {
26620Sstevel@tonic-gate 			major = (major_t)(uintptr_t)arg;
26630Sstevel@tonic-gate 			cmn_err(CE_CONT,
26640Sstevel@tonic-gate 			    "pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
26650Sstevel@tonic-gate 			    ddi_get_instance(parent),
26660Sstevel@tonic-gate 			    ddi_major_to_name(major));
26670Sstevel@tonic-gate 		}
26680Sstevel@tonic-gate 		break;
26690Sstevel@tonic-gate 
26700Sstevel@tonic-gate 	case BUS_UNCONFIG_ALL:
26710Sstevel@tonic-gate 		if (pshot_debug) {
26720Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
26730Sstevel@tonic-gate 			    " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent));
26740Sstevel@tonic-gate 		}
26750Sstevel@tonic-gate 		break;
26760Sstevel@tonic-gate 
26770Sstevel@tonic-gate 	default:
26780Sstevel@tonic-gate 		if (pshot_debug) {
26790Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n",
26800Sstevel@tonic-gate 			    ddi_get_instance(parent));
26810Sstevel@tonic-gate 		}
26820Sstevel@tonic-gate 		rval = NDI_FAILURE;
26830Sstevel@tonic-gate 	}
26840Sstevel@tonic-gate 
26850Sstevel@tonic-gate 	if (rval == NDI_SUCCESS)
26860Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(parent, flags, op, arg);
26870Sstevel@tonic-gate 
26880Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate 	if (pshot_debug)
26910Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n",
26920Sstevel@tonic-gate 		    ddi_get_instance(parent),
26930Sstevel@tonic-gate 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	return (rval);
26960Sstevel@tonic-gate }
26970Sstevel@tonic-gate 
26980Sstevel@tonic-gate static dev_info_t *
pshot_findchild(dev_info_t * pdip,char * cname,char * caddr)26990Sstevel@tonic-gate pshot_findchild(dev_info_t *pdip, char *cname, char *caddr)
27000Sstevel@tonic-gate {
27010Sstevel@tonic-gate 	dev_info_t *dip;
27020Sstevel@tonic-gate 	char *addr;
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate 	ASSERT(cname != NULL && caddr != NULL);
27050Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(pdip));
27060Sstevel@tonic-gate 
27070Sstevel@tonic-gate 	for (dip = ddi_get_child(pdip); dip != NULL;
27080Sstevel@tonic-gate 	    dip = ddi_get_next_sibling(dip)) {
27090Sstevel@tonic-gate 		if (strcmp(cname, ddi_node_name(dip)) != 0)
27100Sstevel@tonic-gate 			continue;
27110Sstevel@tonic-gate 
27120Sstevel@tonic-gate 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
27130Sstevel@tonic-gate 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
27140Sstevel@tonic-gate 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
27150Sstevel@tonic-gate 				if (strcmp(caddr, addr) == 0) {
27160Sstevel@tonic-gate 					ddi_prop_free(addr);
27170Sstevel@tonic-gate 					return (dip);
27180Sstevel@tonic-gate 				}
27190Sstevel@tonic-gate 				ddi_prop_free(addr);
27200Sstevel@tonic-gate 			}
27210Sstevel@tonic-gate 		} else {
27220Sstevel@tonic-gate 			if (strcmp(caddr, addr) == 0)
27230Sstevel@tonic-gate 				return (dip);
27240Sstevel@tonic-gate 		}
27250Sstevel@tonic-gate 	}
27260Sstevel@tonic-gate 
27270Sstevel@tonic-gate 	return (NULL);
27280Sstevel@tonic-gate }
27290Sstevel@tonic-gate 
27300Sstevel@tonic-gate static void
pshot_nexus_properties(dev_info_t * parent,dev_info_t * child,char * cname,char * caddr)27310Sstevel@tonic-gate pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname,
27320Sstevel@tonic-gate     char *caddr)
27330Sstevel@tonic-gate {
27340Sstevel@tonic-gate 	char *extension;
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate 	/*
273785Scth 	 * extract the address extension
27380Sstevel@tonic-gate 	 */
27390Sstevel@tonic-gate 	extension = strstr(caddr, ",");
27400Sstevel@tonic-gate 	if (extension != NULL) {
27410Sstevel@tonic-gate 		++extension;
27420Sstevel@tonic-gate 	} else {
27430Sstevel@tonic-gate 		extension = "null";
27440Sstevel@tonic-gate 	}
27450Sstevel@tonic-gate 
27460Sstevel@tonic-gate 	/*
27470Sstevel@tonic-gate 	 * Create the "pm-want-child-notification?" property for all
27480Sstevel@tonic-gate 	 * nodes that do not have the "pm_strict" or "nopm_strict"
27490Sstevel@tonic-gate 	 * extension
27500Sstevel@tonic-gate 	 */
27510Sstevel@tonic-gate 	if (strcmp(extension, "pm_strict") != 0 &&
27520Sstevel@tonic-gate 	    strcmp(extension, "nopm_strict") != 0) {
27530Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
27540Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
27550Sstevel@tonic-gate 		    "pm-want-child-notification?") == 0) {
27560Sstevel@tonic-gate 			if (pshot_debug) {
27570Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
27580Sstevel@tonic-gate 				    " nexus_properties:\n\tcreate the"
27590Sstevel@tonic-gate 				    " \"pm-want-child-notification?\""
27600Sstevel@tonic-gate 				    " property for %s@%s\n",
27610Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
27620Sstevel@tonic-gate 			}
27630Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
27640Sstevel@tonic-gate 			    "pm-want-child-notification?", NULL, 0)
27650Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
27660Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
27670Sstevel@tonic-gate 				    " nexus_properties:\n\tunable to create"
27680Sstevel@tonic-gate 				    " the \"pm-want-child-notification?\""
27690Sstevel@tonic-gate 				    " property for %s@%s",
27700Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
27710Sstevel@tonic-gate 			}
27720Sstevel@tonic-gate 		}
27730Sstevel@tonic-gate 	}
27740Sstevel@tonic-gate 
27750Sstevel@tonic-gate 	/*
27760Sstevel@tonic-gate 	 * Create the "no-pm-components" property for all nodes
27770Sstevel@tonic-gate 	 * with extension "nopm" or "nopm_strict"
27780Sstevel@tonic-gate 	 */
27790Sstevel@tonic-gate 	if (strcmp(extension, "nopm") == 0 ||
27800Sstevel@tonic-gate 	    strcmp(extension, "nopm_strict") == 0) {
27810Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
27820Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
27830Sstevel@tonic-gate 		    "no-pm-components") == 0) {
27840Sstevel@tonic-gate 			if (pshot_debug) {
27850Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
27860Sstevel@tonic-gate 				    " nexus_properties:\n\tcreate the"
27870Sstevel@tonic-gate 				    " \"no-pm-components\""
27880Sstevel@tonic-gate 				    " property for %s@%s\n",
27890Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
27900Sstevel@tonic-gate 			}
27910Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
27920Sstevel@tonic-gate 			    "no-pm-components", NULL, 0)
27930Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
27940Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
27950Sstevel@tonic-gate 				    " nexus_properties:\n\tunable to create"
27960Sstevel@tonic-gate 				    " the \"no-pm-components\""
27970Sstevel@tonic-gate 				    " property for %s@%s",
27987656SSherry.Moore@Sun.COM 				    ddi_get_instance(parent), cname, caddr);
27990Sstevel@tonic-gate 			}
28000Sstevel@tonic-gate 		}
28010Sstevel@tonic-gate 	}
28020Sstevel@tonic-gate }
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate static void
pshot_leaf_properties(dev_info_t * parent,dev_info_t * child,char * cname,char * caddr)28050Sstevel@tonic-gate pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname,
28060Sstevel@tonic-gate     char *caddr)
28070Sstevel@tonic-gate {
28080Sstevel@tonic-gate 	char *extension;
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate 	/*
281185Scth 	 * extract the address extension
28120Sstevel@tonic-gate 	 */
28130Sstevel@tonic-gate 	extension = strstr(caddr, ",");
28140Sstevel@tonic-gate 	if (extension != NULL) {
28150Sstevel@tonic-gate 		++extension;
28160Sstevel@tonic-gate 	} else {
28170Sstevel@tonic-gate 		extension = "null";
28180Sstevel@tonic-gate 	}
28190Sstevel@tonic-gate 
28200Sstevel@tonic-gate 	/*
28210Sstevel@tonic-gate 	 * Create the "no-involuntary-power-cycles" property for
28220Sstevel@tonic-gate 	 * all leaf nodes with extension "no_invol"
28230Sstevel@tonic-gate 	 */
28240Sstevel@tonic-gate 	if (strcmp(extension, "no_invol") == 0) {
28250Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
28260Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
28270Sstevel@tonic-gate 		    "no-involuntary-power-cycles") == 0) {
28280Sstevel@tonic-gate 			if (pshot_debug) {
28290Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
28300Sstevel@tonic-gate 				    " leaf_properties:\n\tcreate the"
28310Sstevel@tonic-gate 				    " \"no-involuntary-power-cycles\""
28320Sstevel@tonic-gate 				    " property for %s@%s\n",
28330Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
28340Sstevel@tonic-gate 			}
28350Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
28360Sstevel@tonic-gate 			    DDI_PROP_CANSLEEP,
28370Sstevel@tonic-gate 			    "no-involuntary-power-cycles", NULL, 0)
28380Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
28390Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
28400Sstevel@tonic-gate 				    " leaf_properties:\n\tunable to create the"
28410Sstevel@tonic-gate 				    " \"no-involuntary-power-cycles\""
28420Sstevel@tonic-gate 				    " property for %s@%s",
28430Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
28440Sstevel@tonic-gate 			}
28450Sstevel@tonic-gate 		}
28460Sstevel@tonic-gate 	}
28470Sstevel@tonic-gate 
28480Sstevel@tonic-gate 	/*
28490Sstevel@tonic-gate 	 * Create the "dependency-property" property for all leaf
28500Sstevel@tonic-gate 	 * nodes with extension "dep_prop"
28510Sstevel@tonic-gate 	 * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
28520Sstevel@tonic-gate 	 */
28530Sstevel@tonic-gate 	if (strcmp(extension, "dep_prop") == 0) {
28540Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
28550Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
28560Sstevel@tonic-gate 		    "dependency-property") == 0) {
28570Sstevel@tonic-gate 			if (pshot_debug) {
28580Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
28590Sstevel@tonic-gate 				    " leaf_properties:\n\tcreate the"
28600Sstevel@tonic-gate 				    " \"dependency-property\""
28610Sstevel@tonic-gate 				    " property for %s@%s\n",
28620Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
28630Sstevel@tonic-gate 			}
28640Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
28650Sstevel@tonic-gate 			    DDI_PROP_CANSLEEP, "dependency-property", NULL, 0)
28660Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
28670Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
28680Sstevel@tonic-gate 				    " leaf_properties:\n\tunable to create the"
28690Sstevel@tonic-gate 				    " \"dependency-property\" property for"
28700Sstevel@tonic-gate 				    " %s@%s", ddi_get_instance(parent),
28710Sstevel@tonic-gate 				    cname, caddr);
28720Sstevel@tonic-gate 			}
28730Sstevel@tonic-gate 		}
28740Sstevel@tonic-gate 	}
28750Sstevel@tonic-gate }
28760Sstevel@tonic-gate 
28770Sstevel@tonic-gate /*
28780Sstevel@tonic-gate  * BUS_CONFIG_ONE: setup a child nexus instance.
28790Sstevel@tonic-gate  */
28800Sstevel@tonic-gate static int
pshot_bus_config_setup_nexus(dev_info_t * parent,char * cname,char * caddr)28810Sstevel@tonic-gate pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr)
28820Sstevel@tonic-gate {
28830Sstevel@tonic-gate 	dev_info_t *child;
28840Sstevel@tonic-gate 	int rval;
28850Sstevel@tonic-gate 
28860Sstevel@tonic-gate 	ASSERT(parent != 0);
28870Sstevel@tonic-gate 	ASSERT(cname != NULL);
28880Sstevel@tonic-gate 	ASSERT(caddr != NULL);
28890Sstevel@tonic-gate 
28900Sstevel@tonic-gate 	child = pshot_findchild(parent, cname, caddr);
28910Sstevel@tonic-gate 	if (child) {
28920Sstevel@tonic-gate 		if (pshot_debug) {
28930Sstevel@tonic-gate 			cmn_err(CE_CONT,
28940Sstevel@tonic-gate 			    "pshot%d: bus_config one %s@%s found\n",
28950Sstevel@tonic-gate 			    ddi_get_instance(parent), cname, caddr);
28960Sstevel@tonic-gate 		}
28972155Scth 
28980Sstevel@tonic-gate 		/*
28990Sstevel@tonic-gate 		 * create the "pm-want-child-notification?" property
29000Sstevel@tonic-gate 		 * for this child, if it doesn't already exist
29010Sstevel@tonic-gate 		 */
29020Sstevel@tonic-gate 		(void) pshot_nexus_properties(parent, child, cname, caddr);
29030Sstevel@tonic-gate 
29040Sstevel@tonic-gate 		return (NDI_SUCCESS);
29050Sstevel@tonic-gate 	}
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
29080Sstevel@tonic-gate 	ASSERT(child != NULL);
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
29110Sstevel@tonic-gate 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
29120Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed",
29130Sstevel@tonic-gate 		    ddi_get_instance(parent), cname, caddr);
29140Sstevel@tonic-gate 		(void) ndi_devi_free(child);
29150Sstevel@tonic-gate 		return (NDI_FAILURE);
29160Sstevel@tonic-gate 	}
29170Sstevel@tonic-gate 
29180Sstevel@tonic-gate 	rval = ndi_devi_bind_driver(child, 0);
29190Sstevel@tonic-gate 	if (rval != NDI_SUCCESS) {
29200Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
29210Sstevel@tonic-gate 		    ddi_get_instance(parent), cname);
29220Sstevel@tonic-gate 		(void) ndi_devi_free(child);
29230Sstevel@tonic-gate 		return (NDI_FAILURE);
29240Sstevel@tonic-gate 	}
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	/*
29270Sstevel@tonic-gate 	 * create the "pm-want-child-notification?" property
29280Sstevel@tonic-gate 	 */
29290Sstevel@tonic-gate 	(void) pshot_nexus_properties(parent, child, cname, caddr);
29300Sstevel@tonic-gate 
29310Sstevel@tonic-gate 	return (NDI_SUCCESS);
29320Sstevel@tonic-gate }
29330Sstevel@tonic-gate 
29340Sstevel@tonic-gate /*
29350Sstevel@tonic-gate  * BUS_CONFIG_ONE: setup a child leaf device instance.
29360Sstevel@tonic-gate  * for testing purposes, we will create nodes of a variety of types.
29370Sstevel@tonic-gate  */
29380Sstevel@tonic-gate static int
pshot_bus_config_setup_leaf(dev_info_t * parent,char * cname,char * caddr)29390Sstevel@tonic-gate pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr)
29400Sstevel@tonic-gate {
29410Sstevel@tonic-gate 	dev_info_t *child;
29420Sstevel@tonic-gate 	char *compat_name;
29430Sstevel@tonic-gate 	char *nodetype;
29440Sstevel@tonic-gate 	int rval;
29450Sstevel@tonic-gate 	int i;
29460Sstevel@tonic-gate 
29470Sstevel@tonic-gate 	ASSERT(parent != 0);
29480Sstevel@tonic-gate 	ASSERT(cname != NULL);
29490Sstevel@tonic-gate 	ASSERT(caddr != NULL);
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 	/*
29520Sstevel@tonic-gate 	 * if we already have a node with this name, return it
29530Sstevel@tonic-gate 	 */
29540Sstevel@tonic-gate 	if ((child = pshot_findchild(parent, cname, caddr)) != NULL) {
29550Sstevel@tonic-gate 		/*
29560Sstevel@tonic-gate 		 * create the "no-involuntary-power-cycles" or
29570Sstevel@tonic-gate 		 * the "dependency-property" property, if they
29580Sstevel@tonic-gate 		 * don't already exit
29590Sstevel@tonic-gate 		 */
29600Sstevel@tonic-gate 		(void) pshot_leaf_properties(parent, child, cname, caddr);
29610Sstevel@tonic-gate 
29620Sstevel@tonic-gate 		return (NDI_SUCCESS);
29630Sstevel@tonic-gate 	}
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
29660Sstevel@tonic-gate 	ASSERT(child != NULL);
29670Sstevel@tonic-gate 
29680Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr",
29690Sstevel@tonic-gate 	    caddr) != DDI_PROP_SUCCESS) {
29700Sstevel@tonic-gate 		(void) ndi_devi_free(child);
29710Sstevel@tonic-gate 		return (NDI_FAILURE);
29720Sstevel@tonic-gate 	}
29730Sstevel@tonic-gate 
29740Sstevel@tonic-gate 	/*
29750Sstevel@tonic-gate 	 * test compatible naming
29760Sstevel@tonic-gate 	 * if the child nodename is "cdisk", attach the list of compatible
29770Sstevel@tonic-gate 	 * named disks
29780Sstevel@tonic-gate 	 */
29790Sstevel@tonic-gate 	if (strcmp(cname, pshot_compat_diskname) == 0) {
29800Sstevel@tonic-gate 		if ((ndi_prop_update_string_array(DDI_DEV_T_NONE,
29810Sstevel@tonic-gate 		    child, "compatible", (char **)pshot_compat_psramdisks,
29820Sstevel@tonic-gate 		    5)) != DDI_PROP_SUCCESS) {
29830Sstevel@tonic-gate 			(void) ndi_devi_free(child);
29840Sstevel@tonic-gate 			return (NDI_FAILURE);
29850Sstevel@tonic-gate 		}
29860Sstevel@tonic-gate 	} else {
29870Sstevel@tonic-gate 		for (i = 0; i < pshot_devices_len && pshot_devices[i].name;
29880Sstevel@tonic-gate 		    i++) {
29890Sstevel@tonic-gate 			if (strcmp(cname, pshot_devices[i].name) == 0) {
29900Sstevel@tonic-gate 				compat_name = pshot_devices[i].compat;
29910Sstevel@tonic-gate 				nodetype = pshot_devices[i].nodetype;
29920Sstevel@tonic-gate 				if (pshot_debug) {
29930Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: %s %s %s\n",
29940Sstevel@tonic-gate 					    ddi_get_instance(parent), cname,
29950Sstevel@tonic-gate 					    compat_name, nodetype);
29960Sstevel@tonic-gate 				}
29970Sstevel@tonic-gate 				if ((ndi_prop_update_string_array(
29980Sstevel@tonic-gate 				    DDI_DEV_T_NONE, child, "compatible",
29990Sstevel@tonic-gate 				    &compat_name, 1)) != DDI_PROP_SUCCESS) {
30000Sstevel@tonic-gate 					(void) ndi_devi_free(child);
30010Sstevel@tonic-gate 					return (NDI_FAILURE);
30020Sstevel@tonic-gate 				}
30030Sstevel@tonic-gate 				if ((ndi_prop_update_string(
30040Sstevel@tonic-gate 				    DDI_DEV_T_NONE, child, "node-type",
30050Sstevel@tonic-gate 				    nodetype)) != DDI_PROP_SUCCESS) {
30060Sstevel@tonic-gate 					(void) ndi_devi_free(child);
30070Sstevel@tonic-gate 					return (NDI_FAILURE);
30080Sstevel@tonic-gate 				}
30090Sstevel@tonic-gate 			}
30100Sstevel@tonic-gate 		}
30110Sstevel@tonic-gate 	}
30120Sstevel@tonic-gate 
30130Sstevel@tonic-gate 	rval = ndi_devi_bind_driver(child, 0);
30140Sstevel@tonic-gate 	if (rval != NDI_SUCCESS) {
30150Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
30160Sstevel@tonic-gate 		    ddi_get_instance(parent), cname);
30170Sstevel@tonic-gate 		(void) ndi_devi_free(child);
30180Sstevel@tonic-gate 		return (NDI_FAILURE);
30190Sstevel@tonic-gate 	}
30200Sstevel@tonic-gate 
30210Sstevel@tonic-gate 	/*
30220Sstevel@tonic-gate 	 * create the "no-involuntary-power-cycles" or
30230Sstevel@tonic-gate 	 * the "dependency-property" property
30240Sstevel@tonic-gate 	 */
30250Sstevel@tonic-gate 	(void) pshot_leaf_properties(parent, child, cname, caddr);
30260Sstevel@tonic-gate 
30270Sstevel@tonic-gate 	return (NDI_SUCCESS);
30280Sstevel@tonic-gate }
30290Sstevel@tonic-gate 
30300Sstevel@tonic-gate /*
30310Sstevel@tonic-gate  * Handle some special cases for testing bus_config via pshot
30320Sstevel@tonic-gate  *
30330Sstevel@tonic-gate  * Match these special address formats to behavior:
30340Sstevel@tonic-gate  *
30350Sstevel@tonic-gate  *	err.*		- induce bus_config error
30360Sstevel@tonic-gate  *	delay		- induce 1 second of bus_config delay time
30370Sstevel@tonic-gate  *	delay,n		- induce n seconds of bus_config delay time
30380Sstevel@tonic-gate  *	wait		- induce 1 second of bus_config wait time
30390Sstevel@tonic-gate  *	wait,n		- induce n seconds of bus_config wait time
30400Sstevel@tonic-gate  *	failinit.*	- induce error at INITCHILD
30410Sstevel@tonic-gate  *	failprobe.*	- induce error at probe
30420Sstevel@tonic-gate  *	failattach.*	- induce error at attach
30430Sstevel@tonic-gate  */
30440Sstevel@tonic-gate /*ARGSUSED*/
30450Sstevel@tonic-gate static int
pshot_bus_config_test_specials(dev_info_t * parent,char * devname,char * cname,char * caddr)30460Sstevel@tonic-gate pshot_bus_config_test_specials(dev_info_t *parent, char *devname,
30470Sstevel@tonic-gate 	char *cname, char *caddr)
30480Sstevel@tonic-gate {
30490Sstevel@tonic-gate 	char	*p;
30500Sstevel@tonic-gate 	int	n;
30510Sstevel@tonic-gate 
30520Sstevel@tonic-gate 	if (strncmp(caddr, "err", 3) == 0) {
30530Sstevel@tonic-gate 		if (pshot_debug)
30540Sstevel@tonic-gate 			cmn_err(CE_CONT,
30550Sstevel@tonic-gate 			    "pshot%d: %s forced failure\n",
30567656SSherry.Moore@Sun.COM 			    ddi_get_instance(parent), devname);
30570Sstevel@tonic-gate 		return (NDI_FAILURE);
30580Sstevel@tonic-gate 	}
30590Sstevel@tonic-gate 
30600Sstevel@tonic-gate 	/*
30610Sstevel@tonic-gate 	 * The delay and wait strings have the same effect.
30620Sstevel@tonic-gate 	 * The "wait[,]" support should be removed once the
30630Sstevel@tonic-gate 	 * devfs test suites are fixed.
30640Sstevel@tonic-gate 	 * NOTE: delay should not be called from interrupt context
30650Sstevel@tonic-gate 	 */
30660Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
30670Sstevel@tonic-gate 
30680Sstevel@tonic-gate 	if (strncmp(caddr, "delay,", 6) == 0) {
30690Sstevel@tonic-gate 		p = caddr+6;
30700Sstevel@tonic-gate 		n = stoi(&p);
30710Sstevel@tonic-gate 		if (*p != 0)
30720Sstevel@tonic-gate 			n = 1;
30730Sstevel@tonic-gate 		if (pshot_debug)
30740Sstevel@tonic-gate 			cmn_err(CE_CONT,
30750Sstevel@tonic-gate 			    "pshot%d: %s delay %d second\n",
30767656SSherry.Moore@Sun.COM 			    ddi_get_instance(parent), devname, n);
30770Sstevel@tonic-gate 		delay(n * drv_usectohz(1000000));
30780Sstevel@tonic-gate 	} else if (strncmp(caddr, "delay", 5) == 0) {
30790Sstevel@tonic-gate 		if (pshot_debug)
30800Sstevel@tonic-gate 			cmn_err(CE_CONT,
30810Sstevel@tonic-gate 			    "pshot%d: %s delay 1 second\n",
30827656SSherry.Moore@Sun.COM 			    ddi_get_instance(parent), devname);
30830Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
30840Sstevel@tonic-gate 	} else if (strncmp(caddr, "wait,", 5) == 0) {
30850Sstevel@tonic-gate 		p = caddr+5;
30860Sstevel@tonic-gate 		n = stoi(&p);
30870Sstevel@tonic-gate 		if (*p != 0)
30880Sstevel@tonic-gate 			n = 1;
30890Sstevel@tonic-gate 		if (pshot_debug)
30900Sstevel@tonic-gate 			cmn_err(CE_CONT,
30910Sstevel@tonic-gate 			    "pshot%d: %s wait %d second\n",
30927656SSherry.Moore@Sun.COM 			    ddi_get_instance(parent), devname, n);
30930Sstevel@tonic-gate 		delay(n * drv_usectohz(1000000));
30940Sstevel@tonic-gate 	} else if (strncmp(caddr, "wait", 4) == 0) {
30950Sstevel@tonic-gate 		if (pshot_debug)
30960Sstevel@tonic-gate 			cmn_err(CE_CONT,
30970Sstevel@tonic-gate 			    "pshot%d: %s wait 1 second\n",
30980Sstevel@tonic-gate 			    ddi_get_instance(parent), devname);
30990Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
31000Sstevel@tonic-gate 	}
31010Sstevel@tonic-gate 
31020Sstevel@tonic-gate 	return (NDI_SUCCESS);
31030Sstevel@tonic-gate }
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate /*
31060Sstevel@tonic-gate  * translate nodetype name to actual value
31070Sstevel@tonic-gate  */
31080Sstevel@tonic-gate static char *
pshot_str2nt(char * str)31090Sstevel@tonic-gate pshot_str2nt(char *str)
31100Sstevel@tonic-gate {
31110Sstevel@tonic-gate 	int i;
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate 	for (i = 0; pshot_nodetypes[i].name; i++) {
31140Sstevel@tonic-gate 		if (strcmp(pshot_nodetypes[i].name, str) == 0)
31150Sstevel@tonic-gate 			return (pshot_nodetypes[i].val);
31160Sstevel@tonic-gate 	}
31170Sstevel@tonic-gate 	return (NULL);
31180Sstevel@tonic-gate }
31190Sstevel@tonic-gate 
31200Sstevel@tonic-gate /*
31210Sstevel@tonic-gate  * grows array pointed to by <dstp>, with <src> data
31220Sstevel@tonic-gate  * <dstlen> = # elements of the original <*dstp>
31230Sstevel@tonic-gate  * <srclen> = # elements of <src>
31240Sstevel@tonic-gate  *
31250Sstevel@tonic-gate  * on success, returns 0 and a pointer to the new array through <dstp> with
31260Sstevel@tonic-gate  * <srclen> + <dstlen> number of elements;
31270Sstevel@tonic-gate  * else returns non-zero
31280Sstevel@tonic-gate  *
31290Sstevel@tonic-gate  * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
31300Sstevel@tonic-gate  */
31310Sstevel@tonic-gate static int
pshot_devices_grow(pshot_device_t ** dstp,size_t dstlen,const pshot_device_t * src,size_t srclen)31320Sstevel@tonic-gate pshot_devices_grow(pshot_device_t **dstp, size_t dstlen,
31330Sstevel@tonic-gate     const pshot_device_t *src, size_t srclen)
31340Sstevel@tonic-gate {
31350Sstevel@tonic-gate 	size_t i;
31360Sstevel@tonic-gate 	pshot_device_t *newdst;
31370Sstevel@tonic-gate 
31380Sstevel@tonic-gate 	newdst = kmem_alloc((srclen + dstlen) * sizeof (*src),
31390Sstevel@tonic-gate 	    KM_SLEEP);
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate 	/* keep old pointers and dup new ones */
31420Sstevel@tonic-gate 	if (*dstp)
31430Sstevel@tonic-gate 		bcopy(*dstp, newdst, dstlen * sizeof (*src));
31440Sstevel@tonic-gate 	for (i = 0; i < srclen; i++) {
31450Sstevel@tonic-gate 		newdst[i + dstlen].name =
31460Sstevel@tonic-gate 		    i_ddi_strdup(src[i].name, KM_SLEEP);
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 		newdst[i + dstlen].nodetype =
31490Sstevel@tonic-gate 		    i_ddi_strdup(src[i].nodetype, KM_SLEEP);
31500Sstevel@tonic-gate 
31510Sstevel@tonic-gate 		newdst[i + dstlen].compat =
31520Sstevel@tonic-gate 		    i_ddi_strdup(src[i].compat, KM_SLEEP);
31530Sstevel@tonic-gate 	}
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 	/* do last */
31560Sstevel@tonic-gate 	if (*dstp)
31570Sstevel@tonic-gate 		kmem_free(*dstp, dstlen * sizeof (*src));
31580Sstevel@tonic-gate 	*dstp = newdst;
31590Sstevel@tonic-gate 	return (0);
31600Sstevel@tonic-gate }
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate /*
31630Sstevel@tonic-gate  * free a pshot_device_t array <dp> with <len> elements
31640Sstevel@tonic-gate  * null pointers within the elements are ok
31650Sstevel@tonic-gate  */
31660Sstevel@tonic-gate static void
pshot_devices_free(pshot_device_t * dp,size_t len)31670Sstevel@tonic-gate pshot_devices_free(pshot_device_t *dp, size_t len)
31680Sstevel@tonic-gate {
31690Sstevel@tonic-gate 	size_t i;
31700Sstevel@tonic-gate 
31710Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
31720Sstevel@tonic-gate 		if (dp[i].name)
31730Sstevel@tonic-gate 			kmem_free(dp[i].name, strlen(dp[i].name) + 1);
31740Sstevel@tonic-gate 		if (dp[i].nodetype)
31750Sstevel@tonic-gate 			kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1);
31760Sstevel@tonic-gate 		if (dp[i].compat)
31770Sstevel@tonic-gate 			kmem_free(dp[i].compat, strlen(dp[i].compat) + 1);
31780Sstevel@tonic-gate 	}
31790Sstevel@tonic-gate 	kmem_free(dp, len * sizeof (*dp));
31800Sstevel@tonic-gate }
31810Sstevel@tonic-gate 
31820Sstevel@tonic-gate /*
31830Sstevel@tonic-gate  * returns an array of pshot_device_t parsed from <dip>'s properties
31840Sstevel@tonic-gate  *
31850Sstevel@tonic-gate  * property structure (i.e. pshot.conf) for pshot:
31860Sstevel@tonic-gate  *
31870Sstevel@tonic-gate  * corresponding         |   pshot_device_t array elements
31880Sstevel@tonic-gate  * pshot_device_t        |
31890Sstevel@tonic-gate  * member by prop name   |   [0]            [1]           [2]
31900Sstevel@tonic-gate  * ----------------------|--------------|-------------|-----------------------
31910Sstevel@tonic-gate  * <PSHOT_PROP_DEVNAME>  ="disk",        "tape",       "testdev";
31920Sstevel@tonic-gate  * <PSHOT_PROP_DEVNT>    ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
31930Sstevel@tonic-gate  * <PSHOT_PROP_DEVCOMPAT>="testdrv",     "testdrv",    "testdrv";
31940Sstevel@tonic-gate  *
31950Sstevel@tonic-gate  *
31960Sstevel@tonic-gate  * if any of these properties are specified, then:
31970Sstevel@tonic-gate  * - all the members must be specified
31980Sstevel@tonic-gate  * - the number of elements for each string array property must be the same
31990Sstevel@tonic-gate  * - no empty strings allowed
32000Sstevel@tonic-gate  * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
32010Sstevel@tonic-gate  *   sys/sunddi.h
32020Sstevel@tonic-gate  *
32030Sstevel@tonic-gate  * NOTE: the pshot_nodetypes[] table should be kept in sync with the list
32040Sstevel@tonic-gate  * of ddi nodetypes.  It's not normally critical to always be in sync so
32050Sstevel@tonic-gate  * keeping this up-to-date can usually be done "on-demand".
32060Sstevel@tonic-gate  *
32070Sstevel@tonic-gate  * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
32080Sstevel@tonic-gate  * these will be duplicated verbatim
32090Sstevel@tonic-gate  */
32100Sstevel@tonic-gate static pshot_device_t *
pshot_devices_from_props(dev_info_t * dip,size_t * lenp,int flags)32110Sstevel@tonic-gate pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags)
32120Sstevel@tonic-gate {
32130Sstevel@tonic-gate 	pshot_device_t *devarr = NULL;
32140Sstevel@tonic-gate 	char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL;
32150Sstevel@tonic-gate 	uint_t name_arr_len, nt_arr_len, compat_arr_len;
32160Sstevel@tonic-gate 	uint_t i;
32170Sstevel@tonic-gate 	char *str;
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
32200Sstevel@tonic-gate 	    PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) !=
32210Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
32220Sstevel@tonic-gate 		name_arr = NULL;
32230Sstevel@tonic-gate 
32240Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
32250Sstevel@tonic-gate 	    PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) !=
32260Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
32270Sstevel@tonic-gate 		nt_arr = NULL;
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
32300Sstevel@tonic-gate 	    PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) !=
32310Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
32320Sstevel@tonic-gate 		compat_arr = NULL;
32330Sstevel@tonic-gate 
32340Sstevel@tonic-gate 	/*
32350Sstevel@tonic-gate 	 * warn about any incorrect usage, if specified
32360Sstevel@tonic-gate 	 */
32370Sstevel@tonic-gate 	if (!(name_arr || nt_arr || compat_arr))
32380Sstevel@tonic-gate 		return (NULL);
32390Sstevel@tonic-gate 
32400Sstevel@tonic-gate 	if (!(name_arr && nt_arr && compat_arr) ||
32410Sstevel@tonic-gate 	    (name_arr_len != nt_arr_len) ||
32420Sstevel@tonic-gate 	    (name_arr_len != compat_arr_len))
32430Sstevel@tonic-gate 		goto FAIL;
32440Sstevel@tonic-gate 
32450Sstevel@tonic-gate 	for (i = 0; i < name_arr_len; i++) {
32460Sstevel@tonic-gate 		if (*name_arr[i] == '\0' ||
32470Sstevel@tonic-gate 		    *nt_arr[i] == '\0' ||
32480Sstevel@tonic-gate 		    *compat_arr[i] == '\0')
32490Sstevel@tonic-gate 			goto FAIL;
32500Sstevel@tonic-gate 	}
32510Sstevel@tonic-gate 
32520Sstevel@tonic-gate 	devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP);
32530Sstevel@tonic-gate 	for (i = 0; i < name_arr_len; i++) {
32540Sstevel@tonic-gate 		devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP);
32550Sstevel@tonic-gate 		devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP);
32560Sstevel@tonic-gate 
32570Sstevel@tonic-gate 		if ((str = pshot_str2nt(nt_arr[i])) == NULL)
32580Sstevel@tonic-gate 			if (flags & PSHOT_DEV_ANYNT)
32590Sstevel@tonic-gate 				str = nt_arr[i];
32600Sstevel@tonic-gate 			else
32610Sstevel@tonic-gate 				goto FAIL;
32620Sstevel@tonic-gate 		devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP);
32630Sstevel@tonic-gate 	}
32640Sstevel@tonic-gate 	ddi_prop_free(name_arr);
32650Sstevel@tonic-gate 	ddi_prop_free(nt_arr);
32660Sstevel@tonic-gate 	ddi_prop_free(compat_arr);
32670Sstevel@tonic-gate 
32680Sstevel@tonic-gate 	/* set <*lenp> ONLY on success */
32690Sstevel@tonic-gate 	*lenp = name_arr_len;
32700Sstevel@tonic-gate 
32710Sstevel@tonic-gate 	return (devarr);
32720Sstevel@tonic-gate 	/*NOTREACHED*/
32730Sstevel@tonic-gate FAIL:
32740Sstevel@tonic-gate 	cmn_err(CE_WARN, "malformed device specification property");
32750Sstevel@tonic-gate 	if (name_arr)
32760Sstevel@tonic-gate 		ddi_prop_free(name_arr);
32770Sstevel@tonic-gate 	if (nt_arr)
32780Sstevel@tonic-gate 		ddi_prop_free(nt_arr);
32790Sstevel@tonic-gate 	if (compat_arr)
32800Sstevel@tonic-gate 		ddi_prop_free(compat_arr);
32810Sstevel@tonic-gate 	if (devarr)
32820Sstevel@tonic-gate 		pshot_devices_free(devarr, name_arr_len);
32830Sstevel@tonic-gate 	return (NULL);
32840Sstevel@tonic-gate }
32850Sstevel@tonic-gate 
32860Sstevel@tonic-gate /*
32870Sstevel@tonic-gate  * if global <pshot_devices> was not set up already (i.e. is NULL):
32880Sstevel@tonic-gate  *	sets up global <pshot_devices> and <pshot_devices_len>,
32890Sstevel@tonic-gate  *	using device properties	from <dip> and global <pshot_stock_devices>.
32900Sstevel@tonic-gate  *	device properties, if any, overrides pshot_stock_devices.
32910Sstevel@tonic-gate  *
32920Sstevel@tonic-gate  * returns 0 on success (or if pshot_devices already set up)
32930Sstevel@tonic-gate  *
32940Sstevel@tonic-gate  * INTERNAL LOCKING: <pshot_devices_lock>
32950Sstevel@tonic-gate  */
32960Sstevel@tonic-gate static int
pshot_devices_setup(dev_info_t * dip)32970Sstevel@tonic-gate pshot_devices_setup(dev_info_t *dip)
32980Sstevel@tonic-gate {
32990Sstevel@tonic-gate 	pshot_device_t *newdevs = NULL;
33000Sstevel@tonic-gate 	size_t newdevs_len = 0;
33010Sstevel@tonic-gate 	int rv = 0;
33020Sstevel@tonic-gate 
33030Sstevel@tonic-gate 	mutex_enter(&pshot_devices_lock);
33040Sstevel@tonic-gate 	if (pshot_devices != NULL)
33050Sstevel@tonic-gate 		goto FAIL;
33060Sstevel@tonic-gate 
33070Sstevel@tonic-gate 	ASSERT(pshot_devices_len == 0);
33080Sstevel@tonic-gate 
33090Sstevel@tonic-gate 	newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT);
33100Sstevel@tonic-gate 	rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices,
33110Sstevel@tonic-gate 	    PSHOT_N_STOCK_DEVICES);
33120Sstevel@tonic-gate 	if (rv != 0) {
33130Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow "
33140Sstevel@tonic-gate 		    "failed");
33150Sstevel@tonic-gate 		goto FAIL;
33160Sstevel@tonic-gate 	}
33170Sstevel@tonic-gate 	newdevs_len += PSHOT_N_STOCK_DEVICES;
33180Sstevel@tonic-gate 
33190Sstevel@tonic-gate 	pshot_devices = newdevs;
33200Sstevel@tonic-gate 	pshot_devices_len = newdevs_len;
33210Sstevel@tonic-gate 	rv = 0;
33220Sstevel@tonic-gate FAIL:
33230Sstevel@tonic-gate 	if (rv && newdevs)
33240Sstevel@tonic-gate 		pshot_devices_free(newdevs, newdevs_len);
33250Sstevel@tonic-gate 	mutex_exit(&pshot_devices_lock);
33260Sstevel@tonic-gate 	return (rv);
33270Sstevel@tonic-gate }
33280Sstevel@tonic-gate 
33290Sstevel@tonic-gate 
33300Sstevel@tonic-gate #ifdef NOTNEEDED
33310Sstevel@tonic-gate /* ARGSUSED */
33320Sstevel@tonic-gate static int
pshot_probe_family(dev_info_t * self,ddi_probe_method_t probe_how,dev_info_t ** return_dip)33330Sstevel@tonic-gate pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how,
33340Sstevel@tonic-gate     dev_info_t **return_dip)
33350Sstevel@tonic-gate {
33360Sstevel@tonic-gate 	char name[64];
33370Sstevel@tonic-gate 	uint_t bus_id;
33380Sstevel@tonic-gate 	dev_info_t *child;
33390Sstevel@tonic-gate 
33400Sstevel@tonic-gate 	for (bus_id = 10; bus_id < 20; bus_id++) {
33410Sstevel@tonic-gate 		(void) sprintf(name, "%d", bus_id);
33420Sstevel@tonic-gate 		if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID,
33430Sstevel@tonic-gate 		    &child)) != NDI_SUCCESS) {
33440Sstevel@tonic-gate 			return (DDI_FAILURE);
33450Sstevel@tonic-gate 		}
33460Sstevel@tonic-gate 
33470Sstevel@tonic-gate 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
33480Sstevel@tonic-gate 		    "bus-addr", name) != DDI_PROP_SUCCESS) {
33490Sstevel@tonic-gate 			(void) ndi_devi_free(child);
33500Sstevel@tonic-gate 			if (return_dip != NULL)
33510Sstevel@tonic-gate 				*return_dip = (dev_info_t *)NULL;
33520Sstevel@tonic-gate 			return (DDI_FAILURE);
33530Sstevel@tonic-gate 		}
33540Sstevel@tonic-gate 
33550Sstevel@tonic-gate 		if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
33560Sstevel@tonic-gate 			return (DDI_FAILURE);
33570Sstevel@tonic-gate 		}
33580Sstevel@tonic-gate 	}
33590Sstevel@tonic-gate 	return (DDI_SUCCESS);
33600Sstevel@tonic-gate }
336185Scth 
33620Sstevel@tonic-gate static int
strtoi(char * str)33630Sstevel@tonic-gate strtoi(char *str)
33640Sstevel@tonic-gate {
33650Sstevel@tonic-gate 	int c;
33660Sstevel@tonic-gate 	int val;
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate 	for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
33690Sstevel@tonic-gate 		val *= 10;
33700Sstevel@tonic-gate 		val += c - '0';
33710Sstevel@tonic-gate 	}
33720Sstevel@tonic-gate 	return (val);
33730Sstevel@tonic-gate }
33740Sstevel@tonic-gate 
337585Scth #endif
33760Sstevel@tonic-gate 
33770Sstevel@tonic-gate static void
pshot_setup_autoattach(dev_info_t * devi)33780Sstevel@tonic-gate pshot_setup_autoattach(dev_info_t *devi)
33790Sstevel@tonic-gate {
33800Sstevel@tonic-gate 	dev_info_t *l1child, *l2child;
33810Sstevel@tonic-gate 	int rv;
33820Sstevel@tonic-gate 
33830Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child);
33840Sstevel@tonic-gate 	if (rv == NDI_SUCCESS) {
33850Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
33860Sstevel@tonic-gate 		    "bus-addr", "0");
33870Sstevel@tonic-gate 		rv =  ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID,
33880Sstevel@tonic-gate 		    &l2child);
33890Sstevel@tonic-gate 		if (rv == NDI_SUCCESS)
33900Sstevel@tonic-gate 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
33910Sstevel@tonic-gate 			    l2child, "bus-addr", "99");
33920Sstevel@tonic-gate 	}
33930Sstevel@tonic-gate 
33940Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child);
33950Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
33960Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
33970Sstevel@tonic-gate 		    "bus-addr", "99");
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child);
34000Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
34010Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
34020Sstevel@tonic-gate 		    "bus-addr", "99");
34030Sstevel@tonic-gate 
34040Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child);
34050Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
34060Sstevel@tonic-gate 		(void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID,
34070Sstevel@tonic-gate 		    &l2child);
34080Sstevel@tonic-gate }
34090Sstevel@tonic-gate 
34100Sstevel@tonic-gate #ifdef PRUNE_SNUBS
34110Sstevel@tonic-gate 
34120Sstevel@tonic-gate #define	PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \
34130Sstevel@tonic-gate 	(DEVI_PROM_NODE((d)->devi_nodeid)) && \
34140Sstevel@tonic-gate 	((d)->devi_addr == NULL))
34150Sstevel@tonic-gate /*
34160Sstevel@tonic-gate  * test code to remove OBP nodes that have not attached
34170Sstevel@tonic-gate  */
34180Sstevel@tonic-gate static void
prune_snubs(const char * name)34190Sstevel@tonic-gate prune_snubs(const char *name)
34200Sstevel@tonic-gate {
34210Sstevel@tonic-gate 	struct dev_info *nex_dip, *cdip, *cndip;
34220Sstevel@tonic-gate 	int maj;
34230Sstevel@tonic-gate 	int rv;
34240Sstevel@tonic-gate 
34250Sstevel@tonic-gate 	maj = ddi_name_to_major((char *)name);
34260Sstevel@tonic-gate 	if (maj != -1) {
34270Sstevel@tonic-gate 		nex_dip = (struct dev_info *)devnamesp[maj].dn_head;
34280Sstevel@tonic-gate 		while (nex_dip != NULL) {
34290Sstevel@tonic-gate 			cndip = ddi_get_child(nex_dip);
34300Sstevel@tonic-gate 			while ((cdip = cndip) != NULL) {
34310Sstevel@tonic-gate 				cndip = cdip->devi_sibling;
34320Sstevel@tonic-gate 				if (PRUNE_THIS_NODE(cdip)) {
34330Sstevel@tonic-gate 					cmn_err(CE_NOTE,
34340Sstevel@tonic-gate 					    "parent %s@%s pruning node %s",
34350Sstevel@tonic-gate 					    nex_dip->devi_node_name,
34360Sstevel@tonic-gate 					    nex_dip->devi_addr,
34370Sstevel@tonic-gate 					    cdip->devi_node_name);
34380Sstevel@tonic-gate 					rv = ndi_devi_offline(cdip,
34390Sstevel@tonic-gate 					    NDI_DEVI_REMOVE);
34400Sstevel@tonic-gate 					if (rv != NDI_SUCCESS)
34410Sstevel@tonic-gate 						cmn_err(CE_NOTE,
34420Sstevel@tonic-gate 						    "failed to prune node, "
34430Sstevel@tonic-gate 						    "err %d", rv);
34440Sstevel@tonic-gate 				}
34450Sstevel@tonic-gate 			}
34460Sstevel@tonic-gate 		nex_dip = nex_dip->devi_next;
34470Sstevel@tonic-gate 		}
34480Sstevel@tonic-gate 	}
34490Sstevel@tonic-gate }
34500Sstevel@tonic-gate 
34510Sstevel@tonic-gate #endif /* PRUBE_SNUBS */
34520Sstevel@tonic-gate 
34530Sstevel@tonic-gate #ifdef KERNEL_DEVICE_TREE_WALKER
34540Sstevel@tonic-gate static kthread_id_t pwt;
34550Sstevel@tonic-gate static kmutex_t pwl;
34560Sstevel@tonic-gate static kcondvar_t pwcv;
34570Sstevel@tonic-gate 
34580Sstevel@tonic-gate static void
pshot_walk_tree()34590Sstevel@tonic-gate pshot_walk_tree()
34600Sstevel@tonic-gate {
34610Sstevel@tonic-gate 	static int pshot_devnode(dev_info_t *dip, void * arg);
34620Sstevel@tonic-gate 
34630Sstevel@tonic-gate 	dev_info_t *root = ddi_root_node();
34640Sstevel@tonic-gate 	ddi_walk_devs(root, pshot_devnode, NULL);
34650Sstevel@tonic-gate }
34660Sstevel@tonic-gate 
34670Sstevel@tonic-gate static void
pshot_walk_thread()34680Sstevel@tonic-gate pshot_walk_thread()
34690Sstevel@tonic-gate {
34700Sstevel@tonic-gate 	static void pshot_timeout(void *arg);
34710Sstevel@tonic-gate 	static kthread_id_t pwt;
34720Sstevel@tonic-gate 
34730Sstevel@tonic-gate 	pwt = curthread;
34740Sstevel@tonic-gate 	mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL);
34750Sstevel@tonic-gate 	cv_init(&pwcv, NULL, CV_DRIVER, NULL);
34760Sstevel@tonic-gate 
34770Sstevel@tonic-gate 	while (1) {
34780Sstevel@tonic-gate 		pshot_walk_tree();
34790Sstevel@tonic-gate 		mutex_enter(&pwl);
34800Sstevel@tonic-gate 		(void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000));
34810Sstevel@tonic-gate 		cv_wait(&pwcv, &pwl);
34820Sstevel@tonic-gate 		mutex_exit(&pwl);
34830Sstevel@tonic-gate 	}
34840Sstevel@tonic-gate }
34850Sstevel@tonic-gate 
34860Sstevel@tonic-gate static void
pshot_timeout(void * arg)34870Sstevel@tonic-gate pshot_timeout(void *arg)
34880Sstevel@tonic-gate {
34890Sstevel@tonic-gate 	mutex_enter(&pwl);
34900Sstevel@tonic-gate 	cv_signal(&pwcv);
34910Sstevel@tonic-gate 	mutex_exit(&pwl);
34920Sstevel@tonic-gate }
34930Sstevel@tonic-gate 
34940Sstevel@tonic-gate static int
pshot_devnode(dev_info_t * dip,void * arg)34950Sstevel@tonic-gate pshot_devnode(dev_info_t *dip, void *arg)
34960Sstevel@tonic-gate {
34970Sstevel@tonic-gate 	dev_info_t *f_dip;
34980Sstevel@tonic-gate 
34990Sstevel@tonic-gate 	if (dip != ddi_root_node()) {
35000Sstevel@tonic-gate 		f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent,
35010Sstevel@tonic-gate 		    DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr);
35020Sstevel@tonic-gate 		if (f_dip != dip) {
35030Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!pshot_devnode: failed lookup"
35047656SSherry.Moore@Sun.COM 			    "node (%s/%s@%s)\n",
35057656SSherry.Moore@Sun.COM 			    DEVI(DEVI(dip)->devi_parent)->devi_node_name,
35067656SSherry.Moore@Sun.COM 			    (DEVI(dip)->devi_node_name ?
35077656SSherry.Moore@Sun.COM 			    DEVI(dip)->devi_node_name : "NULL"),
35087656SSherry.Moore@Sun.COM 			    (DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr :
35097656SSherry.Moore@Sun.COM 			    "NULL"));
35100Sstevel@tonic-gate 		}
35110Sstevel@tonic-gate 	}
35120Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
35130Sstevel@tonic-gate }
35140Sstevel@tonic-gate #endif /* KERNEL_DEVICE_TREE_WALKER */
35150Sstevel@tonic-gate 
35160Sstevel@tonic-gate #ifdef DEBUG
35170Sstevel@tonic-gate static void
pshot_event_cb_test(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata)35180Sstevel@tonic-gate pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie,
35190Sstevel@tonic-gate 	void *arg, void *bus_impldata)
35200Sstevel@tonic-gate {
35210Sstevel@tonic-gate 	pshot_t *softstate = (pshot_t *)arg;
35220Sstevel@tonic-gate 	int event_tag;
35230Sstevel@tonic-gate 
35240Sstevel@tonic-gate 	/* look up the event */
35250Sstevel@tonic-gate 	event_tag = NDI_EVENT_TAG(cookie);
35260Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot_event_cb_test:\n\t"
35270Sstevel@tonic-gate 	    "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
35280Sstevel@tonic-gate 	    "arg = 0x%p bus_impl = 0x%p\n",
35290Sstevel@tonic-gate 	    (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie),
35300Sstevel@tonic-gate 	    event_tag, (void *)softstate, (void *)bus_impldata);
35310Sstevel@tonic-gate 
35320Sstevel@tonic-gate }
35330Sstevel@tonic-gate 
35340Sstevel@tonic-gate static void
pshot_event_test(void * arg)35350Sstevel@tonic-gate pshot_event_test(void *arg)
35360Sstevel@tonic-gate {
35370Sstevel@tonic-gate 	pshot_t *pshot = (pshot_t *)arg;
35380Sstevel@tonic-gate 	ndi_event_hdl_t hdl;
35390Sstevel@tonic-gate 	ndi_event_set_t	events;
35400Sstevel@tonic-gate 	int i, rval;
35410Sstevel@tonic-gate 
35420Sstevel@tonic-gate 	(void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP);
35430Sstevel@tonic-gate 
35440Sstevel@tonic-gate 	events.ndi_events_version = NDI_EVENTS_REV1;
35450Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
35460Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
35470Sstevel@tonic-gate 
35480Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
35490Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35500Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35510Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35520Sstevel@tonic-gate 
35530Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
35540Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35550Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35560Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35570Sstevel@tonic-gate 
35580Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
35590Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35600Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
35610Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
35620Sstevel@tonic-gate 
35630Sstevel@tonic-gate 
35640Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
35650Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35660Sstevel@tonic-gate 	events.ndi_n_events = 1;
35670Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35680Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35690Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35700Sstevel@tonic-gate 
35710Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
35720Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35730Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
35740Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
35750Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35760Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35770Sstevel@tonic-gate 
35780Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
35790Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35800Sstevel@tonic-gate 	events.ndi_n_events = 1;
35810Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35820Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
35830Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35840Sstevel@tonic-gate 
35850Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
35860Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35870Sstevel@tonic-gate 	events.ndi_n_events = 1;
35880Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35890Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35900Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35910Sstevel@tonic-gate 
35920Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
35930Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35940Sstevel@tonic-gate 	events.ndi_n_events = 1;
35950Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35960Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
35970Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35980Sstevel@tonic-gate 
35990Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
36000Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36010Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
36020Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36030Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
36040Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
36050Sstevel@tonic-gate 
36060Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding first 2 events\n");
36070Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36080Sstevel@tonic-gate 	events.ndi_n_events = 2;
36090Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36100Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36110Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36120Sstevel@tonic-gate 
36130Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n");
36140Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36150Sstevel@tonic-gate 	events.ndi_n_events = 2;
36160Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36170Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36180Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36190Sstevel@tonic-gate 
36200Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  middle 2 events\n");
36210Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36220Sstevel@tonic-gate 	events.ndi_n_events = 2;
36230Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
36240Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36250Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding those 2 events back\n");
36280Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36290Sstevel@tonic-gate 	events.ndi_n_events = 2;
36300Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
36310Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
36320Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
36330Sstevel@tonic-gate 
36340Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  2 events\n");
36350Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36360Sstevel@tonic-gate 	events.ndi_n_events = 2;
36370Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
36380Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36390Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36400Sstevel@tonic-gate 
36410Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
36420Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36430Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
36440Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36450Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36460Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36470Sstevel@tonic-gate 
36480Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36490Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36500Sstevel@tonic-gate 	events.ndi_n_events = 1;
36510Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[2];
36520Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36530Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36540Sstevel@tonic-gate 
36550Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36560Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36570Sstevel@tonic-gate 	events.ndi_n_events = 1;
36580Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[3];
36590Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36600Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36610Sstevel@tonic-gate 
36620Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36630Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36640Sstevel@tonic-gate 	events.ndi_n_events = 1;
36650Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[6];
36660Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36670Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36680Sstevel@tonic-gate 
36690Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36700Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36710Sstevel@tonic-gate 	events.ndi_n_events = 1;
36720Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[7];
36730Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36740Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36750Sstevel@tonic-gate 
36760Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
36770Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36780Sstevel@tonic-gate 
36790Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
36800Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36810Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
36820Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
36830Sstevel@tonic-gate 
36840Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: adding 8 callbacks\n");
36850Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36860Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
36870Sstevel@tonic-gate 		rval = ndi_event_add_callback(hdl, pshot->dip,
36887656SSherry.Moore@Sun.COM 		    ndi_event_tag_to_cookie(hdl,
36897656SSherry.Moore@Sun.COM 		    pshot_test_events[i].ndi_event_tag),
36907656SSherry.Moore@Sun.COM 		    pshot_event_cb_test,
36917656SSherry.Moore@Sun.COM 		    (void *)(uintptr_t)pshot_test_events[i].ndi_event_tag,
36927656SSherry.Moore@Sun.COM 		    NDI_SLEEP, &pshot->test_callback_cache[i]);
36930Sstevel@tonic-gate 		ASSERT(rval == NDI_SUCCESS);
36940Sstevel@tonic-gate 	}
36950Sstevel@tonic-gate 
36960Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: event callbacks\n");
36970Sstevel@tonic-gate 
36980Sstevel@tonic-gate 	for (i = 10; i < 18; i++) {
36990Sstevel@tonic-gate 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
37000Sstevel@tonic-gate 
37010Sstevel@tonic-gate 		rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie,
37020Sstevel@tonic-gate 		    (void *)hdl);
37030Sstevel@tonic-gate 
37040Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
37057656SSherry.Moore@Sun.COM 		    i, rval);
37060Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
37070Sstevel@tonic-gate 	}
37080Sstevel@tonic-gate 
37090Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: redo event callbacks\n");
37100Sstevel@tonic-gate 
37110Sstevel@tonic-gate 	for (i = 10; i < 18; i++) {
37120Sstevel@tonic-gate 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
37130Sstevel@tonic-gate 
37140Sstevel@tonic-gate 		rval = ndi_event_run_callbacks(hdl,
37157656SSherry.Moore@Sun.COM 		    pshot->dip, cookie, (void *)hdl);
37160Sstevel@tonic-gate 
37170Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
37187656SSherry.Moore@Sun.COM 		    i, rval);
37190Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
37200Sstevel@tonic-gate 	}
37210Sstevel@tonic-gate 
37220Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: removing 8 callbacks\n");
37230Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
37240Sstevel@tonic-gate 
37250Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
37260Sstevel@tonic-gate 		(void) ndi_event_remove_callback(hdl,
37270Sstevel@tonic-gate 		    pshot->test_callback_cache[i]);
37280Sstevel@tonic-gate 
37290Sstevel@tonic-gate 		pshot->test_callback_cache[i] = 0;
37300Sstevel@tonic-gate 	}
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: freeing handle with bound set\n");
37330Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
37340Sstevel@tonic-gate 
37350Sstevel@tonic-gate 	rval =	ndi_event_free_hdl(hdl);
37360Sstevel@tonic-gate 
37370Sstevel@tonic-gate 	ASSERT(rval == NDI_SUCCESS);
37380Sstevel@tonic-gate 
37390Sstevel@tonic-gate }
37400Sstevel@tonic-gate 
37410Sstevel@tonic-gate void
pshot_event_test_post_one(void * arg)37420Sstevel@tonic-gate pshot_event_test_post_one(void *arg)
37430Sstevel@tonic-gate {
37440Sstevel@tonic-gate 	pshot_t	*pshot = (pshot_t *)arg;
37450Sstevel@tonic-gate 	int rval;
37460Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
37470Sstevel@tonic-gate 
37480Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n",
37497656SSherry.Moore@Sun.COM 	    pshot->instance);
37500Sstevel@tonic-gate 
37510Sstevel@tonic-gate 	if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST,
37520Sstevel@tonic-gate 	    &cookie) != DDI_SUCCESS) {
37530Sstevel@tonic-gate 		cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found");
37540Sstevel@tonic-gate 		return;
37550Sstevel@tonic-gate 	}
37560Sstevel@tonic-gate 
37570Sstevel@tonic-gate 	rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL);
37580Sstevel@tonic-gate 
37590Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n",
37607656SSherry.Moore@Sun.COM 	    pshot->instance, rval);
37610Sstevel@tonic-gate 
37620Sstevel@tonic-gate 	(void) timeout(pshot_event_test_post_one, (void *)pshot,
37637656SSherry.Moore@Sun.COM 	    pshot->instance * drv_usectohz(60000000));
37640Sstevel@tonic-gate 
37650Sstevel@tonic-gate }
37660Sstevel@tonic-gate #endif /* DEBUG */
3767