xref: /illumos-gate/usr/src/uts/common/io/pshot.c (revision d5ebc493)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55e3986cbScth  * Common Development and Distribution License (the "License").
65e3986cbScth  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2208492e39SVikram Hegde  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
25cd21e7c5SGarrett D'Amore /*
26cd21e7c5SGarrett D'Amore  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
2748bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
283fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
29cd21e7c5SGarrett D'Amore  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * pseudo bus nexus driver
337c478bd9Sstevel@tonic-gate  * hotplug framework test facility
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate  * The pshot driver can be used to exercise the i/o framework together
387c478bd9Sstevel@tonic-gate  * with devfs by configuring an arbitrarily complex device tree.
397c478bd9Sstevel@tonic-gate  *
407c478bd9Sstevel@tonic-gate  * The pshot driver is rooted at /devices/pshot.  The following commands
417c478bd9Sstevel@tonic-gate  * illustrate the operation of devfs together with pshot's bus_config.
427c478bd9Sstevel@tonic-gate  * The first command demonstrates that, like the magician showing there's
4348bbca81SDaniel Hoffman  * nothing up their sleeve, /devices/pshot is empty.  The second command
447c478bd9Sstevel@tonic-gate  * conjures up a branch of pshot nodes.  Note that pshot's bus_config is
457c478bd9Sstevel@tonic-gate  * called sequentially by devfs for each node, as part of the pathname
467c478bd9Sstevel@tonic-gate  * resolution, and that each pshot node is fully configured and
477c478bd9Sstevel@tonic-gate  * attached before that node's bus_config is called to configure the
487c478bd9Sstevel@tonic-gate  * next child down the tree.  The final result is a "disk" node configured
497c478bd9Sstevel@tonic-gate  * at the bottom of the named hierarchy of pshot nodes.
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  *	#
527c478bd9Sstevel@tonic-gate  *	# ls /devices/pshot
537c478bd9Sstevel@tonic-gate  *	#
547c478bd9Sstevel@tonic-gate  *	# ls -ld /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
557c478bd9Sstevel@tonic-gate  *	drwxr-xr-x   2 root     sys          512 Feb  6 15:10
567c478bd9Sstevel@tonic-gate  *		/devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
577c478bd9Sstevel@tonic-gate  *
587c478bd9Sstevel@tonic-gate  * pshot supports some unique behaviors as aids for test error cases.
597c478bd9Sstevel@tonic-gate  *
607c478bd9Sstevel@tonic-gate  * Match these special address formats to behavior:
617c478bd9Sstevel@tonic-gate  *
627c478bd9Sstevel@tonic-gate  *	err.*		- induce bus_config error
637c478bd9Sstevel@tonic-gate  *	delay		- induce 1 second of bus_config delay time
647c478bd9Sstevel@tonic-gate  *	delay,n		- induce n seconds of bus_config delay time
657c478bd9Sstevel@tonic-gate  *	wait		- induce 1 second of bus_config wait time
667c478bd9Sstevel@tonic-gate  *	wait,n		- induce n seconds of bus_config wait time
677c478bd9Sstevel@tonic-gate  *	failinit.*	- induce error at INITCHILD
687c478bd9Sstevel@tonic-gate  *	failprobe.*	- induce error at probe
697c478bd9Sstevel@tonic-gate  *	failattach.*	- induce error at attach
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
737c478bd9Sstevel@tonic-gate #define	DEBUG	1
747c478bd9Sstevel@tonic-gate #endif
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #include <sys/types.h>
777c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
787c478bd9Sstevel@tonic-gate #include <sys/conf.h>
797c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
807c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
817c478bd9Sstevel@tonic-gate #include <sys/open.h>
827c478bd9Sstevel@tonic-gate #include <sys/stat.h>
837c478bd9Sstevel@tonic-gate #include <sys/file.h>
847c478bd9Sstevel@tonic-gate #include <sys/errno.h>
857c478bd9Sstevel@tonic-gate #include <sys/systm.h>
867c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
877c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
887c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
897c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
907c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
917c478bd9Sstevel@tonic-gate #include <sys/devctl.h>
927c478bd9Sstevel@tonic-gate #include <sys/disp.h>
937c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
947c478bd9Sstevel@tonic-gate #include <sys/pshot.h>
957c478bd9Sstevel@tonic-gate #include <sys/debug.h>
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate static int pshot_log		= 0;
987c478bd9Sstevel@tonic-gate static int pshot_devctl_debug	= 0;
997c478bd9Sstevel@tonic-gate static int pshot_debug_busy	= 0;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static void *pshot_softstatep;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate static int pshot_prop_autoattach;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	MAXPWR	3
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * device configuration data
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /* should keep in sync with current release */
1137c478bd9Sstevel@tonic-gate static struct {
1147c478bd9Sstevel@tonic-gate 	char *name;
1157c478bd9Sstevel@tonic-gate 	char *val;
1167c478bd9Sstevel@tonic-gate } pshot_nodetypes[] = {
1177c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL", DDI_NT_SERIAL},
1187c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB},
1197c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO},
1207c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO},
1217c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON},
1227c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK", DDI_NT_BLOCK},
1237c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN},
1247c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN},
125d88e498aSjiang wu - Sun Microsystems - Beijing China 	{"DDI_NT_BLOCK_SAS", DDI_NT_BLOCK_SAS},
1267c478bd9Sstevel@tonic-gate 	{"DDI_NT_CD", DDI_NT_CD},
1277c478bd9Sstevel@tonic-gate 	{"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN},
1287c478bd9Sstevel@tonic-gate 	{"DDI_NT_FD", DDI_NT_FD},
1297c478bd9Sstevel@tonic-gate 	{"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE},
1307c478bd9Sstevel@tonic-gate 	{"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE},
1317c478bd9Sstevel@tonic-gate 	{"DDI_NT_TAPE", DDI_NT_TAPE},
1327c478bd9Sstevel@tonic-gate 	{"DDI_NT_NET", DDI_NT_NET},
1337c478bd9Sstevel@tonic-gate 	{"DDI_NT_DISPLAY", DDI_NT_DISPLAY},
1347c478bd9Sstevel@tonic-gate 	{"DDI_PSEUDO", DDI_PSEUDO},
1357c478bd9Sstevel@tonic-gate 	{"DDI_NT_AUDIO", DDI_NT_AUDIO},
1367c478bd9Sstevel@tonic-gate 	{"DDI_NT_MOUSE", DDI_NT_MOUSE},
1377c478bd9Sstevel@tonic-gate 	{"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD},
1387c478bd9Sstevel@tonic-gate 	{"DDI_NT_PARALLEL", DDI_NT_PARALLEL},
1397c478bd9Sstevel@tonic-gate 	{"DDI_NT_PRINTER", DDI_NT_PRINTER},
1407c478bd9Sstevel@tonic-gate 	{"DDI_NT_UGEN", DDI_NT_UGEN},
1417c478bd9Sstevel@tonic-gate 	{"DDI_NT_NEXUS", DDI_NT_NEXUS},
1427c478bd9Sstevel@tonic-gate 	{"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS},
1437c478bd9Sstevel@tonic-gate 	{"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT},
1447c478bd9Sstevel@tonic-gate 	{"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT},
1457c478bd9Sstevel@tonic-gate 	{"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT},
1467c478bd9Sstevel@tonic-gate 	{"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT},
1477c478bd9Sstevel@tonic-gate 	{"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT},
1487c478bd9Sstevel@tonic-gate 	{"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT},
1497c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC},
1507c478bd9Sstevel@tonic-gate 	{"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC},
1517c478bd9Sstevel@tonic-gate 	{"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH},
1527c478bd9Sstevel@tonic-gate 	{ NULL, NULL }
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /* Node name */
1567c478bd9Sstevel@tonic-gate static char *pshot_compat_diskname = "cdisk";
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /* Compatible names... */
1597c478bd9Sstevel@tonic-gate static char *pshot_compat_psramdisks[] = {
1607c478bd9Sstevel@tonic-gate 	"psramhead",
1617c478bd9Sstevel@tonic-gate 	"psramrom",
1627c478bd9Sstevel@tonic-gate 	"psramdisk",
1637c478bd9Sstevel@tonic-gate 	"psramd",
1647c478bd9Sstevel@tonic-gate 	"psramwhat"
1657c478bd9Sstevel@tonic-gate };
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * devices "natively" supported by pshot (i.e. included with SUNWiotu)
1697c478bd9Sstevel@tonic-gate  * used to initialize pshot_devices with
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate static pshot_device_t pshot_stock_devices[] = {
1727c478bd9Sstevel@tonic-gate 	{"disk",	DDI_NT_BLOCK,		"gen_drv"},
1737c478bd9Sstevel@tonic-gate 	{"disk_chan",	DDI_NT_BLOCK_CHAN,	"gen_drv"},
1747c478bd9Sstevel@tonic-gate 	{"disk_wwn",	DDI_NT_BLOCK_WWN,	"gen_drv"},
1757c478bd9Sstevel@tonic-gate 	{"disk_cdrom",	DDI_NT_CD,		"gen_drv"},
1767c478bd9Sstevel@tonic-gate 	{"disk_cdrom.chan", DDI_NT_CD_CHAN,	"gen_drv"},
1777c478bd9Sstevel@tonic-gate /* Note: use bad_drv to force attach errors */
1787c478bd9Sstevel@tonic-gate 	{"disk_fd",	DDI_NT_FD,		"bad_drv"},
1797c478bd9Sstevel@tonic-gate 	{"tape",	DDI_NT_TAPE,		"gen_drv"},
1807c478bd9Sstevel@tonic-gate 	{"net",		DDI_NT_NET,		"gen_drv"},
1817c478bd9Sstevel@tonic-gate 	{"display",	DDI_NT_DISPLAY,		"gen_drv"},
1827c478bd9Sstevel@tonic-gate 	{"pseudo",	DDI_PSEUDO,		"gen_drv"},
1837c478bd9Sstevel@tonic-gate 	{"audio",	DDI_NT_AUDIO,		"gen_drv"},
1847c478bd9Sstevel@tonic-gate 	{"mouse",	DDI_NT_MOUSE,		"gen_drv"},
1857c478bd9Sstevel@tonic-gate 	{"keyboard",	DDI_NT_KEYBOARD,	"gen_drv"},
1867c478bd9Sstevel@tonic-gate 	{"nexus",	DDI_NT_NEXUS,		"pshot"}
1877c478bd9Sstevel@tonic-gate };
1887c478bd9Sstevel@tonic-gate #define	PSHOT_N_STOCK_DEVICES \
1897c478bd9Sstevel@tonic-gate 	(sizeof (pshot_stock_devices) / sizeof (pshot_device_t))
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate static pshot_device_t *pshot_devices = NULL;
1927c478bd9Sstevel@tonic-gate static size_t pshot_devices_len = 0;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /* protects <pshot_devices>, <pshot_devices_len> */
1957c478bd9Sstevel@tonic-gate static kmutex_t pshot_devices_lock;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate  * event testing
2007c478bd9Sstevel@tonic-gate  */
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_ndi_event_defs[] = {
2037c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_OFFLINE, PSHOT_EVENT_NAME_DEV_OFFLINE,
2047c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_DEV_RESET, PSHOT_EVENT_NAME_DEV_RESET,
2077c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_RESET, PSHOT_EVENT_NAME_BUS_RESET,
2107c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_QUIESCE, PSHOT_EVENT_NAME_BUS_QUIESCE,
2137c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_UNQUIESCE, PSHOT_EVENT_NAME_BUS_UNQUIESCE,
2167c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_TEST_POST, PSHOT_EVENT_NAME_BUS_TEST_POST,
2197c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }
2207c478bd9Sstevel@tonic-gate };
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate #define	PSHOT_N_NDI_EVENTS \
2247c478bd9Sstevel@tonic-gate 	(sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t))
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate #ifdef DEBUG
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events[] = {
2297c478bd9Sstevel@tonic-gate { 10, "test event 0", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2307c478bd9Sstevel@tonic-gate { 11, "test event 1", EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
2317c478bd9Sstevel@tonic-gate { 12, "test event 2", EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
2327c478bd9Sstevel@tonic-gate { 13, "test event 3", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2337c478bd9Sstevel@tonic-gate { 14, "test event 4", EPL_KERNEL, NDI_EVENT_POST_TO_ALL},
2347c478bd9Sstevel@tonic-gate { 15, "test event 5", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
2357c478bd9Sstevel@tonic-gate { 16, "test event 6", EPL_KERNEL, NDI_EVENT_POST_TO_ALL },
2367c478bd9Sstevel@tonic-gate { 17, "test event 7", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }
2377c478bd9Sstevel@tonic-gate };
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events_high[] = {
2407c478bd9Sstevel@tonic-gate { 20, "test event high 0", EPL_HIGHLEVEL, NDI_EVENT_POST_TO_ALL}
2417c478bd9Sstevel@tonic-gate };
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate #define	PSHOT_N_TEST_EVENTS \
2447c478bd9Sstevel@tonic-gate 	(sizeof (pshot_test_events)/sizeof (ndi_event_definition_t))
2457c478bd9Sstevel@tonic-gate #endif
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate struct register_events {
2487c478bd9Sstevel@tonic-gate 	char		*event_name;
2497c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t event_cookie;
2507c478bd9Sstevel@tonic-gate 	void	(*event_callback)
2517c478bd9Sstevel@tonic-gate 			(dev_info_t *,
2527c478bd9Sstevel@tonic-gate 			ddi_eventcookie_t,
2537c478bd9Sstevel@tonic-gate 			void *arg,
2547c478bd9Sstevel@tonic-gate 			void *impldata);
2557c478bd9Sstevel@tonic-gate 	ddi_callback_id_t cb_id;
2567c478bd9Sstevel@tonic-gate };
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate struct register_events pshot_register_events[] = {
2597c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 },
2607c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 },
2617c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 },
2627c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 },
2637c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 },
2647c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 }
2657c478bd9Sstevel@tonic-gate };
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate #define	PSHOT_N_DDI_EVENTS \
2687c478bd9Sstevel@tonic-gate 	(sizeof (pshot_register_events) / sizeof (struct register_events))
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate #ifdef DEBUG
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate static struct register_events pshot_register_test[] = {
2747c478bd9Sstevel@tonic-gate { "test event 0", 0, pshot_event_cb_test, 0},
2757c478bd9Sstevel@tonic-gate { "test event 1", 0, pshot_event_cb_test, 0},
2767c478bd9Sstevel@tonic-gate { "test event 2", 0, pshot_event_cb_test, 0},
2777c478bd9Sstevel@tonic-gate { "test event 3", 0, pshot_event_cb_test, 0},
2787c478bd9Sstevel@tonic-gate { "test event 4", 0, pshot_event_cb_test, 0},
2797c478bd9Sstevel@tonic-gate { "test event 5", 0, pshot_event_cb_test, 0},
2807c478bd9Sstevel@tonic-gate { "test event 6", 0, pshot_event_cb_test, 0},
2817c478bd9Sstevel@tonic-gate { "test event 7", 0, pshot_event_cb_test, 0}
2827c478bd9Sstevel@tonic-gate };
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate static struct register_events pshot_register_high_test[] = {
2867c478bd9Sstevel@tonic-gate 	{"test event high 0", 0, pshot_event_cb_test, 0}
2877c478bd9Sstevel@tonic-gate };
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate #endif /* DEBUG */
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate static struct {
2927c478bd9Sstevel@tonic-gate 	int ioctl_int;
2937c478bd9Sstevel@tonic-gate 	char *ioctl_char;
2947c478bd9Sstevel@tonic-gate } pshot_devctls[] = {
2957c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"},
2967c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"},
2977c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"},
2987c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"},
2997c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"},
3007c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"},
3017c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"},
3027c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"},
3037c478bd9Sstevel@tonic-gate 	{0, NULL}
3047c478bd9Sstevel@tonic-gate };
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate static struct bus_ops pshot_bus_ops = {
3077c478bd9Sstevel@tonic-gate 	BUSO_REV,			/* busops_rev */
3087c478bd9Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
3097c478bd9Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
3107c478bd9Sstevel@tonic-gate 	NULL,				/* bus_add_interspec */
3117c478bd9Sstevel@tonic-gate 	NULL,				/* bus_remove_interspec */
3127c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,		/* bus_map_fault */
313cd21e7c5SGarrett D'Amore 	NULL,				/* bus_dma_map */
314b1dd958fScth 	ddi_dma_allochdl,		/* bus_dma_allochdl */
315b1dd958fScth 	ddi_dma_freehdl,		/* bus_dma_freehdl */
316b1dd958fScth 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
317b1dd958fScth 	ddi_dma_unbindhdl,		/* bus_dma_unbindhdl */
318b1dd958fScth 	ddi_dma_flush,			/* bus_dma_flush */
319b1dd958fScth 	ddi_dma_win,			/* bus_dma_win */
320b1dd958fScth 	ddi_dma_mctl,			/* bus_dma_ctl */
3217c478bd9Sstevel@tonic-gate 	pshot_ctl,			/* bus_ctl */
3227c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
3237c478bd9Sstevel@tonic-gate 	pshot_get_eventcookie,		/* bus_get_eventcookie */
3247c478bd9Sstevel@tonic-gate 	pshot_add_eventcall,		/* bus_add_eventcall */
3257c478bd9Sstevel@tonic-gate 	pshot_remove_eventcall,		/* bus_remove_event */
3267c478bd9Sstevel@tonic-gate 	pshot_post_event,		/* bus_post_event */
3277c478bd9Sstevel@tonic-gate 	NULL,				/* bus_intr_ctl */
3287c478bd9Sstevel@tonic-gate 	pshot_bus_config,		/* bus_config */
3297c478bd9Sstevel@tonic-gate 	pshot_bus_unconfig,		/* bus_unconfig */
3307c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_init */
3317c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_fini */
3327c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_enter */
3337c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_exit */
3347c478bd9Sstevel@tonic-gate 	pshot_bus_power,		/* bus_power */
3357c478bd9Sstevel@tonic-gate 	pshot_bus_introp		/* bus_intr_op */
3367c478bd9Sstevel@tonic-gate };
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate static struct cb_ops pshot_cb_ops = {
3397c478bd9Sstevel@tonic-gate 	pshot_open,			/* open */
3407c478bd9Sstevel@tonic-gate 	pshot_close,			/* close */
3417c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
3427c478bd9Sstevel@tonic-gate 	nodev,				/* print */
3437c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
3447c478bd9Sstevel@tonic-gate 	nodev,				/* read */
3457c478bd9Sstevel@tonic-gate 	nodev,				/* write */
3467c478bd9Sstevel@tonic-gate 	pshot_ioctl,			/* ioctl */
3477c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
3487c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
3497c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
3507c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
3517c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* prop_op */
3527c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
3537c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* flags */
3547c478bd9Sstevel@tonic-gate 	CB_REV,				/* cb_rev */
3557c478bd9Sstevel@tonic-gate 	nodev,				/* aread */
3567c478bd9Sstevel@tonic-gate 	nodev,				/* awrite */
3577c478bd9Sstevel@tonic-gate };
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate static struct dev_ops pshot_ops = {
3607c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
3617c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
3627c478bd9Sstevel@tonic-gate 	pshot_info,		/* getinfo */
3637c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
3647c478bd9Sstevel@tonic-gate 	pshot_probe,		/* probe */
3657c478bd9Sstevel@tonic-gate 	pshot_attach,		/* attach */
3667c478bd9Sstevel@tonic-gate 	pshot_detach,		/* detach */
3677c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
3687c478bd9Sstevel@tonic-gate 	&pshot_cb_ops,		/* driver operations */
3697c478bd9Sstevel@tonic-gate 	&pshot_bus_ops,		/* bus operations */
37019397407SSherry Moore 	pshot_power,		/* power */
37119397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate };
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
3807c478bd9Sstevel@tonic-gate 	&mod_driverops,
38119397407SSherry Moore 	"pshotnex",
3827c478bd9Sstevel@tonic-gate 	&pshot_ops,
3837c478bd9Sstevel@tonic-gate };
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3867c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
3877c478bd9Sstevel@tonic-gate };
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * pshot_devices is set up on the first attach and destroyed on fini
3927c478bd9Sstevel@tonic-gate  *
3937c478bd9Sstevel@tonic-gate  * therefore PSHOT_PROP_DEV* properties may be set just for the root device,
3947c478bd9Sstevel@tonic-gate  * instead of being set globably, in pshot.conf by specifying the properties
3957c478bd9Sstevel@tonic-gate  * on a single line in the form:
3967c478bd9Sstevel@tonic-gate  *	name="pshot" parent="/" <dev props ..>
3977c478bd9Sstevel@tonic-gate  * to unclutter a device tree snapshot.
3987c478bd9Sstevel@tonic-gate  * this of course produces a long single line that may wrap around several
3997c478bd9Sstevel@tonic-gate  * times on screen
4007c478bd9Sstevel@tonic-gate  */
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate int
_init(void)4037c478bd9Sstevel@tonic-gate _init(void)
4047c478bd9Sstevel@tonic-gate {
4057c478bd9Sstevel@tonic-gate 	int rv;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	rv = ddi_soft_state_init(&pshot_softstatep, sizeof (pshot_t), 0);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (rv != DDI_SUCCESS)
4107c478bd9Sstevel@tonic-gate 		return (rv);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	mutex_init(&pshot_devices_lock, NULL, MUTEX_DRIVER, NULL);
4137c478bd9Sstevel@tonic-gate 	pshot_devices = NULL;
4147c478bd9Sstevel@tonic-gate 	pshot_devices_len = 0;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if ((rv = mod_install(&modlinkage)) != 0) {
4177c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&pshot_softstatep);
4187c478bd9Sstevel@tonic-gate 		mutex_destroy(&pshot_devices_lock);
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 	return (rv);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate int
_fini(void)4247c478bd9Sstevel@tonic-gate _fini(void)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	int rv;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if ((rv = mod_remove(&modlinkage)) != 0)
4297c478bd9Sstevel@tonic-gate 		return (rv);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&pshot_softstatep);
4327c478bd9Sstevel@tonic-gate 	mutex_destroy(&pshot_devices_lock);
4337c478bd9Sstevel@tonic-gate 	if (pshot_devices)
4347c478bd9Sstevel@tonic-gate 		pshot_devices_free(pshot_devices, pshot_devices_len);
4357c478bd9Sstevel@tonic-gate 	return (0);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4397c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
4407c478bd9Sstevel@tonic-gate {
4417c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4467c478bd9Sstevel@tonic-gate static int
pshot_probe(dev_info_t * devi)4477c478bd9Sstevel@tonic-gate pshot_probe(dev_info_t *devi)
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(devi);
4507c478bd9Sstevel@tonic-gate 	char	*bus_addr;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	/*
4537c478bd9Sstevel@tonic-gate 	 * Hook for tests to force probe fail
4547c478bd9Sstevel@tonic-gate 	 */
4557c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
4567c478bd9Sstevel@tonic-gate 	    &bus_addr) == DDI_PROP_SUCCESS) {
4577c478bd9Sstevel@tonic-gate 		if (strncmp(bus_addr, "failprobe", 9) == 0) {
4587c478bd9Sstevel@tonic-gate 			if (pshot_debug)
4597c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: "
4607c478bd9Sstevel@tonic-gate 				    "%s forced probe failure\n",
4617c478bd9Sstevel@tonic-gate 				    instance, bus_addr);
4627c478bd9Sstevel@tonic-gate 			ddi_prop_free(bus_addr);
4637c478bd9Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4737c478bd9Sstevel@tonic-gate static int
pshot_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4747c478bd9Sstevel@tonic-gate pshot_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
4757c478bd9Sstevel@tonic-gate {
4767c478bd9Sstevel@tonic-gate 	int instance;
4777c478bd9Sstevel@tonic-gate 	minor_t minor;
4787c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	minor = getminor((dev_t)arg);
4817c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(minor);
4827c478bd9Sstevel@tonic-gate 	switch (infocmd) {
4837c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
4847c478bd9Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
4857c478bd9Sstevel@tonic-gate 		if (pshot == NULL) {
4867c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot_info: get soft state failed "
4877c478bd9Sstevel@tonic-gate 			    "on minor %u, instance %d", minor, instance);
4887c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
4897c478bd9Sstevel@tonic-gate 		}
4907c478bd9Sstevel@tonic-gate 		*result = (void *)pshot->dip;
4917c478bd9Sstevel@tonic-gate 		break;
4927c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
4937c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
4947c478bd9Sstevel@tonic-gate 		break;
4957c478bd9Sstevel@tonic-gate 	default:
4967c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_info: unrecognized cmd 0x%x on "
4977c478bd9Sstevel@tonic-gate 		    "minor %u, instance %d", infocmd, minor, instance);
4987c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate static int
pshot_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)5067c478bd9Sstevel@tonic-gate pshot_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(devi);
5097c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
5107c478bd9Sstevel@tonic-gate 	int rval, i;
5117c478bd9Sstevel@tonic-gate 	int prop_flags = DDI_PROP_DONTPASS | DDI_PROP_NOTPROM;
5127c478bd9Sstevel@tonic-gate 	char *bus_addr;
5137c478bd9Sstevel@tonic-gate 	char *pm_comp[] = {
5147c478bd9Sstevel@tonic-gate 		"NAME=bus",
5157c478bd9Sstevel@tonic-gate 		"0=B3",
5167c478bd9Sstevel@tonic-gate 		"1=B2",
5177c478bd9Sstevel@tonic-gate 		"2=B1",
5187c478bd9Sstevel@tonic-gate 		"3=B0"};
5197c478bd9Sstevel@tonic-gate 	char *pm_hw_state = {"needs-suspend-resume"};
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	pshot_prop_autoattach = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
5227c478bd9Sstevel@tonic-gate 	    prop_flags, "autoattach", 0);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	switch (cmd) {
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
5277c478bd9Sstevel@tonic-gate 		if (pshot_debug)
5287c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "attach: %s%d/pshot%d\n",
52919397407SSherry Moore 			    ddi_get_name(ddi_get_parent(devi)),
53019397407SSherry Moore 			    ddi_get_instance(ddi_get_parent(devi)),
53119397407SSherry Moore 			    instance);
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		/*
5347c478bd9Sstevel@tonic-gate 		 * Hook for tests to force attach fail
5357c478bd9Sstevel@tonic-gate 		 */
5367c478bd9Sstevel@tonic-gate 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
5377c478bd9Sstevel@tonic-gate 		    &bus_addr) == DDI_PROP_SUCCESS) && bus_addr != NULL) {
5387c478bd9Sstevel@tonic-gate 			if (strncmp(bus_addr, "failattach", 10) == 0) {
5397c478bd9Sstevel@tonic-gate 				if (pshot_debug)
5407c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: "
5417c478bd9Sstevel@tonic-gate 					    "%s forced attach failure\n",
5427c478bd9Sstevel@tonic-gate 					    instance, bus_addr);
5437c478bd9Sstevel@tonic-gate 				ddi_prop_free(bus_addr);
5447c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
5457c478bd9Sstevel@tonic-gate 			}
5467c478bd9Sstevel@tonic-gate 			ddi_prop_free(bus_addr);
5477c478bd9Sstevel@tonic-gate 		}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 		/*
5507c478bd9Sstevel@tonic-gate 		 * minor nodes setup
5517c478bd9Sstevel@tonic-gate 		 */
5527c478bd9Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(pshot_softstatep, instance) !=
5537c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
5547c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
5577c478bd9Sstevel@tonic-gate 		pshot->dip = devi;
5587c478bd9Sstevel@tonic-gate 		pshot->instance = instance;
5597c478bd9Sstevel@tonic-gate 		mutex_init(&pshot->lock, NULL, MUTEX_DRIVER, NULL);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 		/* set each minor, then create on dip all together */
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		i = PSHOT_NODENUM_DEVCTL;
5647c478bd9Sstevel@tonic-gate 		pshot->nodes[i].pshot = pshot;
5657c478bd9Sstevel@tonic-gate 		pshot->nodes[i].minor = pshot_minor_encode(instance, i);
5667c478bd9Sstevel@tonic-gate 		(void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_DEVCTL,
5677c478bd9Sstevel@tonic-gate 		    PSHOT_MAX_MINOR_NAMELEN);
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		i = PSHOT_NODENUM_TESTCTL;
5707c478bd9Sstevel@tonic-gate 		pshot->nodes[i].pshot = pshot;
5717c478bd9Sstevel@tonic-gate 		pshot->nodes[i].minor = pshot_minor_encode(instance, i);
5727c478bd9Sstevel@tonic-gate 		(void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_TESTCTL,
5737c478bd9Sstevel@tonic-gate 		    PSHOT_MAX_MINOR_NAMELEN);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 		/* this assumes contiguous a filling */
5767c478bd9Sstevel@tonic-gate 		for (i = 0; i <= PSHOT_MAX_NODENUM; i++) {
5777c478bd9Sstevel@tonic-gate 			if (ddi_create_minor_node(devi, pshot->nodes[i].name,
5787c478bd9Sstevel@tonic-gate 			    S_IFCHR, pshot->nodes[i].minor, DDI_NT_NEXUS, 0) !=
5797c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
5807c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "attach: cannot create "
5817c478bd9Sstevel@tonic-gate 				    "minor %s", pshot->nodes[i].name);
5827c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
5837c478bd9Sstevel@tonic-gate 			}
5847c478bd9Sstevel@tonic-gate 		}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 		/*
5877c478bd9Sstevel@tonic-gate 		 * pshot_devices setup
5887c478bd9Sstevel@tonic-gate 		 */
5897c478bd9Sstevel@tonic-gate 		if (pshot_devices_setup(devi)) {
5907c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "attach: pshot devices setup "
5917c478bd9Sstevel@tonic-gate 			    "failed");
5927c478bd9Sstevel@tonic-gate 			goto FAIL_ATTACH;
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		/*
5967c478bd9Sstevel@tonic-gate 		 * events setup
5977c478bd9Sstevel@tonic-gate 		 */
5987c478bd9Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
5997c478bd9Sstevel@tonic-gate 			rval =	ddi_get_eventcookie(devi,
6007c478bd9Sstevel@tonic-gate 			    pshot_register_events[i].event_name,
6017c478bd9Sstevel@tonic-gate 			    &pshot_register_events[i].event_cookie);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 			if (pshot_debug)
6047c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: event=%s:"
6057c478bd9Sstevel@tonic-gate 				    "ddi_get_eventcookie rval=%d\n",
6067c478bd9Sstevel@tonic-gate 				    instance,
6077c478bd9Sstevel@tonic-gate 				    pshot_register_events[i].event_name, rval);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 			if (rval == DDI_SUCCESS) {
6107c478bd9Sstevel@tonic-gate 				rval = ddi_add_event_handler(devi,
6117c478bd9Sstevel@tonic-gate 				    pshot_register_events[i].event_cookie,
6127c478bd9Sstevel@tonic-gate 				    pshot_register_events[i].event_callback,
6137c478bd9Sstevel@tonic-gate 				    (void *)pshot,
6147c478bd9Sstevel@tonic-gate 				    &pshot->callback_cache[i]);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 				if (pshot_debug)
6177c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: event=%s: "
6187c478bd9Sstevel@tonic-gate 					    "ddi_add_event_handler rval=%d\n",
6197c478bd9Sstevel@tonic-gate 					    instance,
6207c478bd9Sstevel@tonic-gate 					    pshot_register_events[i].event_name,
6217c478bd9Sstevel@tonic-gate 					    rval);
6227c478bd9Sstevel@tonic-gate 			}
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate #ifdef DEBUG
6267c478bd9Sstevel@tonic-gate 		if (pshot_event_test_enable) {
6277c478bd9Sstevel@tonic-gate 			pshot_event_test((void *)pshot);
6287c478bd9Sstevel@tonic-gate 			(void) timeout(pshot_event_test_post_one, (void *)pshot,
6297c478bd9Sstevel@tonic-gate 			    instance * drv_usectohz(60000000));
6307c478bd9Sstevel@tonic-gate 		}
6317c478bd9Sstevel@tonic-gate #endif
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 		/*
6347c478bd9Sstevel@tonic-gate 		 * allocate an ndi event handle
6357c478bd9Sstevel@tonic-gate 		 */
6367c478bd9Sstevel@tonic-gate 		if (ndi_event_alloc_hdl(devi, NULL, &pshot->ndi_event_hdl,
6377c478bd9Sstevel@tonic-gate 		    NDI_SLEEP) != NDI_SUCCESS) {
6387c478bd9Sstevel@tonic-gate 			goto FAIL_ATTACH;
6397c478bd9Sstevel@tonic-gate 		}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 		pshot->ndi_events.ndi_events_version = NDI_EVENTS_REV1;
6427c478bd9Sstevel@tonic-gate 		pshot->ndi_events.ndi_n_events = PSHOT_N_NDI_EVENTS;
6437c478bd9Sstevel@tonic-gate 		pshot->ndi_events.ndi_event_defs = pshot_ndi_event_defs;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 		if (ndi_event_bind_set(pshot->ndi_event_hdl, &pshot->ndi_events,
6467c478bd9Sstevel@tonic-gate 		    NDI_SLEEP) != NDI_SUCCESS) {
6477c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d bind set failed\n",
64819397407SSherry Moore 			    instance);
6497c478bd9Sstevel@tonic-gate 		}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		/*
6527c478bd9Sstevel@tonic-gate 		 * setup a test for nexus auto-attach iff we are
6537c478bd9Sstevel@tonic-gate 		 * a second level pshot node (parent == /SUNW,pshot)
6547c478bd9Sstevel@tonic-gate 		 * enable by setting "autoattach=1" in pshot.conf
6557c478bd9Sstevel@tonic-gate 		 */
6567c478bd9Sstevel@tonic-gate 		if ((PARENT_IS_PSHOT(devi)) && (pshot_prop_autoattach != 0) &&
6577c478bd9Sstevel@tonic-gate 		    (ddi_get_instance(ddi_get_parent(devi))) == 0)
6587c478bd9Sstevel@tonic-gate 			pshot_setup_autoattach(devi);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 		/*
6617c478bd9Sstevel@tonic-gate 		 * initialize internal state to idle: busy = 0,
6627c478bd9Sstevel@tonic-gate 		 * power level = -1
6637c478bd9Sstevel@tonic-gate 		 */
6647c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
6657c478bd9Sstevel@tonic-gate 		pshot->busy = 0;
6667c478bd9Sstevel@tonic-gate 		pshot->busy_ioctl = 0;
6677c478bd9Sstevel@tonic-gate 		pshot->level = -1;
6687c478bd9Sstevel@tonic-gate 		pshot->state &= ~STRICT_PARENT;
6697c478bd9Sstevel@tonic-gate 		pshot->state |= PM_SUPPORTED;
6707c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		/*
6737c478bd9Sstevel@tonic-gate 		 * Create the "pm-want-child-notification?" property
6747c478bd9Sstevel@tonic-gate 		 * for the root node /devices/pshot
6757c478bd9Sstevel@tonic-gate 		 */
6767c478bd9Sstevel@tonic-gate 		if (instance == 0) {
6777c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
6787c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:\n\t"
6797c478bd9Sstevel@tonic-gate 				    " create the"
6807c478bd9Sstevel@tonic-gate 				    " \"pm-want-child-notification?\" property"
6817c478bd9Sstevel@tonic-gate 				    " for the root node\n", instance);
6827c478bd9Sstevel@tonic-gate 			}
6837c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, devi, 0,
6847c478bd9Sstevel@tonic-gate 			    "pm-want-child-notification?", NULL, 0)
6857c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
6867c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d:\n\t"
6877c478bd9Sstevel@tonic-gate 				    " unable to create the"
6887c478bd9Sstevel@tonic-gate 				    " \"pm-want-child-notification?\""
6897c478bd9Sstevel@tonic-gate 				    " property", ddi_get_name(devi),
6907c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
6937c478bd9Sstevel@tonic-gate 			}
6947c478bd9Sstevel@tonic-gate 		}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 		/*
6977c478bd9Sstevel@tonic-gate 		 * Check if the pm-want-child-notification? property was
6987c478bd9Sstevel@tonic-gate 		 * created in pshot_bus_config_setup_nexus() by the parent.
6997c478bd9Sstevel@tonic-gate 		 * Set the STRICT_PARENT flag if not.
7007c478bd9Sstevel@tonic-gate 		 */
7017c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
7027c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
7037c478bd9Sstevel@tonic-gate 		    "pm-want-child-notification?") != 1) {
7047c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
7057c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7067c478bd9Sstevel@tonic-gate 				    " STRICT PARENT\n", instance);
7077c478bd9Sstevel@tonic-gate 			}
7087c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
7097c478bd9Sstevel@tonic-gate 			pshot->state |= STRICT_PARENT;
7107c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
7117c478bd9Sstevel@tonic-gate 		} else {
7127c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
7137c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7147c478bd9Sstevel@tonic-gate 				    " INVOLVED PARENT\n", instance);
7157c478bd9Sstevel@tonic-gate 			}
7167c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
7177c478bd9Sstevel@tonic-gate 			pshot->state &= ~STRICT_PARENT;
7187c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
7197c478bd9Sstevel@tonic-gate 		}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 		/*
7227c478bd9Sstevel@tonic-gate 		 * create the pm-components property: one component
7237c478bd9Sstevel@tonic-gate 		 * with 4 power levels.
7247c478bd9Sstevel@tonic-gate 		 * - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict:
7257c478bd9Sstevel@tonic-gate 		 * "no-pm-components" property
7267c478bd9Sstevel@tonic-gate 		 */
7277c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
7287c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
7297c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 0) {
7307c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
7317c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7327c478bd9Sstevel@tonic-gate 				    " create the \"pm_components\" property\n",
7337c478bd9Sstevel@tonic-gate 				    instance);
7347c478bd9Sstevel@tonic-gate 			}
7357c478bd9Sstevel@tonic-gate 			if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
7367c478bd9Sstevel@tonic-gate 			    "pm-components", pm_comp, 5) != DDI_PROP_SUCCESS) {
7377c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
7387c478bd9Sstevel@tonic-gate 				    " unable to create the \"pm-components\""
7397c478bd9Sstevel@tonic-gate 				    " property", ddi_get_name(devi),
7407c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
7437c478bd9Sstevel@tonic-gate 			}
7447c478bd9Sstevel@tonic-gate 		} else {
7457c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
7467c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7477c478bd9Sstevel@tonic-gate 				    " NO-PM_COMPONENTS PARENT\n", instance);
7487c478bd9Sstevel@tonic-gate 			}
7497c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
7507c478bd9Sstevel@tonic-gate 			pshot->state &= ~PM_SUPPORTED;
7517c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
7527c478bd9Sstevel@tonic-gate 		}
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 		/*
7557c478bd9Sstevel@tonic-gate 		 * create the property needed to get DDI_SUSPEND
7567c478bd9Sstevel@tonic-gate 		 * and DDI_RESUME calls
7577c478bd9Sstevel@tonic-gate 		 */
7587c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
7597c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7607c478bd9Sstevel@tonic-gate 			    " create pm-hardware-state property\n",
7617c478bd9Sstevel@tonic-gate 			    instance);
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 		if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
7647c478bd9Sstevel@tonic-gate 		    "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
7657c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
7667c478bd9Sstevel@tonic-gate 			    " unable to create the \"pm-hardware-state\""
7677c478bd9Sstevel@tonic-gate 			    " property", ddi_get_name(devi),
7687c478bd9Sstevel@tonic-gate 			    ddi_get_instance(devi));
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 			goto FAIL_ATTACH;
7717c478bd9Sstevel@tonic-gate 		}
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 		/*
7747c478bd9Sstevel@tonic-gate 		 * set power level to max via pm_raise_power(),
7757c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
7767c478bd9Sstevel@tonic-gate 		 */
7777c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
7787c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
7797c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
7807c478bd9Sstevel@tonic-gate 				    " raise power to MAXPWR\n", instance);
7817c478bd9Sstevel@tonic-gate 			}
7827c478bd9Sstevel@tonic-gate 			if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
7837c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
7847c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:"
7857c478bd9Sstevel@tonic-gate 				    " pm_raise_power failed",
7867c478bd9Sstevel@tonic-gate 				    ddi_get_name(devi),
7877c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 			}
7927c478bd9Sstevel@tonic-gate 		}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 		if (pshot_log)
7957c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d attached\n", instance);
7967c478bd9Sstevel@tonic-gate 		ddi_report_dev(devi);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7997c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
8007c478bd9Sstevel@tonic-gate FAIL_ATTACH:
8017c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
8027c478bd9Sstevel@tonic-gate 		mutex_destroy(&pshot->lock);
8037c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(pshot_softstatep, instance);
8047c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
8077c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
8087c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resuming\n",
8097c478bd9Sstevel@tonic-gate 			    instance);
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 		/*
8147c478bd9Sstevel@tonic-gate 		 * set power level to max via pm_raise_power(),
8157c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
8167c478bd9Sstevel@tonic-gate 		 */
8177c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
8187c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
8197c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_RESUME:"
8207c478bd9Sstevel@tonic-gate 				    " raise power to MAXPWR\n", instance);
8217c478bd9Sstevel@tonic-gate 			}
8227c478bd9Sstevel@tonic-gate 			if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
8237c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
8247c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_RESUME:"
8257c478bd9Sstevel@tonic-gate 				    " pm_raise_power failed",
8267c478bd9Sstevel@tonic-gate 				    ddi_get_name(devi),
8277c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
8287c478bd9Sstevel@tonic-gate 			}
8297c478bd9Sstevel@tonic-gate 		}
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
8327c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resumed\n",
8337c478bd9Sstevel@tonic-gate 			    instance);
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate 	default:
8387c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate static int
pshot_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)8437c478bd9Sstevel@tonic-gate pshot_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(devi);
8467c478bd9Sstevel@tonic-gate 	int i, rval;
8477c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
8487c478bd9Sstevel@tonic-gate 	int level_tmp;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	if (pshot == NULL)
8517c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	switch (cmd) {
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
8567c478bd9Sstevel@tonic-gate 		if (pshot_debug)
8577c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_DETACH\n", instance);
8587c478bd9Sstevel@tonic-gate 		/*
8597c478bd9Sstevel@tonic-gate 		 * power off component 0
8607c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
8617c478bd9Sstevel@tonic-gate 		 */
8627c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
8637c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
8647c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_DETACH:"
8657c478bd9Sstevel@tonic-gate 				    " power off\n", instance);
8667c478bd9Sstevel@tonic-gate 			}
8677c478bd9Sstevel@tonic-gate 			if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
8687c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t"
8697c478bd9Sstevel@tonic-gate 				    "pm_lower_power failed for comp 0 to"
8707c478bd9Sstevel@tonic-gate 				    " level 0", ddi_get_name(devi),
8717c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8747c478bd9Sstevel@tonic-gate 			}
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 			/*
8777c478bd9Sstevel@tonic-gate 			 * Check if the power level is actually OFF.
8787c478bd9Sstevel@tonic-gate 			 * Issue pm_power_has_changed if not.
8797c478bd9Sstevel@tonic-gate 			 */
8807c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
8817c478bd9Sstevel@tonic-gate 			if (pshot->level != 0) {
8827c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
8837c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE, "pshot%d:"
8847c478bd9Sstevel@tonic-gate 					    " DDI_DETACH: power off via"
8857c478bd9Sstevel@tonic-gate 					    " pm_power_has_changed instead\n",
8867c478bd9Sstevel@tonic-gate 					    instance);
8877c478bd9Sstevel@tonic-gate 				}
8887c478bd9Sstevel@tonic-gate 				level_tmp = pshot->level;
8897c478bd9Sstevel@tonic-gate 				pshot->level = 0;
8907c478bd9Sstevel@tonic-gate 				if (pm_power_has_changed(pshot->dip, 0, 0) !=
8917c478bd9Sstevel@tonic-gate 				    DDI_SUCCESS) {
8927c478bd9Sstevel@tonic-gate 					if (pshot_debug) {
8937c478bd9Sstevel@tonic-gate 						cmn_err(CE_NOTE, "pshot%d:"
8947c478bd9Sstevel@tonic-gate 						    " DDI_DETACH:"
8957c478bd9Sstevel@tonic-gate 						    " pm_power_has_changed"
8967c478bd9Sstevel@tonic-gate 						    " failed\n", instance);
8977c478bd9Sstevel@tonic-gate 					}
8987c478bd9Sstevel@tonic-gate 					pshot->level = level_tmp;
8997c478bd9Sstevel@tonic-gate 					mutex_exit(&pshot->lock);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
9027c478bd9Sstevel@tonic-gate 				}
9037c478bd9Sstevel@tonic-gate 			}
9047c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
9057c478bd9Sstevel@tonic-gate 		}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
9087c478bd9Sstevel@tonic-gate 			if (pshot->callback_cache[i] != NULL) {
9097c478bd9Sstevel@tonic-gate 				rval = ddi_remove_event_handler(
9107c478bd9Sstevel@tonic-gate 				    pshot->callback_cache[i]);
9117c478bd9Sstevel@tonic-gate 				ASSERT(rval == DDI_SUCCESS);
9127c478bd9Sstevel@tonic-gate 			}
9137c478bd9Sstevel@tonic-gate 		}
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate #ifdef DEBUG
9167c478bd9Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) {
9177c478bd9Sstevel@tonic-gate 			if (pshot->test_callback_cache[i] != NULL) {
9187c478bd9Sstevel@tonic-gate 				rval = ddi_remove_event_handler(
9197c478bd9Sstevel@tonic-gate 				    pshot->test_callback_cache[i]);
9207c478bd9Sstevel@tonic-gate 				ASSERT(rval == DDI_SUCCESS);
9217c478bd9Sstevel@tonic-gate 			}
9227c478bd9Sstevel@tonic-gate 		}
9237c478bd9Sstevel@tonic-gate #endif
9247c478bd9Sstevel@tonic-gate 		rval = ndi_event_free_hdl(pshot->ndi_event_hdl);
9257c478bd9Sstevel@tonic-gate 		ASSERT(rval == DDI_SUCCESS);
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 		if (pshot_log)
9287c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d detached\n", instance);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
9317c478bd9Sstevel@tonic-gate 		mutex_destroy(&pshot->lock);
9327c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(pshot_softstatep, instance);
9337c478bd9Sstevel@tonic-gate 		break;
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
9367c478bd9Sstevel@tonic-gate 		if (pshot_debug)
9377c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND\n", instance);
9387c478bd9Sstevel@tonic-gate 		/*
9397c478bd9Sstevel@tonic-gate 		 * fail the suspend if FAIL_SUSPEND_FLAG is set.
9407c478bd9Sstevel@tonic-gate 		 * clear the FAIL_SUSPEND_FLAG flag
9417c478bd9Sstevel@tonic-gate 		 */
9427c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
9437c478bd9Sstevel@tonic-gate 		if (pshot->state & FAIL_SUSPEND_FLAG) {
9447c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
9457c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
94619397407SSherry Moore 				    " FAIL_SUSPEND_FLAG set, fail suspend\n",
94719397407SSherry Moore 				    ddi_get_instance(devi));
9487c478bd9Sstevel@tonic-gate 			}
9497c478bd9Sstevel@tonic-gate 			pshot->state &= ~FAIL_SUSPEND_FLAG;
9507c478bd9Sstevel@tonic-gate 			rval = DDI_FAILURE;
9517c478bd9Sstevel@tonic-gate 		} else {
9527c478bd9Sstevel@tonic-gate 			rval = DDI_SUCCESS;
9537c478bd9Sstevel@tonic-gate 		}
9547c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 		/*
9577c478bd9Sstevel@tonic-gate 		 * power OFF via pm_power_has_changed
9587c478bd9Sstevel@tonic-gate 		 */
9597c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
9607c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
9617c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
9627c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND:"
9637c478bd9Sstevel@tonic-gate 				    " power off via pm_power_has_changed\n",
9647c478bd9Sstevel@tonic-gate 				    instance);
9657c478bd9Sstevel@tonic-gate 			}
9667c478bd9Sstevel@tonic-gate 			level_tmp = pshot->level;
9677c478bd9Sstevel@tonic-gate 			pshot->level = 0;
9687c478bd9Sstevel@tonic-gate 			if (pm_power_has_changed(pshot->dip, 0, 0) !=
9697c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
9707c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
9717c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE, "pshot%d:"
9727c478bd9Sstevel@tonic-gate 					    " DDI_SUSPEND:"
9737c478bd9Sstevel@tonic-gate 					    " pm_power_has_changed failed\n",
9747c478bd9Sstevel@tonic-gate 					    instance);
9757c478bd9Sstevel@tonic-gate 				}
9767c478bd9Sstevel@tonic-gate 				pshot->level = level_tmp;
9777c478bd9Sstevel@tonic-gate 				rval = DDI_FAILURE;
9787c478bd9Sstevel@tonic-gate 			}
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
9817c478bd9Sstevel@tonic-gate 		return (rval);
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	default:
9847c478bd9Sstevel@tonic-gate 		break;
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate /*
9927c478bd9Sstevel@tonic-gate  * returns number of bits to represent <val>
9937c478bd9Sstevel@tonic-gate  */
9947c478bd9Sstevel@tonic-gate static size_t
pshot_numbits(size_t val)9957c478bd9Sstevel@tonic-gate pshot_numbits(size_t val)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate 	size_t bitcnt;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	if (val == 0)
10007c478bd9Sstevel@tonic-gate 		return (0);
10017c478bd9Sstevel@tonic-gate 	for (bitcnt = 1; 1 << bitcnt < val; bitcnt++)
10027c478bd9Sstevel@tonic-gate 		;
10037c478bd9Sstevel@tonic-gate 	return (bitcnt);
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate  * returns a minor number encoded with instance <inst> and an index <nodenum>
10087c478bd9Sstevel@tonic-gate  * that identifies the minor node for this instance
10097c478bd9Sstevel@tonic-gate  */
10107c478bd9Sstevel@tonic-gate static minor_t
pshot_minor_encode(int inst,minor_t nodenum)10117c478bd9Sstevel@tonic-gate pshot_minor_encode(int inst, minor_t nodenum)
10127c478bd9Sstevel@tonic-gate {
10137c478bd9Sstevel@tonic-gate 	return (((minor_t)inst << PSHOT_NODENUM_BITS()) |
10147c478bd9Sstevel@tonic-gate 	    (((1 << PSHOT_NODENUM_BITS()) - 1) & nodenum));
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate /*
10187c478bd9Sstevel@tonic-gate  * returns instance of <minor>
10197c478bd9Sstevel@tonic-gate  */
10207c478bd9Sstevel@tonic-gate static int
pshot_minor_decode_inst(minor_t minor)10217c478bd9Sstevel@tonic-gate pshot_minor_decode_inst(minor_t minor)
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate 	return (minor >> PSHOT_NODENUM_BITS());
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate /*
10277c478bd9Sstevel@tonic-gate  * returns node number indexing a minor node for the instance in <minor>
10287c478bd9Sstevel@tonic-gate  */
10297c478bd9Sstevel@tonic-gate static minor_t
pshot_minor_decode_nodenum(minor_t minor)10307c478bd9Sstevel@tonic-gate pshot_minor_decode_nodenum(minor_t minor)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate 	return (minor & ((1 << PSHOT_NODENUM_BITS()) - 1));
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate  * pshot_bus_introp: pshot convert an interrupt number to an
10387c478bd9Sstevel@tonic-gate  *			   interrupt. NO OP for pseudo drivers.
10397c478bd9Sstevel@tonic-gate  */
10407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10417c478bd9Sstevel@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)10427c478bd9Sstevel@tonic-gate pshot_bus_introp(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
10437c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate static int
pshot_ctl(dev_info_t * dip,dev_info_t * rdip,ddi_ctl_enum_t ctlop,void * arg,void * result)10487c478bd9Sstevel@tonic-gate pshot_ctl(dev_info_t *dip, dev_info_t *rdip,
10497c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t ctlop, void *arg, void *result)
10507c478bd9Sstevel@tonic-gate {
10517c478bd9Sstevel@tonic-gate 	int instance;
10527c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
10537c478bd9Sstevel@tonic-gate 	char *childname;
10547c478bd9Sstevel@tonic-gate 	int childinstance;
10557c478bd9Sstevel@tonic-gate 	char *name;
10567c478bd9Sstevel@tonic-gate 	struct attachspec *as;
10577c478bd9Sstevel@tonic-gate 	struct detachspec *ds;
10587c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
10597c478bd9Sstevel@tonic-gate 	int no_pm_components_child;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	name = ddi_get_name(dip);
10627c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
10637c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
10647c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
10657c478bd9Sstevel@tonic-gate 		return (ENXIO);
10667c478bd9Sstevel@tonic-gate 	}
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	switch (ctlop) {
10697c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
10707c478bd9Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
10717c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
10727c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?pshot-device: %s%d\n",
10737c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
10747c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
10777c478bd9Sstevel@tonic-gate 	{
10787c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
10817c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "initchild %s%d/%s%d state 0x%x\n",
10827c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), ddi_get_instance(dip),
10837c478bd9Sstevel@tonic-gate 			    ddi_node_name(child), ddi_get_instance(child),
10847c478bd9Sstevel@tonic-gate 			    DEVI(child)->devi_state);
10857c478bd9Sstevel@tonic-gate 		}
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 		return (pshot_initchild(dip, child));
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
10917c478bd9Sstevel@tonic-gate 	{
10927c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
10957c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "uninitchild %s%d/%s%d state 0x%x\n",
10967c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), ddi_get_instance(dip),
10977c478bd9Sstevel@tonic-gate 			    ddi_node_name(child), ddi_get_instance(child),
10987c478bd9Sstevel@tonic-gate 			    DEVI(child)->devi_state);
10997c478bd9Sstevel@tonic-gate 		}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 		return (pshot_uninitchild(dip, child));
11027c478bd9Sstevel@tonic-gate 	}
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
11057c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
11067c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
11077c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
11087c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
11097c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
11107c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
11117c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
11127c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
11137c478bd9Sstevel@tonic-gate 		/*
11147c478bd9Sstevel@tonic-gate 		 * These ops correspond to functions that "shouldn't" be called
11157c478bd9Sstevel@tonic-gate 		 * by a pseudo driver.  So we whine when we're called.
11167c478bd9Sstevel@tonic-gate 		 */
11177c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
111819397407SSherry Moore 		    ddi_get_name(dip), ddi_get_instance(dip),
111919397407SSherry Moore 		    ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
11207c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_ATTACH:
11237c478bd9Sstevel@tonic-gate 	{
11247c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)rdip;
11257c478bd9Sstevel@tonic-gate 		childname = ddi_node_name(child);
11267c478bd9Sstevel@tonic-gate 		childinstance = ddi_get_instance(child);
11277c478bd9Sstevel@tonic-gate 		as = (struct attachspec *)arg;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 		no_pm_components_child = 0;
11307c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
11317c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
11327c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 1) {
11337c478bd9Sstevel@tonic-gate 			no_pm_components_child = 1;
11347c478bd9Sstevel@tonic-gate 		}
11357c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
11367c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n",
11377c478bd9Sstevel@tonic-gate 			    name, instance, childname, childinstance,
11387c478bd9Sstevel@tonic-gate 			    no_pm_components_child);
11397c478bd9Sstevel@tonic-gate 		}
11407c478bd9Sstevel@tonic-gate 
11413fe80ca4SDan Cross 		ndi_devi_enter(dip);
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 		switch (as->when) {
11447c478bd9Sstevel@tonic-gate 		case DDI_PRE:
11457c478bd9Sstevel@tonic-gate 			/*
11467c478bd9Sstevel@tonic-gate 			 * Mark nexus busy before a child attaches.
11477c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
11487c478bd9Sstevel@tonic-gate 			 * - pshot@XXX,nopm_strict)
11497c478bd9Sstevel@tonic-gate 			 */
11507c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED))
11517c478bd9Sstevel@tonic-gate 				break;
11527c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
11537c478bd9Sstevel@tonic-gate 			++(pshot->busy);
11547c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
11557c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
11567c478bd9Sstevel@tonic-gate 				    " ctl_attach_pre: busy for %s%d:"
11577c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
11587c478bd9Sstevel@tonic-gate 				    childname, childinstance,
11597c478bd9Sstevel@tonic-gate 				    pshot->busy);
11607c478bd9Sstevel@tonic-gate 			}
11617c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
11627c478bd9Sstevel@tonic-gate 			rval = pm_busy_component(dip, 0);
11637c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
11647c478bd9Sstevel@tonic-gate 			break;
11657c478bd9Sstevel@tonic-gate 		case DDI_POST:
11667c478bd9Sstevel@tonic-gate 			/*
11677c478bd9Sstevel@tonic-gate 			 * Mark nexus idle after a child attaches.
11687c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
11697c478bd9Sstevel@tonic-gate 			 * - also skip if this is not a stict parent and
11707c478bd9Sstevel@tonic-gate 			 * - the child is a tape device or a no-pm-components
11717c478bd9Sstevel@tonic-gate 			 * - nexus node.
11727c478bd9Sstevel@tonic-gate 			 */
11737c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED) ||
11747c478bd9Sstevel@tonic-gate 			    (strcmp(childname, "tape") == 0 &&
11757c478bd9Sstevel@tonic-gate 			    !(pshot->state & STRICT_PARENT)) ||
11767c478bd9Sstevel@tonic-gate 			    no_pm_components_child)
11777c478bd9Sstevel@tonic-gate 				break;
11787c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
11797c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
11807c478bd9Sstevel@tonic-gate 			--pshot->busy;
11817c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
11827c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
11837c478bd9Sstevel@tonic-gate 				    " ctl_attach_post: idle for %s%d:"
11847c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
11857c478bd9Sstevel@tonic-gate 				    childname, childinstance,
11867c478bd9Sstevel@tonic-gate 				    pshot->busy);
11877c478bd9Sstevel@tonic-gate 			}
11887c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
11897c478bd9Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
11907c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
11917c478bd9Sstevel@tonic-gate 			break;
11927c478bd9Sstevel@tonic-gate 		}
11937c478bd9Sstevel@tonic-gate 
11943fe80ca4SDan Cross 		ndi_devi_exit(dip);
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 		return (rval);
11977c478bd9Sstevel@tonic-gate 	}
11987c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DETACH:
11997c478bd9Sstevel@tonic-gate 		{
12007c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)rdip;
12017c478bd9Sstevel@tonic-gate 		childname = ddi_node_name(child);
12027c478bd9Sstevel@tonic-gate 		childinstance = ddi_get_instance(child);
12037c478bd9Sstevel@tonic-gate 		ds = (struct detachspec *)arg;
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		no_pm_components_child = 0;
12067c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
12077c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
12087c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 1) {
12097c478bd9Sstevel@tonic-gate 			no_pm_components_child = 1;
12107c478bd9Sstevel@tonic-gate 		}
12117c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
12127c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
12137c478bd9Sstevel@tonic-gate 			    "%s%d: ctl_detach %s%d [%d]\n",
12147c478bd9Sstevel@tonic-gate 			    name, instance, childname, childinstance,
12157c478bd9Sstevel@tonic-gate 			    no_pm_components_child);
12167c478bd9Sstevel@tonic-gate 		}
12177c478bd9Sstevel@tonic-gate 
12183fe80ca4SDan Cross 		ndi_devi_enter(dip);
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 		switch (ds->when) {
12217c478bd9Sstevel@tonic-gate 		case DDI_PRE:
12227c478bd9Sstevel@tonic-gate 			/*
12237c478bd9Sstevel@tonic-gate 			 * Mark nexus busy before a child detaches.
12247c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
12257c478bd9Sstevel@tonic-gate 			 * - pshot@XXX,nopm_strict), or if the child is a
12267c478bd9Sstevel@tonic-gate 			 * - no-pm-components nexus node.
12277c478bd9Sstevel@tonic-gate 			 */
12287c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED) ||
12297c478bd9Sstevel@tonic-gate 			    (strcmp(childname, "tape") == 0 &&
12307c478bd9Sstevel@tonic-gate 			    !(pshot->state & STRICT_PARENT)) ||
12317c478bd9Sstevel@tonic-gate 			    no_pm_components_child)
12327c478bd9Sstevel@tonic-gate 				break;
12337c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
12347c478bd9Sstevel@tonic-gate 			++(pshot->busy);
12357c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
12367c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
12377c478bd9Sstevel@tonic-gate 				    " ctl_detach_pre: busy for %s%d:"
12387c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
12397c478bd9Sstevel@tonic-gate 				    childname, childinstance,
12407c478bd9Sstevel@tonic-gate 				    pshot->busy);
12417c478bd9Sstevel@tonic-gate 			}
12427c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
12437c478bd9Sstevel@tonic-gate 			rval = pm_busy_component(dip, 0);
12447c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 			break;
12477c478bd9Sstevel@tonic-gate 		case DDI_POST:
12487c478bd9Sstevel@tonic-gate 			/*
12497c478bd9Sstevel@tonic-gate 			 * Mark nexus idle after a child detaches.
12507c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
12517c478bd9Sstevel@tonic-gate 			 */
12527c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED))
12537c478bd9Sstevel@tonic-gate 				break;
12547c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
12557c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
12567c478bd9Sstevel@tonic-gate 			--pshot->busy;
12577c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
12587c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
12597c478bd9Sstevel@tonic-gate 				    " ctl_detach_post: idle for %s%d:"
12607c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
12617c478bd9Sstevel@tonic-gate 				    childname, childinstance,
12627c478bd9Sstevel@tonic-gate 				    pshot->busy);
12637c478bd9Sstevel@tonic-gate 			}
12647c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
12657c478bd9Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
12667c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 			/*
12697c478bd9Sstevel@tonic-gate 			 * Mark the driver idle if the NO_INVOL_FLAG
12707c478bd9Sstevel@tonic-gate 			 * is set. This is needed to make sure the
12717c478bd9Sstevel@tonic-gate 			 * parent is idle after the child detaches
12727c478bd9Sstevel@tonic-gate 			 * without calling pm_lower_power().
12737c478bd9Sstevel@tonic-gate 			 * Clear the NO_INVOL_FLAG.
12747c478bd9Sstevel@tonic-gate 			 * - also mark idle if a tape device has detached
12757c478bd9Sstevel@tonic-gate 			 */
12767c478bd9Sstevel@tonic-gate 			if (!(pshot->state & NO_INVOL_FLAG))
12777c478bd9Sstevel@tonic-gate 				break;
12787c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
12797c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
12807c478bd9Sstevel@tonic-gate 			--pshot->busy;
12817c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
12827c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
12837c478bd9Sstevel@tonic-gate 				    " ctl_detach_post: NO_INVOL:"
12847c478bd9Sstevel@tonic-gate 				    " idle for %s%d: busy = %d\n",
12857c478bd9Sstevel@tonic-gate 				    name, instance, childname,
12867c478bd9Sstevel@tonic-gate 				    childinstance, pshot->busy);
12877c478bd9Sstevel@tonic-gate 			}
12887c478bd9Sstevel@tonic-gate 			pshot->state &= ~NO_INVOL_FLAG;
12897c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
12907c478bd9Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
12917c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 			break;
12947c478bd9Sstevel@tonic-gate 		}
12957c478bd9Sstevel@tonic-gate 
12963fe80ca4SDan Cross 		ndi_devi_exit(dip);
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 		return (rval);
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 
13015e3986cbScth 	case DDI_CTLOPS_BTOP:
13025e3986cbScth 	case DDI_CTLOPS_BTOPR:
13037c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DVMAPAGESIZE:
13047c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
13057c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PTOB:
13067c478bd9Sstevel@tonic-gate 	default:
13077c478bd9Sstevel@tonic-gate 		/*
13087c478bd9Sstevel@tonic-gate 		 * The ops that we pass up (default).  We pass up memory
13097c478bd9Sstevel@tonic-gate 		 * allocation oriented ops that we receive - these may be
13107c478bd9Sstevel@tonic-gate 		 * associated with pseudo HBA drivers below us with target
13117c478bd9Sstevel@tonic-gate 		 * drivers below them that use ddi memory allocation
13127c478bd9Sstevel@tonic-gate 		 * interfaces like scsi_alloc_consistent_buf.
13137c478bd9Sstevel@tonic-gate 		 */
13147c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
13197c478bd9Sstevel@tonic-gate static int
pshot_power(dev_info_t * dip,int cmpt,int level)13207c478bd9Sstevel@tonic-gate pshot_power(dev_info_t *dip, int cmpt, int level)
13217c478bd9Sstevel@tonic-gate {
13227c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
13237c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
13247c478bd9Sstevel@tonic-gate 	char *name = ddi_node_name(dip);
13257c478bd9Sstevel@tonic-gate 	int rv;
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
13287c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13317c478bd9Sstevel@tonic-gate 	}
13327c478bd9Sstevel@tonic-gate 
13333fe80ca4SDan Cross 	ndi_devi_enter(dip);
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	/*
13367c478bd9Sstevel@tonic-gate 	 * set POWER_FLAG when power() is called.
13377c478bd9Sstevel@tonic-gate 	 * ioctl(DEVCT_PM_POWER) is a clear on read call.
13387c478bd9Sstevel@tonic-gate 	 */
13397c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
13407c478bd9Sstevel@tonic-gate 	pshot->state |= POWER_FLAG;
13417c478bd9Sstevel@tonic-gate 	/*
13427c478bd9Sstevel@tonic-gate 	 * refuse to power OFF if the component is busy
13437c478bd9Sstevel@tonic-gate 	 */
13447c478bd9Sstevel@tonic-gate 	if (pshot->busy != 0 && pshot->level > level) {
13457c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE"
13467c478bd9Sstevel@tonic-gate 		    " (%d->%d), DEVICE NOT IDLE: busy = %d",
13477c478bd9Sstevel@tonic-gate 		    name, instance, pshot->level, level, pshot->busy);
13487c478bd9Sstevel@tonic-gate 		rv = DDI_FAILURE;
13497c478bd9Sstevel@tonic-gate 	} else {
13507c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
13517c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n",
13527c478bd9Sstevel@tonic-gate 			    name, instance, cmpt, pshot->level, level);
13537c478bd9Sstevel@tonic-gate 		}
13547c478bd9Sstevel@tonic-gate 		pshot->level = level;
13557c478bd9Sstevel@tonic-gate 		rv = DDI_SUCCESS;
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
13587c478bd9Sstevel@tonic-gate 
13593fe80ca4SDan Cross 	ndi_devi_exit(dip);
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	return (rv);
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
13657c478bd9Sstevel@tonic-gate static int
pshot_bus_power(dev_info_t * dip,void * impl_arg,pm_bus_power_op_t op,void * arg,void * result)13667c478bd9Sstevel@tonic-gate pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
13677c478bd9Sstevel@tonic-gate     void *arg, void *result)
13687c478bd9Sstevel@tonic-gate {
1369*d5ebc493SDan Cross 	int				ret;
1370*d5ebc493SDan Cross 	int				instance = ddi_get_instance(dip);
13717c478bd9Sstevel@tonic-gate 	char				*name = ddi_node_name(dip);
1372*d5ebc493SDan Cross 	pshot_t				*pshot;
13737c478bd9Sstevel@tonic-gate 	pm_bp_child_pwrchg_t		*bpc;
13747c478bd9Sstevel@tonic-gate 	pm_bp_nexus_pwrup_t		bpn;
13757c478bd9Sstevel@tonic-gate 	pm_bp_has_changed_t		*bphc;
13767c478bd9Sstevel@tonic-gate 	int				pwrup_res;
13777c478bd9Sstevel@tonic-gate 	int				ret_failed = 0;
13787c478bd9Sstevel@tonic-gate 	int				pwrup_res_failed = 0;
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
13817c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	switch (op) {
13877c478bd9Sstevel@tonic-gate 	case BUS_POWER_PRE_NOTIFICATION:
13887c478bd9Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
13897c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
13907c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: pre_bus_power:"
13917c478bd9Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d)\n",
13927c478bd9Sstevel@tonic-gate 			    name, instance, ddi_node_name(bpc->bpc_dip),
13937c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
13947c478bd9Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_olevel,
13957c478bd9Sstevel@tonic-gate 			    bpc->bpc_nlevel);
13967c478bd9Sstevel@tonic-gate 		}
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 		/*
13997c478bd9Sstevel@tonic-gate 		 * mark parent busy if old_level is either -1 or 0,
14007c478bd9Sstevel@tonic-gate 		 * and new level is == MAXPWR
14017c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
14027c478bd9Sstevel@tonic-gate 		 */
14037c478bd9Sstevel@tonic-gate 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
14047c478bd9Sstevel@tonic-gate 		    bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) {
14057c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
14067c478bd9Sstevel@tonic-gate 			++(pshot->busy);
14077c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
14087c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
14097c478bd9Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
14107c478bd9Sstevel@tonic-gate 				    " busy parent for %s%d (%d->%d): "
14117c478bd9Sstevel@tonic-gate 				    " busy = %d\n",
14127c478bd9Sstevel@tonic-gate 				    name, instance,
14137c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14147c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14157c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel,
14167c478bd9Sstevel@tonic-gate 				    pshot->busy);
14177c478bd9Sstevel@tonic-gate 			}
14187c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
14197c478bd9Sstevel@tonic-gate 			ret = pm_busy_component(dip, 0);
14207c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
14217c478bd9Sstevel@tonic-gate 		}
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 		/*
14247c478bd9Sstevel@tonic-gate 		 * if new_level > 0, power up parent, if not already at
14257c478bd9Sstevel@tonic-gate 		 * MAXPWR, via pm_busop_bus_power
14267c478bd9Sstevel@tonic-gate 		 * - skip for the no-pm nexus (pshot@XXX,nopm)
14277c478bd9Sstevel@tonic-gate 		 */
14287c478bd9Sstevel@tonic-gate 		if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 &&
14297c478bd9Sstevel@tonic-gate 		    pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) {
14307c478bd9Sstevel@tonic-gate 			/*
14317c478bd9Sstevel@tonic-gate 			 * stuff the bpn struct
14327c478bd9Sstevel@tonic-gate 			 */
14337c478bd9Sstevel@tonic-gate 			bpn.bpn_comp = 0;
14347c478bd9Sstevel@tonic-gate 			bpn.bpn_level = MAXPWR;
14357c478bd9Sstevel@tonic-gate 			bpn.bpn_private = bpc->bpc_private;
14367c478bd9Sstevel@tonic-gate 			bpn.bpn_dip = dip;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 			/*
14397c478bd9Sstevel@tonic-gate 			 * ask pm to power parent up
14407c478bd9Sstevel@tonic-gate 			 */
14417c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
14427c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d: pre_bus_power:"
14437c478bd9Sstevel@tonic-gate 				    " pm_busop_bus_power on parent for %s%d"
14447c478bd9Sstevel@tonic-gate 				    " (%d->%d): enter", name, instance,
14457c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14467c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14477c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
14487c478bd9Sstevel@tonic-gate 			}
14497c478bd9Sstevel@tonic-gate 			ret = pm_busop_bus_power(dip, impl_arg,
14507c478bd9Sstevel@tonic-gate 			    BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
14517c478bd9Sstevel@tonic-gate 			    (void *)&pwrup_res);
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 			/*
14547c478bd9Sstevel@tonic-gate 			 * check the return status individually,
14557c478bd9Sstevel@tonic-gate 			 * idle parent and exit if either failed.
14567c478bd9Sstevel@tonic-gate 			 */
14577c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
14587c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
14597c478bd9Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
14607c478bd9Sstevel@tonic-gate 				    " pm_busop_bus_power FAILED (ret) FOR"
14617c478bd9Sstevel@tonic-gate 				    " %s%d (%d->%d)",
14627c478bd9Sstevel@tonic-gate 				    name, instance,
14637c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14647c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14657c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
14667c478bd9Sstevel@tonic-gate 				ret_failed = 1;
14677c478bd9Sstevel@tonic-gate 			}
14687c478bd9Sstevel@tonic-gate 			if (pwrup_res != DDI_SUCCESS) {
14697c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
14707c478bd9Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
14717c478bd9Sstevel@tonic-gate 				    " pm_busop_bus_power FAILED (pwrup_res)"
14727c478bd9Sstevel@tonic-gate 				    " FOR %s%d (%d->%d)",
14737c478bd9Sstevel@tonic-gate 				    name, instance,
14747c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
14757c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
14767c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
14777c478bd9Sstevel@tonic-gate 				pwrup_res_failed = 1;
14787c478bd9Sstevel@tonic-gate 			}
14797c478bd9Sstevel@tonic-gate 			if (ret_failed || pwrup_res_failed) {
14807c478bd9Sstevel@tonic-gate 				/*
14817c478bd9Sstevel@tonic-gate 				 * decrement the busy count if it
14827c478bd9Sstevel@tonic-gate 				 * had been incremented.
14837c478bd9Sstevel@tonic-gate 				 */
14847c478bd9Sstevel@tonic-gate 				if ((bpc->bpc_comp == 0 &&
14857c478bd9Sstevel@tonic-gate 				    bpc->bpc_nlevel == MAXPWR &&
14867c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel <= 0) &&
14877c478bd9Sstevel@tonic-gate 				    (pshot->state & PM_SUPPORTED)) {
14887c478bd9Sstevel@tonic-gate 					mutex_enter(&pshot->lock);
14897c478bd9Sstevel@tonic-gate 					ASSERT(pshot->busy > 0);
14907c478bd9Sstevel@tonic-gate 					--(pshot->busy);
14917c478bd9Sstevel@tonic-gate 					if (pshot_debug_busy) {
14927c478bd9Sstevel@tonic-gate 						cmn_err(CE_CONT, "%s%d:"
14937c478bd9Sstevel@tonic-gate 						    " pm_busop_bus_power"
14947c478bd9Sstevel@tonic-gate 						    " failed: idle parent for"
14957c478bd9Sstevel@tonic-gate 						    " %s%d (%d->%d):"
14967c478bd9Sstevel@tonic-gate 						    " busy = %d\n",
14977c478bd9Sstevel@tonic-gate 						    name, instance,
14987c478bd9Sstevel@tonic-gate 						    ddi_node_name(
14997c478bd9Sstevel@tonic-gate 						    bpc->bpc_dip),
15007c478bd9Sstevel@tonic-gate 						    ddi_get_instance(
15017c478bd9Sstevel@tonic-gate 						    bpc->bpc_dip),
15027c478bd9Sstevel@tonic-gate 						    bpc->bpc_olevel,
15037c478bd9Sstevel@tonic-gate 						    bpc->bpc_nlevel,
15047c478bd9Sstevel@tonic-gate 						    pshot->busy);
15057c478bd9Sstevel@tonic-gate 					}
15067c478bd9Sstevel@tonic-gate 					mutex_exit(&pshot->lock);
15077c478bd9Sstevel@tonic-gate 					ret = pm_idle_component(dip, 0);
15087c478bd9Sstevel@tonic-gate 					ASSERT(ret == DDI_SUCCESS);
15097c478bd9Sstevel@tonic-gate 				}
15107c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 			} else {
15137c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
15147c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT,
15157c478bd9Sstevel@tonic-gate 					    "%s%d: pre_bus_power:"
15167c478bd9Sstevel@tonic-gate 					    " pm_busop_bus_power on parent"
15177c478bd9Sstevel@tonic-gate 					    " for %s%d (%d->%d)\n",
15187c478bd9Sstevel@tonic-gate 					    name, instance,
15197c478bd9Sstevel@tonic-gate 					    ddi_node_name(bpc->bpc_dip),
15207c478bd9Sstevel@tonic-gate 					    ddi_get_instance(bpc->bpc_dip),
15217c478bd9Sstevel@tonic-gate 					    bpc->bpc_olevel, bpc->bpc_nlevel);
15227c478bd9Sstevel@tonic-gate 				}
15237c478bd9Sstevel@tonic-gate 			}
15247c478bd9Sstevel@tonic-gate 		}
15257c478bd9Sstevel@tonic-gate 		break;
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	case BUS_POWER_POST_NOTIFICATION:
15287c478bd9Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
15297c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
15307c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: post_bus_power:"
15317c478bd9Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d) result %d\n",
15327c478bd9Sstevel@tonic-gate 			    name, instance, ddi_node_name(bpc->bpc_dip),
15337c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
15347c478bd9Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_olevel,
15357c478bd9Sstevel@tonic-gate 			    bpc->bpc_nlevel, *(int *)result);
15367c478bd9Sstevel@tonic-gate 		}
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 		/*
15397c478bd9Sstevel@tonic-gate 		 * handle pm_busop_bus_power() failure case.
15407c478bd9Sstevel@tonic-gate 		 * mark parent idle if had been marked busy.
15417c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
15427c478bd9Sstevel@tonic-gate 		 */
15437c478bd9Sstevel@tonic-gate 		if (*(int *)result != DDI_SUCCESS) {
15447c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
15457c478bd9Sstevel@tonic-gate 			    "pshot%d: post_bus_power_failed:"
15467c478bd9Sstevel@tonic-gate 			    " pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
15477c478bd9Sstevel@tonic-gate 			    instance, ddi_node_name(bpc->bpc_dip),
15487c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
15497c478bd9Sstevel@tonic-gate 			    bpc->bpc_olevel, bpc->bpc_nlevel);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 			if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
15527c478bd9Sstevel@tonic-gate 			    bpc->bpc_olevel <= 0) &&
15537c478bd9Sstevel@tonic-gate 			    (pshot->state & PM_SUPPORTED)) {
15547c478bd9Sstevel@tonic-gate 				mutex_enter(&pshot->lock);
15557c478bd9Sstevel@tonic-gate 				ASSERT(pshot->busy > 0);
15567c478bd9Sstevel@tonic-gate 				--(pshot->busy);
15577c478bd9Sstevel@tonic-gate 				if (pshot_debug_busy) {
15587c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "%s%d:"
15597c478bd9Sstevel@tonic-gate 					    " post_bus_power_failed:"
15607c478bd9Sstevel@tonic-gate 					    " idle parent for %s%d"
15617c478bd9Sstevel@tonic-gate 					    " (%d->%d): busy = %d\n",
15627c478bd9Sstevel@tonic-gate 					    name, instance,
15637c478bd9Sstevel@tonic-gate 					    ddi_node_name(bpc->bpc_dip),
15647c478bd9Sstevel@tonic-gate 					    ddi_get_instance(bpc->bpc_dip),
15657c478bd9Sstevel@tonic-gate 					    bpc->bpc_olevel, bpc->bpc_nlevel,
15667c478bd9Sstevel@tonic-gate 					    pshot->busy);
15677c478bd9Sstevel@tonic-gate 				}
15687c478bd9Sstevel@tonic-gate 				mutex_exit(&pshot->lock);
15697c478bd9Sstevel@tonic-gate 				ret = pm_idle_component(dip, 0);
15707c478bd9Sstevel@tonic-gate 				ASSERT(ret == DDI_SUCCESS);
15717c478bd9Sstevel@tonic-gate 			}
15727c478bd9Sstevel@tonic-gate 		}
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 		/*
15757c478bd9Sstevel@tonic-gate 		 * Mark nexus idle when a child's comp 0
15767c478bd9Sstevel@tonic-gate 		 * is set to level 0 from level 1, 2, or 3 only.
15777c478bd9Sstevel@tonic-gate 		 * And only if result arg == DDI_SUCCESS.
15787c478bd9Sstevel@tonic-gate 		 * This will leave the parent busy when the child
15797c478bd9Sstevel@tonic-gate 		 * does not call pm_lower_power() on detach after
15807c478bd9Sstevel@tonic-gate 		 * unsetting the NO_LOWER_POWER flag.
15817c478bd9Sstevel@tonic-gate 		 * If so, need to notify the parent to mark itself
15827c478bd9Sstevel@tonic-gate 		 * idle anyway, else the no-involumtary-power-cycles
15837c478bd9Sstevel@tonic-gate 		 * test cases will report false passes!
15847c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
15857c478bd9Sstevel@tonic-gate 		 */
15867c478bd9Sstevel@tonic-gate 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 &&
15877c478bd9Sstevel@tonic-gate 		    !(bpc->bpc_olevel <= 0) &&
15887c478bd9Sstevel@tonic-gate 		    *(int *)result == DDI_SUCCESS) &&
15897c478bd9Sstevel@tonic-gate 		    (pshot->state & PM_SUPPORTED)) {
15907c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
15917c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
15927c478bd9Sstevel@tonic-gate 			--(pshot->busy);
15937c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
15947c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
15957c478bd9Sstevel@tonic-gate 				    "%s%d: post_bus_power:"
15967c478bd9Sstevel@tonic-gate 				    " idle parent for %s%d (%d->%d):"
15977c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
15987c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
15997c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
16007c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel,
16017c478bd9Sstevel@tonic-gate 				    pshot->busy);
16027c478bd9Sstevel@tonic-gate 			}
16037c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
16047c478bd9Sstevel@tonic-gate 			ret = pm_idle_component(dip, 0);
16057c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
16067c478bd9Sstevel@tonic-gate 		}
16077c478bd9Sstevel@tonic-gate 		break;
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	case BUS_POWER_HAS_CHANGED:
16107c478bd9Sstevel@tonic-gate 		bphc = (pm_bp_has_changed_t *)arg;
16117c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
16127c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: has_changed_bus_power:"
16137c478bd9Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d) result %d\n",
16147c478bd9Sstevel@tonic-gate 			    name, instance, ddi_node_name(bphc->bphc_dip),
16157c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bphc->bphc_dip),
16167c478bd9Sstevel@tonic-gate 			    bphc->bphc_comp, bphc->bphc_olevel,
16177c478bd9Sstevel@tonic-gate 			    bphc->bphc_nlevel, *(int *)result);
16187c478bd9Sstevel@tonic-gate 		}
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 		/*
16217c478bd9Sstevel@tonic-gate 		 * Mark nexus idle when a child's comp 0
16227c478bd9Sstevel@tonic-gate 		 * is set to level 0 from levels 1, 2, or 3 only.
16237c478bd9Sstevel@tonic-gate 		 *
16247c478bd9Sstevel@tonic-gate 		 * If powering up child leaf/nexus nodes via
16257c478bd9Sstevel@tonic-gate 		 * pm_power_has_changed() calls, first issue
16267c478bd9Sstevel@tonic-gate 		 * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
16277c478bd9Sstevel@tonic-gate 		 * before powering the parent up, then power up the
16287c478bd9Sstevel@tonic-gate 		 * child node.
16297c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
16307c478bd9Sstevel@tonic-gate 		 */
16317c478bd9Sstevel@tonic-gate 		if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 &&
16327c478bd9Sstevel@tonic-gate 		    !(bphc->bphc_olevel <= 0)) &&
16337c478bd9Sstevel@tonic-gate 		    pshot->state & PM_SUPPORTED) {
16347c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
16357c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
16367c478bd9Sstevel@tonic-gate 			--(pshot->busy);
16377c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
16387c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
16397c478bd9Sstevel@tonic-gate 				    "%s%d: has_changed_bus_power:"
16407c478bd9Sstevel@tonic-gate 				    " idle parent for %s%d (%d->%d):"
16417c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
16427c478bd9Sstevel@tonic-gate 				    ddi_node_name(bphc->bphc_dip),
16437c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bphc->bphc_dip),
16447c478bd9Sstevel@tonic-gate 				    bphc->bphc_olevel,
16457c478bd9Sstevel@tonic-gate 				    bphc->bphc_nlevel, pshot->busy);
16467c478bd9Sstevel@tonic-gate 			}
16477c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
16487c478bd9Sstevel@tonic-gate 			ret = pm_idle_component(dip, 0);
16497c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
16507c478bd9Sstevel@tonic-gate 		}
16517c478bd9Sstevel@tonic-gate 		break;
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	default:
16547c478bd9Sstevel@tonic-gate 		return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
16597c478bd9Sstevel@tonic-gate }
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate static int
pshot_initchild(dev_info_t * dip,dev_info_t * child)16627c478bd9Sstevel@tonic-gate pshot_initchild(dev_info_t *dip, dev_info_t *child)
16637c478bd9Sstevel@tonic-gate {
16647c478bd9Sstevel@tonic-gate 	char	name[64];
16657c478bd9Sstevel@tonic-gate 	char	*bus_addr;
16667c478bd9Sstevel@tonic-gate 	char	*c_nodename;
16677c478bd9Sstevel@tonic-gate 	int	bus_id;
16687c478bd9Sstevel@tonic-gate 	dev_info_t *enum_child;
16697c478bd9Sstevel@tonic-gate 	int	enum_base;
16707c478bd9Sstevel@tonic-gate 	int	enum_extent;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	/* check for bus_enum node */
16747c478bd9Sstevel@tonic-gate 
16757c478bd9Sstevel@tonic-gate #ifdef	NOT_USED
16767c478bd9Sstevel@tonic-gate 	if (impl_ddi_merge_child(child) != DDI_SUCCESS)
16777c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
16787c478bd9Sstevel@tonic-gate #endif
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
16817c478bd9Sstevel@tonic-gate 	    "busid_ebase", 0);
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate 	enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child,
16847c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "busid_range", 0);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	/*
16877c478bd9Sstevel@tonic-gate 	 * bus enumeration node
16887c478bd9Sstevel@tonic-gate 	 */
16897c478bd9Sstevel@tonic-gate 	if ((enum_base != 0) && (enum_extent != 0))	{
16907c478bd9Sstevel@tonic-gate 		c_nodename = ddi_node_name(child);
16917c478bd9Sstevel@tonic-gate 		bus_id = enum_base;
16927c478bd9Sstevel@tonic-gate 		for (; bus_id < enum_extent; bus_id++) {
16937c478bd9Sstevel@tonic-gate 			if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID,
16947c478bd9Sstevel@tonic-gate 			    &enum_child) != NDI_SUCCESS)
16957c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%d", bus_id);
16987c478bd9Sstevel@tonic-gate 			if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child,
16997c478bd9Sstevel@tonic-gate 			    "bus-addr", name) != DDI_PROP_SUCCESS) {
17007c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(enum_child);
17017c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
17027c478bd9Sstevel@tonic-gate 			}
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 			if (ndi_devi_online(enum_child, 0) !=
17057c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
17067c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(enum_child);
17077c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
17087c478bd9Sstevel@tonic-gate 			}
17097c478bd9Sstevel@tonic-gate 		}
17107c478bd9Sstevel@tonic-gate 		/*
17117c478bd9Sstevel@tonic-gate 		 * fail the enumeration node itself
17127c478bd9Sstevel@tonic-gate 		 */
17137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr",
17177c478bd9Sstevel@tonic-gate 	    &bus_addr) != DDI_PROP_SUCCESS) {
17187c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)",
17197c478bd9Sstevel@tonic-gate 		    ddi_node_name(child));
17207c478bd9Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	if (strlen(bus_addr) == 0) {
17247c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)",
17257c478bd9Sstevel@tonic-gate 		    ddi_node_name(child));
17267c478bd9Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
17277c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17287c478bd9Sstevel@tonic-gate 	}
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	if (strncmp(bus_addr, "failinit", 8) == 0) {
17317c478bd9Sstevel@tonic-gate 		if (pshot_debug)
17327c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
17337c478bd9Sstevel@tonic-gate 			    "pshot%d: %s forced INITCHILD failure\n",
173419397407SSherry Moore 			    ddi_get_instance(dip), bus_addr);
17357c478bd9Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
17367c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	if (pshot_log) {
17407c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "initchild %s%d/%s@%s\n",
174119397407SSherry Moore 		    ddi_get_name(dip), ddi_get_instance(dip),
174219397407SSherry Moore 		    ddi_node_name(child), bus_addr);
17437c478bd9Sstevel@tonic-gate 	}
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, bus_addr);
17467c478bd9Sstevel@tonic-gate 	ddi_prop_free(bus_addr);
17477c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17517c478bd9Sstevel@tonic-gate static int
pshot_uninitchild(dev_info_t * dip,dev_info_t * child)17527c478bd9Sstevel@tonic-gate pshot_uninitchild(dev_info_t *dip, dev_info_t *child)
17537c478bd9Sstevel@tonic-gate {
17547c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
17557c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate /*
17607c478bd9Sstevel@tonic-gate  * devctl IOCTL support
17617c478bd9Sstevel@tonic-gate  */
17627c478bd9Sstevel@tonic-gate /* ARGSUSED */
17637c478bd9Sstevel@tonic-gate static int
pshot_open(dev_t * devp,int flags,int otyp,cred_t * credp)17647c478bd9Sstevel@tonic-gate pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp)
17657c478bd9Sstevel@tonic-gate {
17667c478bd9Sstevel@tonic-gate 	int instance;
17677c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
17707c478bd9Sstevel@tonic-gate 		return (EINVAL);
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(*devp));
17737c478bd9Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
17747c478bd9Sstevel@tonic-gate 		return (ENXIO);
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	/*
17777c478bd9Sstevel@tonic-gate 	 * Access is currently determined on a per-instance basis.
17787c478bd9Sstevel@tonic-gate 	 * If we want per-node, then need to add state and lock members to
17797c478bd9Sstevel@tonic-gate 	 * pshot_minor_t
17807c478bd9Sstevel@tonic-gate 	 */
17817c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
17827c478bd9Sstevel@tonic-gate 	if (((flags & FEXCL) && (pshot->state & IS_OPEN)) ||
17837c478bd9Sstevel@tonic-gate 	    (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) {
17847c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
17857c478bd9Sstevel@tonic-gate 		return (EBUSY);
17867c478bd9Sstevel@tonic-gate 	}
17877c478bd9Sstevel@tonic-gate 	pshot->state |= IS_OPEN;
17887c478bd9Sstevel@tonic-gate 	if (flags & FEXCL)
17897c478bd9Sstevel@tonic-gate 		pshot->state |= IS_OPEN_EXCL;
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	if (pshot_debug)
17927c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d open\n", instance);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
17957c478bd9Sstevel@tonic-gate 	return (0);
17967c478bd9Sstevel@tonic-gate }
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate /*
17997c478bd9Sstevel@tonic-gate  * pshot_close
18007c478bd9Sstevel@tonic-gate  */
18017c478bd9Sstevel@tonic-gate /* ARGSUSED */
18027c478bd9Sstevel@tonic-gate static int
pshot_close(dev_t dev,int flag,int otyp,cred_t * credp)18037c478bd9Sstevel@tonic-gate pshot_close(dev_t dev, int flag, int otyp, cred_t *credp)
18047c478bd9Sstevel@tonic-gate {
18057c478bd9Sstevel@tonic-gate 	int instance;
18067c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
18097c478bd9Sstevel@tonic-gate 		return (EINVAL);
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(dev));
18127c478bd9Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
18137c478bd9Sstevel@tonic-gate 		return (ENXIO);
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
18167c478bd9Sstevel@tonic-gate 	pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL);
18177c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
18187c478bd9Sstevel@tonic-gate 	if (pshot_debug)
18197c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d closed\n", instance);
18207c478bd9Sstevel@tonic-gate 	return (0);
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate /*
18257c478bd9Sstevel@tonic-gate  * pshot_ioctl: redirects to appropriate command handler based on various
1826*d5ebc493SDan Cross  *	criteria
18277c478bd9Sstevel@tonic-gate  */
18287c478bd9Sstevel@tonic-gate /* ARGSUSED */
18297c478bd9Sstevel@tonic-gate static int
pshot_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)18307c478bd9Sstevel@tonic-gate pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
18317c478bd9Sstevel@tonic-gate     int *rvalp)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
18347c478bd9Sstevel@tonic-gate 	int instance;
18357c478bd9Sstevel@tonic-gate 	minor_t nodenum;
18367c478bd9Sstevel@tonic-gate 	char *nodename;
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(dev));
18397c478bd9Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
18407c478bd9Sstevel@tonic-gate 		return (ENXIO);
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	nodenum = pshot_minor_decode_nodenum(getminor(dev));
18437c478bd9Sstevel@tonic-gate 	nodename = pshot->nodes[nodenum].name;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	if (pshot_debug)
18467c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
18477c478bd9Sstevel@tonic-gate 		    "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
18487c478bd9Sstevel@tonic-gate 		    instance, (void *)dev, cmd, (void *)arg, mode);
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0)
18517c478bd9Sstevel@tonic-gate 		return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp,
18527c478bd9Sstevel@tonic-gate 		    rvalp));
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0)
18557c478bd9Sstevel@tonic-gate 		return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp,
18567c478bd9Sstevel@tonic-gate 		    rvalp));
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u",
18597c478bd9Sstevel@tonic-gate 	    pshot->nodes[nodenum].minor);
18607c478bd9Sstevel@tonic-gate 	return (ENXIO);
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate /*
18657c478bd9Sstevel@tonic-gate  * pshot_devctl: handle DEVCTL operations
18667c478bd9Sstevel@tonic-gate  */
18677c478bd9Sstevel@tonic-gate /* ARGSUSED */
18687c478bd9Sstevel@tonic-gate static int
pshot_devctl(pshot_t * pshot,minor_t nodenum,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)18697c478bd9Sstevel@tonic-gate pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
18707c478bd9Sstevel@tonic-gate     cred_t *credp, int *rvalp)
18717c478bd9Sstevel@tonic-gate {
18727c478bd9Sstevel@tonic-gate 	dev_info_t *self;
18737c478bd9Sstevel@tonic-gate 	dev_info_t *child = NULL;
18747c478bd9Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
18757c478bd9Sstevel@tonic-gate 	uint_t state;
18767c478bd9Sstevel@tonic-gate 	int rv = 0;
18777c478bd9Sstevel@tonic-gate 	uint_t flags;
18787c478bd9Sstevel@tonic-gate 	int instance;
18797c478bd9Sstevel@tonic-gate 	int i;
18807c478bd9Sstevel@tonic-gate 	int ret;
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	self = pshot->dip;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0;
18857c478bd9Sstevel@tonic-gate 	instance = pshot->instance;
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	/*
18887c478bd9Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
18897c478bd9Sstevel@tonic-gate 	 */
18907c478bd9Sstevel@tonic-gate 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
18917c478bd9Sstevel@tonic-gate 		if (pshot_devctls[i].ioctl_int == cmd) {
18927c478bd9Sstevel@tonic-gate 			if (pshot_debug)
18937c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d devctl: %s",
18947c478bd9Sstevel@tonic-gate 				    instance, pshot_devctls[i].ioctl_char);
18957c478bd9Sstevel@tonic-gate 		}
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 	switch (cmd) {
18987c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
18997c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
19007c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
19017c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_REMOVE:
19027c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
19037c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_DEV_CREATE:
19047c478bd9Sstevel@tonic-gate 		rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags);
19057c478bd9Sstevel@tonic-gate 		if (pshot_debug && rv != 0) {
19067c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:"
19077c478bd9Sstevel@tonic-gate 			    " failed, rv = %d", instance, rv);
19087c478bd9Sstevel@tonic-gate 		}
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 		return (rv);
19117c478bd9Sstevel@tonic-gate 	}
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 	/*
19147c478bd9Sstevel@tonic-gate 	 * read devctl ioctl data
19157c478bd9Sstevel@tonic-gate 	 */
19167c478bd9Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
19177c478bd9Sstevel@tonic-gate 		return (EFAULT);
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	switch (cmd) {
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
19227c478bd9Sstevel@tonic-gate 		if (pshot_debug)
19237c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19247c478bd9Sstevel@tonic-gate 			    " DEVCTL_DEVICE_RESET\n", instance);
19257c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
19267c478bd9Sstevel@tonic-gate 		    child, (void *)self);
19277c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19287c478bd9Sstevel@tonic-gate 		break;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
19317c478bd9Sstevel@tonic-gate 		if (pshot_debug)
19327c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19337c478bd9Sstevel@tonic-gate 			    " DEVCTL_BUS_QUIESCE\n", instance);
19347c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
19357c478bd9Sstevel@tonic-gate 			if (state == BUS_QUIESCED) {
19367c478bd9Sstevel@tonic-gate 				break;
19377c478bd9Sstevel@tonic-gate 			}
19387c478bd9Sstevel@tonic-gate 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
19397c478bd9Sstevel@tonic-gate 		}
19407c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
19417c478bd9Sstevel@tonic-gate 		    child, (void *)self);
19427c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 		break;
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
19477c478bd9Sstevel@tonic-gate 		if (pshot_debug)
19487c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19497c478bd9Sstevel@tonic-gate 			    " DEVCTL_BUS_UNQUIESCE\n", instance);
19507c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
19517c478bd9Sstevel@tonic-gate 			if (state == BUS_ACTIVE) {
19527c478bd9Sstevel@tonic-gate 				break;
19537c478bd9Sstevel@tonic-gate 			}
19547c478bd9Sstevel@tonic-gate 		}
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 		/*
19577c478bd9Sstevel@tonic-gate 		 * quiesce the bus through bus-specific means
19587c478bd9Sstevel@tonic-gate 		 */
19597c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
19607c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
19617c478bd9Sstevel@tonic-gate 		    child, (void *)self);
19627c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19637c478bd9Sstevel@tonic-gate 		break;
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
19667c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
19677c478bd9Sstevel@tonic-gate 		/*
19687c478bd9Sstevel@tonic-gate 		 * no reset support for the pseudo bus
19697c478bd9Sstevel@tonic-gate 		 * but if there were....
19707c478bd9Sstevel@tonic-gate 		 */
19717c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
197219397407SSherry Moore 		    child, (void *)self);
19737c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
19747c478bd9Sstevel@tonic-gate 		break;
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	/*
19777c478bd9Sstevel@tonic-gate 	 * PM related ioctls
19787c478bd9Sstevel@tonic-gate 	 */
19797c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUSY_COMP:
19807c478bd9Sstevel@tonic-gate 		/*
19817c478bd9Sstevel@tonic-gate 		 * mark component 0 busy.
19827c478bd9Sstevel@tonic-gate 		 * Keep track of ioctl updates to the busy count
19837c478bd9Sstevel@tonic-gate 		 * via pshot->busy_ioctl.
19847c478bd9Sstevel@tonic-gate 		 */
19857c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
19867c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
19877c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP\n", instance);
19887c478bd9Sstevel@tonic-gate 		}
19897c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
19907c478bd9Sstevel@tonic-gate 		++(pshot->busy);
19917c478bd9Sstevel@tonic-gate 		++(pshot->busy_ioctl);
19927c478bd9Sstevel@tonic-gate 		if (pshot_debug_busy) {
19937c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d:"
19947c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP comp 0 busy"
19957c478bd9Sstevel@tonic-gate 			    " %d busy_ioctl %d\n", instance, pshot->busy,
19967c478bd9Sstevel@tonic-gate 			    pshot->busy_ioctl);
19977c478bd9Sstevel@tonic-gate 		}
19987c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
19997c478bd9Sstevel@tonic-gate 		ret = pm_busy_component(pshot->dip, 0);
20007c478bd9Sstevel@tonic-gate 		ASSERT(ret == DDI_SUCCESS);
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 		break;
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUSY_COMP_TEST:
20057c478bd9Sstevel@tonic-gate 		/*
20067c478bd9Sstevel@tonic-gate 		 * test bus's busy state
20077c478bd9Sstevel@tonic-gate 		 */
20087c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
20097c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20107c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP_TEST\n", instance);
20117c478bd9Sstevel@tonic-gate 		}
20127c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
20137c478bd9Sstevel@tonic-gate 		state = pshot->busy;
20147c478bd9Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
20157c478bd9Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
20167c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
20177c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
20187c478bd9Sstevel@tonic-gate 			    instance);
20197c478bd9Sstevel@tonic-gate 			rv = EINVAL;
20207c478bd9Sstevel@tonic-gate 		}
20217c478bd9Sstevel@tonic-gate 		if (pshot_debug_busy) {
20227c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:"
20237c478bd9Sstevel@tonic-gate 			    " comp 0 busy %d busy_ioctl %d\n", instance,
20247c478bd9Sstevel@tonic-gate 			    state, pshot->busy_ioctl);
20257c478bd9Sstevel@tonic-gate 		}
20267c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
20277c478bd9Sstevel@tonic-gate 		break;
20287c478bd9Sstevel@tonic-gate 
20297c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_IDLE_COMP:
20307c478bd9Sstevel@tonic-gate 		/*
20317c478bd9Sstevel@tonic-gate 		 * mark component 0 idle.
20327c478bd9Sstevel@tonic-gate 		 * NOP if pshot->busy_ioctl <= 0.
20337c478bd9Sstevel@tonic-gate 		 */
20347c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
20357c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20367c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_IDLE_COMP\n", instance);
20377c478bd9Sstevel@tonic-gate 		}
20387c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
20397c478bd9Sstevel@tonic-gate 		if (pshot->busy_ioctl > 0) {
20407c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
20417c478bd9Sstevel@tonic-gate 			--(pshot->busy);
20427c478bd9Sstevel@tonic-gate 			--(pshot->busy_ioctl);
20437c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
20447c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
20457c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_IDLE_COM: comp 0"
20467c478bd9Sstevel@tonic-gate 				    " busy %d busy_ioctl %d\n", instance,
20477c478bd9Sstevel@tonic-gate 				    pshot->busy, pshot->busy_ioctl);
20487c478bd9Sstevel@tonic-gate 			}
20497c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20507c478bd9Sstevel@tonic-gate 			ret = pm_idle_component(pshot->dip, 0);
20517c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 		} else {
20547c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20557c478bd9Sstevel@tonic-gate 		}
20567c478bd9Sstevel@tonic-gate 		break;
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_RAISE_PWR:
20597c478bd9Sstevel@tonic-gate 		/*
20607c478bd9Sstevel@tonic-gate 		 * raise component 0 to full power level MAXPWR via a
20617c478bd9Sstevel@tonic-gate 		 * pm_raise_power() call
20627c478bd9Sstevel@tonic-gate 		 */
20637c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
20647c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20657c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_RAISE_PWR\n", instance);
20667c478bd9Sstevel@tonic-gate 		}
20677c478bd9Sstevel@tonic-gate 		if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) {
20687c478bd9Sstevel@tonic-gate 			rv = EINVAL;
20697c478bd9Sstevel@tonic-gate 		} else {
20707c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
20717c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
20727c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
20737c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_RAISE_POWER: comp 0"
20747c478bd9Sstevel@tonic-gate 				    " to level %d\n", instance, pshot->level);
20757c478bd9Sstevel@tonic-gate 			}
20767c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20777c478bd9Sstevel@tonic-gate 		}
20787c478bd9Sstevel@tonic-gate 		break;
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_LOWER_PWR:
20817c478bd9Sstevel@tonic-gate 		/*
20827c478bd9Sstevel@tonic-gate 		 * pm_lower_power() call for negative testing
20837c478bd9Sstevel@tonic-gate 		 * expected to fail.
20847c478bd9Sstevel@tonic-gate 		 */
20857c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
20867c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
20877c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_LOWER_PWR\n", instance);
20887c478bd9Sstevel@tonic-gate 		}
20897c478bd9Sstevel@tonic-gate 		if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
20907c478bd9Sstevel@tonic-gate 			rv = EINVAL;
20917c478bd9Sstevel@tonic-gate 		} else {
20927c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
20937c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
20947c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
20957c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_LOWER_POWER comp 0"
20967c478bd9Sstevel@tonic-gate 				    " to level %d\n", instance, pshot->level);
20977c478bd9Sstevel@tonic-gate 			}
20987c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
20997c478bd9Sstevel@tonic-gate 		}
21007c478bd9Sstevel@tonic-gate 		break;
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_CHANGE_PWR_LOW:
21037c478bd9Sstevel@tonic-gate 		/*
21047c478bd9Sstevel@tonic-gate 		 * inform the PM framework that component 0 has changed
21057c478bd9Sstevel@tonic-gate 		 * power level to 0 via a pm_power_has_changed() call
21067c478bd9Sstevel@tonic-gate 		 */
21077c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
21087c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21097c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
21107c478bd9Sstevel@tonic-gate 		}
21117c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21127c478bd9Sstevel@tonic-gate 		pshot->level = 0;
21137c478bd9Sstevel@tonic-gate 		if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) {
21147c478bd9Sstevel@tonic-gate 			rv = EINVAL;
21157c478bd9Sstevel@tonic-gate 		} else {
21167c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
21177c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
21187c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
21197c478bd9Sstevel@tonic-gate 				    " level %d\n", instance, pshot->level);
21207c478bd9Sstevel@tonic-gate 			}
21217c478bd9Sstevel@tonic-gate 		}
21227c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21237c478bd9Sstevel@tonic-gate 		break;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_CHANGE_PWR_HIGH:
21267c478bd9Sstevel@tonic-gate 		/*
21277c478bd9Sstevel@tonic-gate 		 * inform the PM framework that component 0 has changed
21287c478bd9Sstevel@tonic-gate 		 * power level to MAXPWR via a pm_power_has_changed() call
21297c478bd9Sstevel@tonic-gate 		 */
21307c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
21317c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21327c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
21337c478bd9Sstevel@tonic-gate 		}
21347c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21357c478bd9Sstevel@tonic-gate 		pshot->level = MAXPWR;
21367c478bd9Sstevel@tonic-gate 		if (pm_power_has_changed(pshot->dip, 0, MAXPWR)
21377c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
21387c478bd9Sstevel@tonic-gate 			rv = EINVAL;
21397c478bd9Sstevel@tonic-gate 		} else {
21407c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
21417c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
21427c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
21437c478bd9Sstevel@tonic-gate 				    " level %d\n", instance, pshot->level);
21447c478bd9Sstevel@tonic-gate 			}
21457c478bd9Sstevel@tonic-gate 		}
21467c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21477c478bd9Sstevel@tonic-gate 		break;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_POWER:
21507c478bd9Sstevel@tonic-gate 		/*
21517c478bd9Sstevel@tonic-gate 		 * test if the pshot_power() routine has been called,
21527c478bd9Sstevel@tonic-gate 		 * then clear
21537c478bd9Sstevel@tonic-gate 		 */
21547c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
21557c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21567c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
21577c478bd9Sstevel@tonic-gate 		}
21587c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21597c478bd9Sstevel@tonic-gate 		state = (pshot->state & POWER_FLAG) ? 1 : 0;
21607c478bd9Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
21617c478bd9Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
21627c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
21637c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER: copyout failed",
21647c478bd9Sstevel@tonic-gate 			    instance);
21657c478bd9Sstevel@tonic-gate 			rv = EINVAL;
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
21687c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:"
21697c478bd9Sstevel@tonic-gate 			    " POWER_FLAG = %d\n", instance, state);
21707c478bd9Sstevel@tonic-gate 		}
21717c478bd9Sstevel@tonic-gate 		pshot->state &= ~POWER_FLAG;
21727c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21737c478bd9Sstevel@tonic-gate 		break;
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_FAIL_SUSPEND:
21767c478bd9Sstevel@tonic-gate 		/*
21777c478bd9Sstevel@tonic-gate 		 * fail DDI_SUSPEND
21787c478bd9Sstevel@tonic-gate 		 */
21797c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
21807c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
21817c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_FAIL_SUSPEND\n", instance);
21827c478bd9Sstevel@tonic-gate 		}
21837c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21847c478bd9Sstevel@tonic-gate 		pshot->state |= FAIL_SUSPEND_FLAG;
21857c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
21867c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
21877c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n",
21887c478bd9Sstevel@tonic-gate 			    instance);
21897c478bd9Sstevel@tonic-gate 		}
21907c478bd9Sstevel@tonic-gate 		break;
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUS_STRICT_TEST:
21937c478bd9Sstevel@tonic-gate 		/*
21947c478bd9Sstevel@tonic-gate 		 * test the STRICT_PARENT flag:
21957c478bd9Sstevel@tonic-gate 		 *	set => STRICT PARENT
21967c478bd9Sstevel@tonic-gate 		 *	not set => INVOLVED PARENT
21977c478bd9Sstevel@tonic-gate 		 */
21987c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
21997c478bd9Sstevel@tonic-gate 		state = (pshot->state & STRICT_PARENT) ? 1 : 0;
22007c478bd9Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
22017c478bd9Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
22027c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
22037c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
22047c478bd9Sstevel@tonic-gate 			    instance);
22057c478bd9Sstevel@tonic-gate 			rv = EINVAL;
22067c478bd9Sstevel@tonic-gate 		}
22077c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
22087c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
22097c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
22107c478bd9Sstevel@tonic-gate 			    instance, ((state == 0) ? "INVOLVED" : "STRICT"));
22117c478bd9Sstevel@tonic-gate 		}
22127c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
22137c478bd9Sstevel@tonic-gate 		break;
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUS_NO_INVOL:
22167c478bd9Sstevel@tonic-gate 		/*
22177c478bd9Sstevel@tonic-gate 		 * Set the NO_INVOL_FLAG flag to
22187c478bd9Sstevel@tonic-gate 		 * notify the driver that the child will not
22197c478bd9Sstevel@tonic-gate 		 * call pm_lower_power() on detach.
22207c478bd9Sstevel@tonic-gate 		 * The driver needs to mark itself idle twice
22217c478bd9Sstevel@tonic-gate 		 * during DDI_CTLOPS_DETACH (post).
22227c478bd9Sstevel@tonic-gate 		 */
22237c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
22247c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
22257c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_NO_INVOL\n", instance);
22267c478bd9Sstevel@tonic-gate 		}
22277c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
22287c478bd9Sstevel@tonic-gate 		pshot->state |= NO_INVOL_FLAG;
22297c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
22307c478bd9Sstevel@tonic-gate 		break;
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	default:
22337c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
22347c478bd9Sstevel@tonic-gate 	}
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
22377c478bd9Sstevel@tonic-gate 	return (rv);
22387c478bd9Sstevel@tonic-gate }
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate /*
22427c478bd9Sstevel@tonic-gate  * pshot_testctl: handle other test operations
22437c478bd9Sstevel@tonic-gate  *	- If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
22447c478bd9Sstevel@tonic-gate  *	  child to direct the DEVCTL to, if applicable;
22457c478bd9Sstevel@tonic-gate  *	  furthermore, any cmd here can be sent by layered ioctls (unlike
22467c478bd9Sstevel@tonic-gate  *	  those to pshot_devctl() which must come from userland)
22477c478bd9Sstevel@tonic-gate  */
22487c478bd9Sstevel@tonic-gate /* ARGSUSED */
22497c478bd9Sstevel@tonic-gate static int
pshot_testctl(pshot_t * pshot,minor_t nodenum,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)22507c478bd9Sstevel@tonic-gate pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
22517c478bd9Sstevel@tonic-gate     cred_t *credp, int *rvalp)
22527c478bd9Sstevel@tonic-gate {
22537c478bd9Sstevel@tonic-gate 	dev_info_t *self;
22547c478bd9Sstevel@tonic-gate 	dev_info_t *child = NULL;
22557c478bd9Sstevel@tonic-gate 	uint_t state;
22567c478bd9Sstevel@tonic-gate 	int rv = 0;
22577c478bd9Sstevel@tonic-gate 	int instance;
22587c478bd9Sstevel@tonic-gate 	int i;
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 	/* uint_t flags; */
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	/* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
22637c478bd9Sstevel@tonic-gate 	self = pshot->dip;
22647c478bd9Sstevel@tonic-gate 	instance = pshot->instance;
22657c478bd9Sstevel@tonic-gate 
22667c478bd9Sstevel@tonic-gate 	if (cmd & DEVCTL_IOC) {
22677c478bd9Sstevel@tonic-gate 		child = e_ddi_hold_devi_by_dev((dev_t)arg, 0);
22687c478bd9Sstevel@tonic-gate 	}
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
22717c478bd9Sstevel@tonic-gate 		if (pshot_devctls[i].ioctl_int == cmd) {
22727c478bd9Sstevel@tonic-gate 			if (pshot_debug)
22737c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d devctl: %s",
22747c478bd9Sstevel@tonic-gate 				    instance, pshot_devctls[i].ioctl_char);
22757c478bd9Sstevel@tonic-gate 		}
22767c478bd9Sstevel@tonic-gate 	}
22777c478bd9Sstevel@tonic-gate 	switch (cmd) {
22787c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
22797c478bd9Sstevel@tonic-gate 		if (pshot_debug)
22807c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
22817c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
22827c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
22837c478bd9Sstevel@tonic-gate 		    child, (void *)self);
22847c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
22857c478bd9Sstevel@tonic-gate 		break;
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
22887c478bd9Sstevel@tonic-gate 		if (pshot_debug)
22897c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
22907c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
22917c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
22927c478bd9Sstevel@tonic-gate 			if (state == BUS_QUIESCED) {
22937c478bd9Sstevel@tonic-gate 				break;
22947c478bd9Sstevel@tonic-gate 			}
22957c478bd9Sstevel@tonic-gate 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
22967c478bd9Sstevel@tonic-gate 		}
22977c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
22987c478bd9Sstevel@tonic-gate 		    child, (void *)self);
22997c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate 		break;
23027c478bd9Sstevel@tonic-gate 
23037c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
23047c478bd9Sstevel@tonic-gate 		if (pshot_debug)
23057c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
23067c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
23077c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
23087c478bd9Sstevel@tonic-gate 			if (state == BUS_ACTIVE) {
23097c478bd9Sstevel@tonic-gate 				break;
23107c478bd9Sstevel@tonic-gate 			}
23117c478bd9Sstevel@tonic-gate 		}
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 		/*
23147c478bd9Sstevel@tonic-gate 		 * quiesce the bus through bus-specific means
23157c478bd9Sstevel@tonic-gate 		 */
23167c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
23177c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
23187c478bd9Sstevel@tonic-gate 		    child, (void *)self);
23197c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
23207c478bd9Sstevel@tonic-gate 		break;
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
23237c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
23247c478bd9Sstevel@tonic-gate 		/*
23257c478bd9Sstevel@tonic-gate 		 * no reset support for the pseudo bus
23267c478bd9Sstevel@tonic-gate 		 * but if there were....
23277c478bd9Sstevel@tonic-gate 		 */
23287c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
232919397407SSherry Moore 		    child, (void *)self);
23307c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
23317c478bd9Sstevel@tonic-gate 		break;
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 	default:
23347c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
23357c478bd9Sstevel@tonic-gate 	}
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	if (child != NULL)
23387c478bd9Sstevel@tonic-gate 		ddi_release_devi(child);
23397c478bd9Sstevel@tonic-gate 	return (rv);
23407c478bd9Sstevel@tonic-gate }
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate static int
pshot_get_eventcookie(dev_info_t * dip,dev_info_t * rdip,char * eventname,ddi_eventcookie_t * event_cookiep)23447c478bd9Sstevel@tonic-gate pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
2345*d5ebc493SDan Cross     char *eventname, ddi_eventcookie_t *event_cookiep)
23467c478bd9Sstevel@tonic-gate {
23477c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
23487c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	if (pshot_debug)
235119397407SSherry Moore 		cmn_err(CE_CONT, "pshot%d: "
235219397407SSherry Moore 		    "pshot_get_eventcookie:\n\t"
235319397407SSherry Moore 		    "dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
235419397407SSherry Moore 		    instance, (void *)dip, (void *)rdip,
235519397407SSherry Moore 		    ddi_node_name(rdip), ddi_get_instance(rdip),
235619397407SSherry Moore 		    eventname);
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 
23597c478bd9Sstevel@tonic-gate 	return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl,
236019397407SSherry Moore 	    rdip, eventname, event_cookiep, NDI_EVENT_NOPASS));
23617c478bd9Sstevel@tonic-gate }
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@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)23647c478bd9Sstevel@tonic-gate pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
2365*d5ebc493SDan Cross     ddi_eventcookie_t cookie,
2366*d5ebc493SDan Cross     void (*callback)(), void *arg, ddi_callback_id_t *cb_id)
23677c478bd9Sstevel@tonic-gate {
23687c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
23697c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	if (pshot_debug)
237219397407SSherry Moore 		cmn_err(CE_CONT, "pshot%d: "
237319397407SSherry Moore 		    "pshot_add_eventcall:\n\t"
237419397407SSherry Moore 		    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
237519397407SSherry Moore 		    "cb = 0x%p, arg = 0x%p\n",
237619397407SSherry Moore 		    instance, (void *)dip, (void *)rdip,
237719397407SSherry Moore 		    ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
237819397407SSherry Moore 		    NDI_EVENT_NAME(cookie), (void *)callback, arg);
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	/* add callback to our event handle */
23817c478bd9Sstevel@tonic-gate 	return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip,
238219397407SSherry Moore 	    cookie, callback, arg, NDI_SLEEP, cb_id));
23837c478bd9Sstevel@tonic-gate }
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate static int
pshot_remove_eventcall(dev_info_t * dip,ddi_callback_id_t cb_id)23867c478bd9Sstevel@tonic-gate pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
23877c478bd9Sstevel@tonic-gate {
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
23927c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 	ASSERT(cb);
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	if (pshot_debug)
239719397407SSherry Moore 		cmn_err(CE_CONT, "pshot%d: "
239819397407SSherry Moore 		    "pshot_remove_eventcall:\n\t"
239919397407SSherry Moore 		    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
240019397407SSherry Moore 		    instance, (void *)dip, (void *)cb->ndi_evtcb_dip,
240119397407SSherry Moore 		    ddi_node_name(cb->ndi_evtcb_dip),
240219397407SSherry Moore 		    ddi_get_instance(cb->ndi_evtcb_dip),
240319397407SSherry Moore 		    (void *)cb->ndi_evtcb_cookie,
240419397407SSherry Moore 		    NDI_EVENT_NAME(cb->ndi_evtcb_cookie));
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id));
24077c478bd9Sstevel@tonic-gate }
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate static int
pshot_post_event(dev_info_t * dip,dev_info_t * rdip,ddi_eventcookie_t cookie,void * impl_data)24107c478bd9Sstevel@tonic-gate pshot_post_event(dev_info_t *dip, dev_info_t *rdip,
2411*d5ebc493SDan Cross     ddi_eventcookie_t cookie, void *impl_data)
24127c478bd9Sstevel@tonic-gate {
24137c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
24147c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
241719397407SSherry Moore 		if (rdip) {
241819397407SSherry Moore 			cmn_err(CE_CONT, "pshot%d: "
241919397407SSherry Moore 			    "pshot_post_event:\n\t"
242019397407SSherry Moore 			    "dip = 0x%p rdip = 0x%p (%s%d\n\t"
242119397407SSherry Moore 			    "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
242219397407SSherry Moore 			    instance, (void *)dip, (void *)rdip,
242319397407SSherry Moore 			    ddi_node_name(rdip), ddi_get_instance(rdip),
242419397407SSherry Moore 			    (void *)cookie,
242519397407SSherry Moore 			    NDI_EVENT_NAME(cookie), impl_data);
242619397407SSherry Moore 		} else {
242719397407SSherry Moore 			cmn_err(CE_CONT, "pshot%d: "
242819397407SSherry Moore 			    "pshot_post_event:\n\t"
242919397407SSherry Moore 			    "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
243019397407SSherry Moore 			    instance, (void *)dip, (void *)cookie,
243119397407SSherry Moore 			    NDI_EVENT_NAME(cookie), impl_data);
243219397407SSherry Moore 		}
24337c478bd9Sstevel@tonic-gate 	}
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate 	/*  run callbacks for this event */
24367c478bd9Sstevel@tonic-gate 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip,
24377c478bd9Sstevel@tonic-gate 	    cookie, impl_data));
24387c478bd9Sstevel@tonic-gate }
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate /*
24417c478bd9Sstevel@tonic-gate  * the nexus driver will generate events
24427c478bd9Sstevel@tonic-gate  * that need to go to children
24437c478bd9Sstevel@tonic-gate  */
24447c478bd9Sstevel@tonic-gate static int
pshot_event(pshot_t * pshot,int event_tag,dev_info_t * child,void * bus_impldata)24457c478bd9Sstevel@tonic-gate pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child,
2446*d5ebc493SDan Cross     void *bus_impldata)
24477c478bd9Sstevel@tonic-gate {
24487c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(
244919397407SSherry Moore 	    pshot->ndi_event_hdl, event_tag);
24507c478bd9Sstevel@tonic-gate 
24517c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
24527c478bd9Sstevel@tonic-gate 		if (child) {
245319397407SSherry Moore 			cmn_err(CE_CONT, "pshot%d: "
245419397407SSherry Moore 			    "pshot_event: event_tag = 0x%x (%s)\n\t"
245519397407SSherry Moore 			    "child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
245619397407SSherry Moore 			    pshot->instance, event_tag,
245719397407SSherry Moore 			    ndi_event_tag_to_name(pshot->ndi_event_hdl,
245819397407SSherry Moore 			    event_tag),
245919397407SSherry Moore 			    (void *)child, ddi_node_name(child),
246019397407SSherry Moore 			    ddi_get_instance(child), bus_impldata,
246119397407SSherry Moore 			    ddi_node_name((dev_info_t *)bus_impldata),
246219397407SSherry Moore 			    ddi_get_instance((dev_info_t *)bus_impldata));
24637c478bd9Sstevel@tonic-gate 		} else {
246419397407SSherry Moore 			cmn_err(CE_CONT, "pshot%d: "
246519397407SSherry Moore 			    "pshot_event: event_tag = 0x%x (%s)\n\t"
246619397407SSherry Moore 			    "child = NULL,  bus_impl = 0x%p (%s%d)\n",
246719397407SSherry Moore 			    pshot->instance, event_tag,
246819397407SSherry Moore 			    ndi_event_tag_to_name(pshot->ndi_event_hdl,
246919397407SSherry Moore 			    event_tag),
247019397407SSherry Moore 			    bus_impldata,
247119397407SSherry Moore 			    ddi_node_name((dev_info_t *)bus_impldata),
247219397407SSherry Moore 			    ddi_get_instance((dev_info_t *)bus_impldata));
24737c478bd9Sstevel@tonic-gate 		}
24747c478bd9Sstevel@tonic-gate 	}
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl,
247719397407SSherry Moore 	    child, cookie, bus_impldata));
24787c478bd9Sstevel@tonic-gate }
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate /*
24827c478bd9Sstevel@tonic-gate  * the pshot driver event notification callback
24837c478bd9Sstevel@tonic-gate  */
24847c478bd9Sstevel@tonic-gate static void
pshot_event_cb(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata)24857c478bd9Sstevel@tonic-gate pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
2486*d5ebc493SDan Cross     void *arg, void *bus_impldata)
24877c478bd9Sstevel@tonic-gate {
24887c478bd9Sstevel@tonic-gate 	pshot_t *pshot = (pshot_t *)arg;
24897c478bd9Sstevel@tonic-gate 	int event_tag;
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	/* look up the event */
24927c478bd9Sstevel@tonic-gate 	event_tag = NDI_EVENT_TAG(cookie);
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
24957c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: "
24967c478bd9Sstevel@tonic-gate 		    "pshot_event_cb:\n\t"
24977c478bd9Sstevel@tonic-gate 		    "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
24987c478bd9Sstevel@tonic-gate 		    "arg = 0x%p bus_impl = 0x%p (%s%d)\n",
24997c478bd9Sstevel@tonic-gate 		    pshot->instance, (void *)dip, (void *)cookie,
25007c478bd9Sstevel@tonic-gate 		    NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata,
25017c478bd9Sstevel@tonic-gate 		    ddi_node_name((dev_info_t *)bus_impldata),
25027c478bd9Sstevel@tonic-gate 		    ddi_get_instance((dev_info_t *)bus_impldata));
25037c478bd9Sstevel@tonic-gate 	}
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 	switch (event_tag) {
25067c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_OFFLINE:
25077c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_RESET:
25087c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_QUIESCE:
25097c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_UNQUIESCE:
25107c478bd9Sstevel@tonic-gate 		/* notify all subscribers of the this event */
25117c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(pshot->ndi_event_hdl,
251219397407SSherry Moore 		    NULL, cookie, bus_impldata);
25137c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
25147c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: event=%s\n\t"
251519397407SSherry Moore 			    "pshot_event_cb\n", pshot->instance,
251619397407SSherry Moore 			    NDI_EVENT_NAME(cookie));
25177c478bd9Sstevel@tonic-gate 		}
25187c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
25197c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_TEST_POST:
25207c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_DEV_RESET:
25217c478bd9Sstevel@tonic-gate 	default:
25227c478bd9Sstevel@tonic-gate 		return;
25237c478bd9Sstevel@tonic-gate 	}
25247c478bd9Sstevel@tonic-gate }
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@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)25277c478bd9Sstevel@tonic-gate pshot_bus_config(dev_info_t *parent, uint_t flags,
25287c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
25297c478bd9Sstevel@tonic-gate {
25307c478bd9Sstevel@tonic-gate 	int		rval;
25317c478bd9Sstevel@tonic-gate 	char		*devname;
25327c478bd9Sstevel@tonic-gate 	char		*devstr, *cname, *caddr;
25337c478bd9Sstevel@tonic-gate 	int		devstrlen;
25347c478bd9Sstevel@tonic-gate 	pshot_t		*pshot;
25357c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(parent);
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
25387c478bd9Sstevel@tonic-gate 		flags |= NDI_DEVI_DEBUG;
25397c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
25407c478bd9Sstevel@tonic-gate 		    "pshot%d: bus_config %s flags=0x%x\n",
25417c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
25427c478bd9Sstevel@tonic-gate 		    (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags);
25437c478bd9Sstevel@tonic-gate 	}
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
25467c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
25497c478bd9Sstevel@tonic-gate 	}
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	/*
25527c478bd9Sstevel@tonic-gate 	 * Hold the nexus across the bus_config
25537c478bd9Sstevel@tonic-gate 	 */
25543fe80ca4SDan Cross 	ndi_devi_enter(parent);
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 	switch (op) {
25577c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ONE:
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate 		/*
25607c478bd9Sstevel@tonic-gate 		 * lookup and hold child device, create if not found
25617c478bd9Sstevel@tonic-gate 		 */
25627c478bd9Sstevel@tonic-gate 		devname = (char *)arg;
25637c478bd9Sstevel@tonic-gate 		devstrlen = strlen(devname) + 1;
25647c478bd9Sstevel@tonic-gate 		devstr = i_ddi_strdup(devname, KM_SLEEP);
25657c478bd9Sstevel@tonic-gate 		i_ddi_parse_name(devstr, &cname, &caddr, NULL);
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 		/*
25687c478bd9Sstevel@tonic-gate 		 * The framework ensures that the node has
25697c478bd9Sstevel@tonic-gate 		 * a name but each nexus is responsible for
25707c478bd9Sstevel@tonic-gate 		 * the bus address name space.  This driver
25717c478bd9Sstevel@tonic-gate 		 * requires that a bus address be specified,
25727c478bd9Sstevel@tonic-gate 		 * as will most nexus drivers.
25737c478bd9Sstevel@tonic-gate 		 */
25747c478bd9Sstevel@tonic-gate 		ASSERT(cname && strlen(cname) > 0);
25757c478bd9Sstevel@tonic-gate 		if (caddr == NULL || strlen(caddr) == 0) {
25767c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
25777c478bd9Sstevel@tonic-gate 			    "pshot%d: malformed name %s (no bus address)",
25787c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent), devname);
25797c478bd9Sstevel@tonic-gate 			kmem_free(devstr, devstrlen);
25803fe80ca4SDan Cross 			ndi_devi_exit(parent);
25817c478bd9Sstevel@tonic-gate 			return (NDI_FAILURE);
25827c478bd9Sstevel@tonic-gate 		}
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 		/*
25857c478bd9Sstevel@tonic-gate 		 * Handle a few special cases for testing purposes
25867c478bd9Sstevel@tonic-gate 		 */
25877c478bd9Sstevel@tonic-gate 		rval = pshot_bus_config_test_specials(parent,
258819397407SSherry Moore 		    devname, cname, caddr);
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 		if (rval == NDI_SUCCESS) {
25917c478bd9Sstevel@tonic-gate 			/*
25927c478bd9Sstevel@tonic-gate 			 * Set up either a leaf or nexus device
25937c478bd9Sstevel@tonic-gate 			 */
25947c478bd9Sstevel@tonic-gate 			if (strcmp(cname, "pshot") == 0) {
25957c478bd9Sstevel@tonic-gate 				rval = pshot_bus_config_setup_nexus(parent,
25967c478bd9Sstevel@tonic-gate 				    cname, caddr);
25977c478bd9Sstevel@tonic-gate 			} else {
25987c478bd9Sstevel@tonic-gate 				rval = pshot_bus_config_setup_leaf(parent,
25997c478bd9Sstevel@tonic-gate 				    cname, caddr);
26007c478bd9Sstevel@tonic-gate 			}
26017c478bd9Sstevel@tonic-gate 		}
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 		kmem_free(devstr, devstrlen);
26047c478bd9Sstevel@tonic-gate 		break;
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_DRIVER:
26077c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ALL:
26087c478bd9Sstevel@tonic-gate 		rval = NDI_SUCCESS;
26097c478bd9Sstevel@tonic-gate 		break;
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	default:
26127c478bd9Sstevel@tonic-gate 		rval = NDI_FAILURE;
26137c478bd9Sstevel@tonic-gate 		break;
26147c478bd9Sstevel@tonic-gate 	}
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	if (rval == NDI_SUCCESS)
26177c478bd9Sstevel@tonic-gate 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
26187c478bd9Sstevel@tonic-gate 
26193fe80ca4SDan Cross 	ndi_devi_exit(parent);
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	if (pshot_debug)
26227c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: bus_config %s\n",
26237c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
26247c478bd9Sstevel@tonic-gate 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	return (rval);
26277c478bd9Sstevel@tonic-gate }
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate static int
pshot_bus_unconfig(dev_info_t * parent,uint_t flags,ddi_bus_config_op_t op,void * arg)26307c478bd9Sstevel@tonic-gate pshot_bus_unconfig(dev_info_t *parent, uint_t flags,
26317c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg)
26327c478bd9Sstevel@tonic-gate {
26337c478bd9Sstevel@tonic-gate 	major_t		major;
26347c478bd9Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
26377c478bd9Sstevel@tonic-gate 		flags |= NDI_DEVI_DEBUG;
26387c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
26397c478bd9Sstevel@tonic-gate 		    "pshot%d: bus_unconfig %s flags=0x%x\n",
26407c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
26417c478bd9Sstevel@tonic-gate 		    (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags);
26427c478bd9Sstevel@tonic-gate 	}
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	/*
26457c478bd9Sstevel@tonic-gate 	 * Hold the nexus across the bus_unconfig
26467c478bd9Sstevel@tonic-gate 	 */
26473fe80ca4SDan Cross 	ndi_devi_enter(parent);
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 	switch (op) {
26507c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_ONE:
26517c478bd9Sstevel@tonic-gate 		/*
26527c478bd9Sstevel@tonic-gate 		 * Nothing special required here
26537c478bd9Sstevel@tonic-gate 		 */
26547c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
26557c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
26567c478bd9Sstevel@tonic-gate 			    " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent));
26577c478bd9Sstevel@tonic-gate 		}
26587c478bd9Sstevel@tonic-gate 		break;
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_DRIVER:
26617c478bd9Sstevel@tonic-gate 		if (pshot_debug > 0) {
26627c478bd9Sstevel@tonic-gate 			major = (major_t)(uintptr_t)arg;
26637c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
26647c478bd9Sstevel@tonic-gate 			    "pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
26657c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent),
26667c478bd9Sstevel@tonic-gate 			    ddi_major_to_name(major));
26677c478bd9Sstevel@tonic-gate 		}
26687c478bd9Sstevel@tonic-gate 		break;
26697c478bd9Sstevel@tonic-gate 
26707c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_ALL:
26717c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
26727c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
26737c478bd9Sstevel@tonic-gate 			    " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent));
26747c478bd9Sstevel@tonic-gate 		}
26757c478bd9Sstevel@tonic-gate 		break;
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 	default:
26787c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
26797c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n",
26807c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent));
26817c478bd9Sstevel@tonic-gate 		}
26827c478bd9Sstevel@tonic-gate 		rval = NDI_FAILURE;
26837c478bd9Sstevel@tonic-gate 	}
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	if (rval == NDI_SUCCESS)
26867c478bd9Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(parent, flags, op, arg);
26877c478bd9Sstevel@tonic-gate 
26883fe80ca4SDan Cross 	ndi_devi_exit(parent);
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 	if (pshot_debug)
26917c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n",
26927c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
26937c478bd9Sstevel@tonic-gate 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 	return (rval);
26967c478bd9Sstevel@tonic-gate }
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate static dev_info_t *
pshot_findchild(dev_info_t * pdip,char * cname,char * caddr)26997c478bd9Sstevel@tonic-gate pshot_findchild(dev_info_t *pdip, char *cname, char *caddr)
27007c478bd9Sstevel@tonic-gate {
27017c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
27027c478bd9Sstevel@tonic-gate 	char *addr;
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate 	ASSERT(cname != NULL && caddr != NULL);
27057c478bd9Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(pdip));
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	for (dip = ddi_get_child(pdip); dip != NULL;
27087c478bd9Sstevel@tonic-gate 	    dip = ddi_get_next_sibling(dip)) {
27097c478bd9Sstevel@tonic-gate 		if (strcmp(cname, ddi_node_name(dip)) != 0)
27107c478bd9Sstevel@tonic-gate 			continue;
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
27137c478bd9Sstevel@tonic-gate 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
27147c478bd9Sstevel@tonic-gate 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
27157c478bd9Sstevel@tonic-gate 				if (strcmp(caddr, addr) == 0) {
27167c478bd9Sstevel@tonic-gate 					ddi_prop_free(addr);
27177c478bd9Sstevel@tonic-gate 					return (dip);
27187c478bd9Sstevel@tonic-gate 				}
27197c478bd9Sstevel@tonic-gate 				ddi_prop_free(addr);
27207c478bd9Sstevel@tonic-gate 			}
27217c478bd9Sstevel@tonic-gate 		} else {
27227c478bd9Sstevel@tonic-gate 			if (strcmp(caddr, addr) == 0)
27237c478bd9Sstevel@tonic-gate 				return (dip);
27247c478bd9Sstevel@tonic-gate 		}
27257c478bd9Sstevel@tonic-gate 	}
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	return (NULL);
27287c478bd9Sstevel@tonic-gate }
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate static void
pshot_nexus_properties(dev_info_t * parent,dev_info_t * child,char * cname,char * caddr)27317c478bd9Sstevel@tonic-gate pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname,
27327c478bd9Sstevel@tonic-gate     char *caddr)
27337c478bd9Sstevel@tonic-gate {
27347c478bd9Sstevel@tonic-gate 	char *extension;
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	/*
2737b1dd958fScth 	 * extract the address extension
27387c478bd9Sstevel@tonic-gate 	 */
27397c478bd9Sstevel@tonic-gate 	extension = strstr(caddr, ",");
27407c478bd9Sstevel@tonic-gate 	if (extension != NULL) {
27417c478bd9Sstevel@tonic-gate 		++extension;
27427c478bd9Sstevel@tonic-gate 	} else {
27437c478bd9Sstevel@tonic-gate 		extension = "null";
27447c478bd9Sstevel@tonic-gate 	}
27457c478bd9Sstevel@tonic-gate 
27467c478bd9Sstevel@tonic-gate 	/*
27477c478bd9Sstevel@tonic-gate 	 * Create the "pm-want-child-notification?" property for all
27487c478bd9Sstevel@tonic-gate 	 * nodes that do not have the "pm_strict" or "nopm_strict"
27497c478bd9Sstevel@tonic-gate 	 * extension
27507c478bd9Sstevel@tonic-gate 	 */
27517c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "pm_strict") != 0 &&
27527c478bd9Sstevel@tonic-gate 	    strcmp(extension, "nopm_strict") != 0) {
27537c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
27547c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
27557c478bd9Sstevel@tonic-gate 		    "pm-want-child-notification?") == 0) {
27567c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
27577c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
27587c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tcreate the"
27597c478bd9Sstevel@tonic-gate 				    " \"pm-want-child-notification?\""
27607c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
27617c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
27627c478bd9Sstevel@tonic-gate 			}
27637c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
27647c478bd9Sstevel@tonic-gate 			    "pm-want-child-notification?", NULL, 0)
27657c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
27667c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
27677c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tunable to create"
27687c478bd9Sstevel@tonic-gate 				    " the \"pm-want-child-notification?\""
27697c478bd9Sstevel@tonic-gate 				    " property for %s@%s",
27707c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
27717c478bd9Sstevel@tonic-gate 			}
27727c478bd9Sstevel@tonic-gate 		}
27737c478bd9Sstevel@tonic-gate 	}
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate 	/*
27767c478bd9Sstevel@tonic-gate 	 * Create the "no-pm-components" property for all nodes
27777c478bd9Sstevel@tonic-gate 	 * with extension "nopm" or "nopm_strict"
27787c478bd9Sstevel@tonic-gate 	 */
27797c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "nopm") == 0 ||
27807c478bd9Sstevel@tonic-gate 	    strcmp(extension, "nopm_strict") == 0) {
27817c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
27827c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
27837c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 0) {
27847c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
27857c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
27867c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tcreate the"
27877c478bd9Sstevel@tonic-gate 				    " \"no-pm-components\""
27887c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
27897c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
27907c478bd9Sstevel@tonic-gate 			}
27917c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
27927c478bd9Sstevel@tonic-gate 			    "no-pm-components", NULL, 0)
27937c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
27947c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
27957c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tunable to create"
27967c478bd9Sstevel@tonic-gate 				    " the \"no-pm-components\""
27977c478bd9Sstevel@tonic-gate 				    " property for %s@%s",
279819397407SSherry Moore 				    ddi_get_instance(parent), cname, caddr);
27997c478bd9Sstevel@tonic-gate 			}
28007c478bd9Sstevel@tonic-gate 		}
28017c478bd9Sstevel@tonic-gate 	}
28027c478bd9Sstevel@tonic-gate }
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate static void
pshot_leaf_properties(dev_info_t * parent,dev_info_t * child,char * cname,char * caddr)28057c478bd9Sstevel@tonic-gate pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname,
28067c478bd9Sstevel@tonic-gate     char *caddr)
28077c478bd9Sstevel@tonic-gate {
28087c478bd9Sstevel@tonic-gate 	char *extension;
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate 	/*
2811b1dd958fScth 	 * extract the address extension
28127c478bd9Sstevel@tonic-gate 	 */
28137c478bd9Sstevel@tonic-gate 	extension = strstr(caddr, ",");
28147c478bd9Sstevel@tonic-gate 	if (extension != NULL) {
28157c478bd9Sstevel@tonic-gate 		++extension;
28167c478bd9Sstevel@tonic-gate 	} else {
28177c478bd9Sstevel@tonic-gate 		extension = "null";
28187c478bd9Sstevel@tonic-gate 	}
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	/*
28217c478bd9Sstevel@tonic-gate 	 * Create the "no-involuntary-power-cycles" property for
28227c478bd9Sstevel@tonic-gate 	 * all leaf nodes with extension "no_invol"
28237c478bd9Sstevel@tonic-gate 	 */
28247c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "no_invol") == 0) {
28257c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
28267c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
28277c478bd9Sstevel@tonic-gate 		    "no-involuntary-power-cycles") == 0) {
28287c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
28297c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
28307c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tcreate the"
28317c478bd9Sstevel@tonic-gate 				    " \"no-involuntary-power-cycles\""
28327c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
28337c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
28347c478bd9Sstevel@tonic-gate 			}
28357c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
28367c478bd9Sstevel@tonic-gate 			    DDI_PROP_CANSLEEP,
28377c478bd9Sstevel@tonic-gate 			    "no-involuntary-power-cycles", NULL, 0)
28387c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
28397c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
28407c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tunable to create the"
28417c478bd9Sstevel@tonic-gate 				    " \"no-involuntary-power-cycles\""
28427c478bd9Sstevel@tonic-gate 				    " property for %s@%s",
28437c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
28447c478bd9Sstevel@tonic-gate 			}
28457c478bd9Sstevel@tonic-gate 		}
28467c478bd9Sstevel@tonic-gate 	}
28477c478bd9Sstevel@tonic-gate 
28487c478bd9Sstevel@tonic-gate 	/*
28497c478bd9Sstevel@tonic-gate 	 * Create the "dependency-property" property for all leaf
28507c478bd9Sstevel@tonic-gate 	 * nodes with extension "dep_prop"
28517c478bd9Sstevel@tonic-gate 	 * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
28527c478bd9Sstevel@tonic-gate 	 */
28537c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "dep_prop") == 0) {
28547c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
28557c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
28567c478bd9Sstevel@tonic-gate 		    "dependency-property") == 0) {
28577c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
28587c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
28597c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tcreate the"
28607c478bd9Sstevel@tonic-gate 				    " \"dependency-property\""
28617c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
28627c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
28637c478bd9Sstevel@tonic-gate 			}
28647c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
28657c478bd9Sstevel@tonic-gate 			    DDI_PROP_CANSLEEP, "dependency-property", NULL, 0)
28667c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
28677c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
28687c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tunable to create the"
28697c478bd9Sstevel@tonic-gate 				    " \"dependency-property\" property for"
28707c478bd9Sstevel@tonic-gate 				    " %s@%s", ddi_get_instance(parent),
28717c478bd9Sstevel@tonic-gate 				    cname, caddr);
28727c478bd9Sstevel@tonic-gate 			}
28737c478bd9Sstevel@tonic-gate 		}
28747c478bd9Sstevel@tonic-gate 	}
28757c478bd9Sstevel@tonic-gate }
28767c478bd9Sstevel@tonic-gate 
28777c478bd9Sstevel@tonic-gate /*
28787c478bd9Sstevel@tonic-gate  * BUS_CONFIG_ONE: setup a child nexus instance.
28797c478bd9Sstevel@tonic-gate  */
28807c478bd9Sstevel@tonic-gate static int
pshot_bus_config_setup_nexus(dev_info_t * parent,char * cname,char * caddr)28817c478bd9Sstevel@tonic-gate pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr)
28827c478bd9Sstevel@tonic-gate {
28837c478bd9Sstevel@tonic-gate 	dev_info_t *child;
28847c478bd9Sstevel@tonic-gate 	int rval;
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate 	ASSERT(parent != 0);
28877c478bd9Sstevel@tonic-gate 	ASSERT(cname != NULL);
28887c478bd9Sstevel@tonic-gate 	ASSERT(caddr != NULL);
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate 	child = pshot_findchild(parent, cname, caddr);
28917c478bd9Sstevel@tonic-gate 	if (child) {
28927c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
28937c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
28947c478bd9Sstevel@tonic-gate 			    "pshot%d: bus_config one %s@%s found\n",
28957c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent), cname, caddr);
28967c478bd9Sstevel@tonic-gate 		}
28975e3986cbScth 
28987c478bd9Sstevel@tonic-gate 		/*
28997c478bd9Sstevel@tonic-gate 		 * create the "pm-want-child-notification?" property
29007c478bd9Sstevel@tonic-gate 		 * for this child, if it doesn't already exist
29017c478bd9Sstevel@tonic-gate 		 */
29027c478bd9Sstevel@tonic-gate 		(void) pshot_nexus_properties(parent, child, cname, caddr);
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 		return (NDI_SUCCESS);
29057c478bd9Sstevel@tonic-gate 	}
29067c478bd9Sstevel@tonic-gate 
29077c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
29087c478bd9Sstevel@tonic-gate 	ASSERT(child != NULL);
29097c478bd9Sstevel@tonic-gate 
29107c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
29117c478bd9Sstevel@tonic-gate 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
29127c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed",
29137c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent), cname, caddr);
29147c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
29157c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
29167c478bd9Sstevel@tonic-gate 	}
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate 	rval = ndi_devi_bind_driver(child, 0);
29197c478bd9Sstevel@tonic-gate 	if (rval != NDI_SUCCESS) {
29207c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
29217c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent), cname);
29227c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
29237c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
29247c478bd9Sstevel@tonic-gate 	}
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 	/*
29277c478bd9Sstevel@tonic-gate 	 * create the "pm-want-child-notification?" property
29287c478bd9Sstevel@tonic-gate 	 */
29297c478bd9Sstevel@tonic-gate 	(void) pshot_nexus_properties(parent, child, cname, caddr);
29307c478bd9Sstevel@tonic-gate 
29317c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
29327c478bd9Sstevel@tonic-gate }
29337c478bd9Sstevel@tonic-gate 
29347c478bd9Sstevel@tonic-gate /*
29357c478bd9Sstevel@tonic-gate  * BUS_CONFIG_ONE: setup a child leaf device instance.
29367c478bd9Sstevel@tonic-gate  * for testing purposes, we will create nodes of a variety of types.
29377c478bd9Sstevel@tonic-gate  */
29387c478bd9Sstevel@tonic-gate static int
pshot_bus_config_setup_leaf(dev_info_t * parent,char * cname,char * caddr)29397c478bd9Sstevel@tonic-gate pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr)
29407c478bd9Sstevel@tonic-gate {
29417c478bd9Sstevel@tonic-gate 	dev_info_t *child;
29427c478bd9Sstevel@tonic-gate 	char *compat_name;
29437c478bd9Sstevel@tonic-gate 	char *nodetype;
29447c478bd9Sstevel@tonic-gate 	int rval;
29457c478bd9Sstevel@tonic-gate 	int i;
29467c478bd9Sstevel@tonic-gate 
29477c478bd9Sstevel@tonic-gate 	ASSERT(parent != 0);
29487c478bd9Sstevel@tonic-gate 	ASSERT(cname != NULL);
29497c478bd9Sstevel@tonic-gate 	ASSERT(caddr != NULL);
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate 	/*
29527c478bd9Sstevel@tonic-gate 	 * if we already have a node with this name, return it
29537c478bd9Sstevel@tonic-gate 	 */
29547c478bd9Sstevel@tonic-gate 	if ((child = pshot_findchild(parent, cname, caddr)) != NULL) {
29557c478bd9Sstevel@tonic-gate 		/*
29567c478bd9Sstevel@tonic-gate 		 * create the "no-involuntary-power-cycles" or
29577c478bd9Sstevel@tonic-gate 		 * the "dependency-property" property, if they
29587c478bd9Sstevel@tonic-gate 		 * don't already exit
29597c478bd9Sstevel@tonic-gate 		 */
29607c478bd9Sstevel@tonic-gate 		(void) pshot_leaf_properties(parent, child, cname, caddr);
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate 		return (NDI_SUCCESS);
29637c478bd9Sstevel@tonic-gate 	}
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
29667c478bd9Sstevel@tonic-gate 	ASSERT(child != NULL);
29677c478bd9Sstevel@tonic-gate 
29687c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr",
29697c478bd9Sstevel@tonic-gate 	    caddr) != DDI_PROP_SUCCESS) {
29707c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
29717c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
29727c478bd9Sstevel@tonic-gate 	}
29737c478bd9Sstevel@tonic-gate 
29747c478bd9Sstevel@tonic-gate 	/*
29757c478bd9Sstevel@tonic-gate 	 * test compatible naming
29767c478bd9Sstevel@tonic-gate 	 * if the child nodename is "cdisk", attach the list of compatible
29777c478bd9Sstevel@tonic-gate 	 * named disks
29787c478bd9Sstevel@tonic-gate 	 */
29797c478bd9Sstevel@tonic-gate 	if (strcmp(cname, pshot_compat_diskname) == 0) {
29807c478bd9Sstevel@tonic-gate 		if ((ndi_prop_update_string_array(DDI_DEV_T_NONE,
29817c478bd9Sstevel@tonic-gate 		    child, "compatible", (char **)pshot_compat_psramdisks,
29827c478bd9Sstevel@tonic-gate 		    5)) != DDI_PROP_SUCCESS) {
29837c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(child);
29847c478bd9Sstevel@tonic-gate 			return (NDI_FAILURE);
29857c478bd9Sstevel@tonic-gate 		}
29867c478bd9Sstevel@tonic-gate 	} else {
29877c478bd9Sstevel@tonic-gate 		for (i = 0; i < pshot_devices_len && pshot_devices[i].name;
29887c478bd9Sstevel@tonic-gate 		    i++) {
29897c478bd9Sstevel@tonic-gate 			if (strcmp(cname, pshot_devices[i].name) == 0) {
29907c478bd9Sstevel@tonic-gate 				compat_name = pshot_devices[i].compat;
29917c478bd9Sstevel@tonic-gate 				nodetype = pshot_devices[i].nodetype;
29927c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
29937c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: %s %s %s\n",
29947c478bd9Sstevel@tonic-gate 					    ddi_get_instance(parent), cname,
29957c478bd9Sstevel@tonic-gate 					    compat_name, nodetype);
29967c478bd9Sstevel@tonic-gate 				}
29977c478bd9Sstevel@tonic-gate 				if ((ndi_prop_update_string_array(
29987c478bd9Sstevel@tonic-gate 				    DDI_DEV_T_NONE, child, "compatible",
29997c478bd9Sstevel@tonic-gate 				    &compat_name, 1)) != DDI_PROP_SUCCESS) {
30007c478bd9Sstevel@tonic-gate 					(void) ndi_devi_free(child);
30017c478bd9Sstevel@tonic-gate 					return (NDI_FAILURE);
30027c478bd9Sstevel@tonic-gate 				}
30037c478bd9Sstevel@tonic-gate 				if ((ndi_prop_update_string(
30047c478bd9Sstevel@tonic-gate 				    DDI_DEV_T_NONE, child, "node-type",
30057c478bd9Sstevel@tonic-gate 				    nodetype)) != DDI_PROP_SUCCESS) {
30067c478bd9Sstevel@tonic-gate 					(void) ndi_devi_free(child);
30077c478bd9Sstevel@tonic-gate 					return (NDI_FAILURE);
30087c478bd9Sstevel@tonic-gate 				}
30097c478bd9Sstevel@tonic-gate 			}
30107c478bd9Sstevel@tonic-gate 		}
30117c478bd9Sstevel@tonic-gate 	}
30127c478bd9Sstevel@tonic-gate 
30137c478bd9Sstevel@tonic-gate 	rval = ndi_devi_bind_driver(child, 0);
30147c478bd9Sstevel@tonic-gate 	if (rval != NDI_SUCCESS) {
30157c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
30167c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent), cname);
30177c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
30187c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
30197c478bd9Sstevel@tonic-gate 	}
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate 	/*
30227c478bd9Sstevel@tonic-gate 	 * create the "no-involuntary-power-cycles" or
30237c478bd9Sstevel@tonic-gate 	 * the "dependency-property" property
30247c478bd9Sstevel@tonic-gate 	 */
30257c478bd9Sstevel@tonic-gate 	(void) pshot_leaf_properties(parent, child, cname, caddr);
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
30287c478bd9Sstevel@tonic-gate }
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate /*
30317c478bd9Sstevel@tonic-gate  * Handle some special cases for testing bus_config via pshot
30327c478bd9Sstevel@tonic-gate  *
30337c478bd9Sstevel@tonic-gate  * Match these special address formats to behavior:
30347c478bd9Sstevel@tonic-gate  *
30357c478bd9Sstevel@tonic-gate  *	err.*		- induce bus_config error
30367c478bd9Sstevel@tonic-gate  *	delay		- induce 1 second of bus_config delay time
30377c478bd9Sstevel@tonic-gate  *	delay,n		- induce n seconds of bus_config delay time
30387c478bd9Sstevel@tonic-gate  *	wait		- induce 1 second of bus_config wait time
30397c478bd9Sstevel@tonic-gate  *	wait,n		- induce n seconds of bus_config wait time
30407c478bd9Sstevel@tonic-gate  *	failinit.*	- induce error at INITCHILD
30417c478bd9Sstevel@tonic-gate  *	failprobe.*	- induce error at probe
30427c478bd9Sstevel@tonic-gate  *	failattach.*	- induce error at attach
30437c478bd9Sstevel@tonic-gate  */
30447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
30457c478bd9Sstevel@tonic-gate static int
pshot_bus_config_test_specials(dev_info_t * parent,char * devname,char * cname,char * caddr)30467c478bd9Sstevel@tonic-gate pshot_bus_config_test_specials(dev_info_t *parent, char *devname,
3047*d5ebc493SDan Cross     char *cname, char *caddr)
30487c478bd9Sstevel@tonic-gate {
30497c478bd9Sstevel@tonic-gate 	char	*p;
30507c478bd9Sstevel@tonic-gate 	int	n;
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate 	if (strncmp(caddr, "err", 3) == 0) {
30537c478bd9Sstevel@tonic-gate 		if (pshot_debug)
30547c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
30557c478bd9Sstevel@tonic-gate 			    "pshot%d: %s forced failure\n",
305619397407SSherry Moore 			    ddi_get_instance(parent), devname);
30577c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
30587c478bd9Sstevel@tonic-gate 	}
30597c478bd9Sstevel@tonic-gate 
30607c478bd9Sstevel@tonic-gate 	/*
30617c478bd9Sstevel@tonic-gate 	 * The delay and wait strings have the same effect.
30627c478bd9Sstevel@tonic-gate 	 * The "wait[,]" support should be removed once the
30637c478bd9Sstevel@tonic-gate 	 * devfs test suites are fixed.
30647c478bd9Sstevel@tonic-gate 	 * NOTE: delay should not be called from interrupt context
30657c478bd9Sstevel@tonic-gate 	 */
30667c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
30677c478bd9Sstevel@tonic-gate 
30687c478bd9Sstevel@tonic-gate 	if (strncmp(caddr, "delay,", 6) == 0) {
30697c478bd9Sstevel@tonic-gate 		p = caddr+6;
30707c478bd9Sstevel@tonic-gate 		n = stoi(&p);
30717c478bd9Sstevel@tonic-gate 		if (*p != 0)
30727c478bd9Sstevel@tonic-gate 			n = 1;
30737c478bd9Sstevel@tonic-gate 		if (pshot_debug)
30747c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
30757c478bd9Sstevel@tonic-gate 			    "pshot%d: %s delay %d second\n",
307619397407SSherry Moore 			    ddi_get_instance(parent), devname, n);
30777c478bd9Sstevel@tonic-gate 		delay(n * drv_usectohz(1000000));
30787c478bd9Sstevel@tonic-gate 	} else if (strncmp(caddr, "delay", 5) == 0) {
30797c478bd9Sstevel@tonic-gate 		if (pshot_debug)
30807c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
30817c478bd9Sstevel@tonic-gate 			    "pshot%d: %s delay 1 second\n",
308219397407SSherry Moore 			    ddi_get_instance(parent), devname);
30837c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
30847c478bd9Sstevel@tonic-gate 	} else if (strncmp(caddr, "wait,", 5) == 0) {
30857c478bd9Sstevel@tonic-gate 		p = caddr+5;
30867c478bd9Sstevel@tonic-gate 		n = stoi(&p);
30877c478bd9Sstevel@tonic-gate 		if (*p != 0)
30887c478bd9Sstevel@tonic-gate 			n = 1;
30897c478bd9Sstevel@tonic-gate 		if (pshot_debug)
30907c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
30917c478bd9Sstevel@tonic-gate 			    "pshot%d: %s wait %d second\n",
309219397407SSherry Moore 			    ddi_get_instance(parent), devname, n);
30937c478bd9Sstevel@tonic-gate 		delay(n * drv_usectohz(1000000));
30947c478bd9Sstevel@tonic-gate 	} else if (strncmp(caddr, "wait", 4) == 0) {
30957c478bd9Sstevel@tonic-gate 		if (pshot_debug)
30967c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
30977c478bd9Sstevel@tonic-gate 			    "pshot%d: %s wait 1 second\n",
30987c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent), devname);
30997c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
31007c478bd9Sstevel@tonic-gate 	}
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
31037c478bd9Sstevel@tonic-gate }
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate /*
31067c478bd9Sstevel@tonic-gate  * translate nodetype name to actual value
31077c478bd9Sstevel@tonic-gate  */
31087c478bd9Sstevel@tonic-gate static char *
pshot_str2nt(char * str)31097c478bd9Sstevel@tonic-gate pshot_str2nt(char *str)
31107c478bd9Sstevel@tonic-gate {
31117c478bd9Sstevel@tonic-gate 	int i;
31127c478bd9Sstevel@tonic-gate 
31137c478bd9Sstevel@tonic-gate 	for (i = 0; pshot_nodetypes[i].name; i++) {
31147c478bd9Sstevel@tonic-gate 		if (strcmp(pshot_nodetypes[i].name, str) == 0)
31157c478bd9Sstevel@tonic-gate 			return (pshot_nodetypes[i].val);
31167c478bd9Sstevel@tonic-gate 	}
31177c478bd9Sstevel@tonic-gate 	return (NULL);
31187c478bd9Sstevel@tonic-gate }
31197c478bd9Sstevel@tonic-gate 
31207c478bd9Sstevel@tonic-gate /*
31217c478bd9Sstevel@tonic-gate  * grows array pointed to by <dstp>, with <src> data
31227c478bd9Sstevel@tonic-gate  * <dstlen> = # elements of the original <*dstp>
31237c478bd9Sstevel@tonic-gate  * <srclen> = # elements of <src>
31247c478bd9Sstevel@tonic-gate  *
31257c478bd9Sstevel@tonic-gate  * on success, returns 0 and a pointer to the new array through <dstp> with
31267c478bd9Sstevel@tonic-gate  * <srclen> + <dstlen> number of elements;
31277c478bd9Sstevel@tonic-gate  * else returns non-zero
31287c478bd9Sstevel@tonic-gate  *
31297c478bd9Sstevel@tonic-gate  * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
31307c478bd9Sstevel@tonic-gate  */
31317c478bd9Sstevel@tonic-gate static int
pshot_devices_grow(pshot_device_t ** dstp,size_t dstlen,const pshot_device_t * src,size_t srclen)31327c478bd9Sstevel@tonic-gate pshot_devices_grow(pshot_device_t **dstp, size_t dstlen,
31337c478bd9Sstevel@tonic-gate     const pshot_device_t *src, size_t srclen)
31347c478bd9Sstevel@tonic-gate {
31357c478bd9Sstevel@tonic-gate 	size_t i;
31367c478bd9Sstevel@tonic-gate 	pshot_device_t *newdst;
31377c478bd9Sstevel@tonic-gate 
31387c478bd9Sstevel@tonic-gate 	newdst = kmem_alloc((srclen + dstlen) * sizeof (*src),
31397c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 	/* keep old pointers and dup new ones */
31427c478bd9Sstevel@tonic-gate 	if (*dstp)
31437c478bd9Sstevel@tonic-gate 		bcopy(*dstp, newdst, dstlen * sizeof (*src));
31447c478bd9Sstevel@tonic-gate 	for (i = 0; i < srclen; i++) {
31457c478bd9Sstevel@tonic-gate 		newdst[i + dstlen].name =
31467c478bd9Sstevel@tonic-gate 		    i_ddi_strdup(src[i].name, KM_SLEEP);
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 		newdst[i + dstlen].nodetype =
31497c478bd9Sstevel@tonic-gate 		    i_ddi_strdup(src[i].nodetype, KM_SLEEP);
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate 		newdst[i + dstlen].compat =
31527c478bd9Sstevel@tonic-gate 		    i_ddi_strdup(src[i].compat, KM_SLEEP);
31537c478bd9Sstevel@tonic-gate 	}
31547c478bd9Sstevel@tonic-gate 
31557c478bd9Sstevel@tonic-gate 	/* do last */
31567c478bd9Sstevel@tonic-gate 	if (*dstp)
31577c478bd9Sstevel@tonic-gate 		kmem_free(*dstp, dstlen * sizeof (*src));
31587c478bd9Sstevel@tonic-gate 	*dstp = newdst;
31597c478bd9Sstevel@tonic-gate 	return (0);
31607c478bd9Sstevel@tonic-gate }
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate /*
31637c478bd9Sstevel@tonic-gate  * free a pshot_device_t array <dp> with <len> elements
31647c478bd9Sstevel@tonic-gate  * null pointers within the elements are ok
31657c478bd9Sstevel@tonic-gate  */
31667c478bd9Sstevel@tonic-gate static void
pshot_devices_free(pshot_device_t * dp,size_t len)31677c478bd9Sstevel@tonic-gate pshot_devices_free(pshot_device_t *dp, size_t len)
31687c478bd9Sstevel@tonic-gate {
31697c478bd9Sstevel@tonic-gate 	size_t i;
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
31727c478bd9Sstevel@tonic-gate 		if (dp[i].name)
31737c478bd9Sstevel@tonic-gate 			kmem_free(dp[i].name, strlen(dp[i].name) + 1);
31747c478bd9Sstevel@tonic-gate 		if (dp[i].nodetype)
31757c478bd9Sstevel@tonic-gate 			kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1);
31767c478bd9Sstevel@tonic-gate 		if (dp[i].compat)
31777c478bd9Sstevel@tonic-gate 			kmem_free(dp[i].compat, strlen(dp[i].compat) + 1);
31787c478bd9Sstevel@tonic-gate 	}
31797c478bd9Sstevel@tonic-gate 	kmem_free(dp, len * sizeof (*dp));
31807c478bd9Sstevel@tonic-gate }
31817c478bd9Sstevel@tonic-gate 
31827c478bd9Sstevel@tonic-gate /*
31837c478bd9Sstevel@tonic-gate  * returns an array of pshot_device_t parsed from <dip>'s properties
31847c478bd9Sstevel@tonic-gate  *
31857c478bd9Sstevel@tonic-gate  * property structure (i.e. pshot.conf) for pshot:
31867c478bd9Sstevel@tonic-gate  *
31877c478bd9Sstevel@tonic-gate  * corresponding         |   pshot_device_t array elements
31887c478bd9Sstevel@tonic-gate  * pshot_device_t        |
31897c478bd9Sstevel@tonic-gate  * member by prop name   |   [0]            [1]           [2]
31907c478bd9Sstevel@tonic-gate  * ----------------------|--------------|-------------|-----------------------
31917c478bd9Sstevel@tonic-gate  * <PSHOT_PROP_DEVNAME>  ="disk",        "tape",       "testdev";
31927c478bd9Sstevel@tonic-gate  * <PSHOT_PROP_DEVNT>    ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
31937c478bd9Sstevel@tonic-gate  * <PSHOT_PROP_DEVCOMPAT>="testdrv",     "testdrv",    "testdrv";
31947c478bd9Sstevel@tonic-gate  *
31957c478bd9Sstevel@tonic-gate  *
31967c478bd9Sstevel@tonic-gate  * if any of these properties are specified, then:
31977c478bd9Sstevel@tonic-gate  * - all the members must be specified
31987c478bd9Sstevel@tonic-gate  * - the number of elements for each string array property must be the same
31997c478bd9Sstevel@tonic-gate  * - no empty strings allowed
32007c478bd9Sstevel@tonic-gate  * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
32017c478bd9Sstevel@tonic-gate  *   sys/sunddi.h
32027c478bd9Sstevel@tonic-gate  *
32037c478bd9Sstevel@tonic-gate  * NOTE: the pshot_nodetypes[] table should be kept in sync with the list
32047c478bd9Sstevel@tonic-gate  * of ddi nodetypes.  It's not normally critical to always be in sync so
32057c478bd9Sstevel@tonic-gate  * keeping this up-to-date can usually be done "on-demand".
32067c478bd9Sstevel@tonic-gate  *
32077c478bd9Sstevel@tonic-gate  * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
32087c478bd9Sstevel@tonic-gate  * these will be duplicated verbatim
32097c478bd9Sstevel@tonic-gate  */
32107c478bd9Sstevel@tonic-gate static pshot_device_t *
pshot_devices_from_props(dev_info_t * dip,size_t * lenp,int flags)32117c478bd9Sstevel@tonic-gate pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags)
32127c478bd9Sstevel@tonic-gate {
32137c478bd9Sstevel@tonic-gate 	pshot_device_t *devarr = NULL;
32147c478bd9Sstevel@tonic-gate 	char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL;
32157c478bd9Sstevel@tonic-gate 	uint_t name_arr_len, nt_arr_len, compat_arr_len;
32167c478bd9Sstevel@tonic-gate 	uint_t i;
32177c478bd9Sstevel@tonic-gate 	char *str;
32187c478bd9Sstevel@tonic-gate 
32197c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
32207c478bd9Sstevel@tonic-gate 	    PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) !=
32217c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
32227c478bd9Sstevel@tonic-gate 		name_arr = NULL;
32237c478bd9Sstevel@tonic-gate 
32247c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
32257c478bd9Sstevel@tonic-gate 	    PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) !=
32267c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
32277c478bd9Sstevel@tonic-gate 		nt_arr = NULL;
32287c478bd9Sstevel@tonic-gate 
32297c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
32307c478bd9Sstevel@tonic-gate 	    PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) !=
32317c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
32327c478bd9Sstevel@tonic-gate 		compat_arr = NULL;
32337c478bd9Sstevel@tonic-gate 
32347c478bd9Sstevel@tonic-gate 	/*
32357c478bd9Sstevel@tonic-gate 	 * warn about any incorrect usage, if specified
32367c478bd9Sstevel@tonic-gate 	 */
32377c478bd9Sstevel@tonic-gate 	if (!(name_arr || nt_arr || compat_arr))
32387c478bd9Sstevel@tonic-gate 		return (NULL);
32397c478bd9Sstevel@tonic-gate 
32407c478bd9Sstevel@tonic-gate 	if (!(name_arr && nt_arr && compat_arr) ||
32417c478bd9Sstevel@tonic-gate 	    (name_arr_len != nt_arr_len) ||
32427c478bd9Sstevel@tonic-gate 	    (name_arr_len != compat_arr_len))
32437c478bd9Sstevel@tonic-gate 		goto FAIL;
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 	for (i = 0; i < name_arr_len; i++) {
32467c478bd9Sstevel@tonic-gate 		if (*name_arr[i] == '\0' ||
32477c478bd9Sstevel@tonic-gate 		    *nt_arr[i] == '\0' ||
32487c478bd9Sstevel@tonic-gate 		    *compat_arr[i] == '\0')
32497c478bd9Sstevel@tonic-gate 			goto FAIL;
32507c478bd9Sstevel@tonic-gate 	}
32517c478bd9Sstevel@tonic-gate 
32527c478bd9Sstevel@tonic-gate 	devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP);
32537c478bd9Sstevel@tonic-gate 	for (i = 0; i < name_arr_len; i++) {
32547c478bd9Sstevel@tonic-gate 		devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP);
32557c478bd9Sstevel@tonic-gate 		devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP);
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 		if ((str = pshot_str2nt(nt_arr[i])) == NULL)
32587c478bd9Sstevel@tonic-gate 			if (flags & PSHOT_DEV_ANYNT)
32597c478bd9Sstevel@tonic-gate 				str = nt_arr[i];
32607c478bd9Sstevel@tonic-gate 			else
32617c478bd9Sstevel@tonic-gate 				goto FAIL;
32627c478bd9Sstevel@tonic-gate 		devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP);
32637c478bd9Sstevel@tonic-gate 	}
32647c478bd9Sstevel@tonic-gate 	ddi_prop_free(name_arr);
32657c478bd9Sstevel@tonic-gate 	ddi_prop_free(nt_arr);
32667c478bd9Sstevel@tonic-gate 	ddi_prop_free(compat_arr);
32677c478bd9Sstevel@tonic-gate 
32687c478bd9Sstevel@tonic-gate 	/* set <*lenp> ONLY on success */
32697c478bd9Sstevel@tonic-gate 	*lenp = name_arr_len;
32707c478bd9Sstevel@tonic-gate 
32717c478bd9Sstevel@tonic-gate 	return (devarr);
32727c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
32737c478bd9Sstevel@tonic-gate FAIL:
32747c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "malformed device specification property");
32757c478bd9Sstevel@tonic-gate 	if (name_arr)
32767c478bd9Sstevel@tonic-gate 		ddi_prop_free(name_arr);
32777c478bd9Sstevel@tonic-gate 	if (nt_arr)
32787c478bd9Sstevel@tonic-gate 		ddi_prop_free(nt_arr);
32797c478bd9Sstevel@tonic-gate 	if (compat_arr)
32807c478bd9Sstevel@tonic-gate 		ddi_prop_free(compat_arr);
32817c478bd9Sstevel@tonic-gate 	if (devarr)
32827c478bd9Sstevel@tonic-gate 		pshot_devices_free(devarr, name_arr_len);
32837c478bd9Sstevel@tonic-gate 	return (NULL);
32847c478bd9Sstevel@tonic-gate }
32857c478bd9Sstevel@tonic-gate 
32867c478bd9Sstevel@tonic-gate /*
32877c478bd9Sstevel@tonic-gate  * if global <pshot_devices> was not set up already (i.e. is NULL):
32887c478bd9Sstevel@tonic-gate  *	sets up global <pshot_devices> and <pshot_devices_len>,
32897c478bd9Sstevel@tonic-gate  *	using device properties	from <dip> and global <pshot_stock_devices>.
32907c478bd9Sstevel@tonic-gate  *	device properties, if any, overrides pshot_stock_devices.
32917c478bd9Sstevel@tonic-gate  *
32927c478bd9Sstevel@tonic-gate  * returns 0 on success (or if pshot_devices already set up)
32937c478bd9Sstevel@tonic-gate  *
32947c478bd9Sstevel@tonic-gate  * INTERNAL LOCKING: <pshot_devices_lock>
32957c478bd9Sstevel@tonic-gate  */
32967c478bd9Sstevel@tonic-gate static int
pshot_devices_setup(dev_info_t * dip)32977c478bd9Sstevel@tonic-gate pshot_devices_setup(dev_info_t *dip)
32987c478bd9Sstevel@tonic-gate {
32997c478bd9Sstevel@tonic-gate 	pshot_device_t *newdevs = NULL;
33007c478bd9Sstevel@tonic-gate 	size_t newdevs_len = 0;
33017c478bd9Sstevel@tonic-gate 	int rv = 0;
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot_devices_lock);
33047c478bd9Sstevel@tonic-gate 	if (pshot_devices != NULL)
33057c478bd9Sstevel@tonic-gate 		goto FAIL;
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 	ASSERT(pshot_devices_len == 0);
33087c478bd9Sstevel@tonic-gate 
33097c478bd9Sstevel@tonic-gate 	newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT);
33107c478bd9Sstevel@tonic-gate 	rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices,
33117c478bd9Sstevel@tonic-gate 	    PSHOT_N_STOCK_DEVICES);
33127c478bd9Sstevel@tonic-gate 	if (rv != 0) {
33137c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow "
33147c478bd9Sstevel@tonic-gate 		    "failed");
33157c478bd9Sstevel@tonic-gate 		goto FAIL;
33167c478bd9Sstevel@tonic-gate 	}
33177c478bd9Sstevel@tonic-gate 	newdevs_len += PSHOT_N_STOCK_DEVICES;
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate 	pshot_devices = newdevs;
33207c478bd9Sstevel@tonic-gate 	pshot_devices_len = newdevs_len;
33217c478bd9Sstevel@tonic-gate 	rv = 0;
33227c478bd9Sstevel@tonic-gate FAIL:
33237c478bd9Sstevel@tonic-gate 	if (rv && newdevs)
33247c478bd9Sstevel@tonic-gate 		pshot_devices_free(newdevs, newdevs_len);
33257c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot_devices_lock);
33267c478bd9Sstevel@tonic-gate 	return (rv);
33277c478bd9Sstevel@tonic-gate }
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate #ifdef NOTNEEDED
33317c478bd9Sstevel@tonic-gate /* ARGSUSED */
33327c478bd9Sstevel@tonic-gate static int
pshot_probe_family(dev_info_t * self,ddi_probe_method_t probe_how,dev_info_t ** return_dip)33337c478bd9Sstevel@tonic-gate pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how,
33347c478bd9Sstevel@tonic-gate     dev_info_t **return_dip)
33357c478bd9Sstevel@tonic-gate {
33367c478bd9Sstevel@tonic-gate 	char name[64];
33377c478bd9Sstevel@tonic-gate 	uint_t bus_id;
33387c478bd9Sstevel@tonic-gate 	dev_info_t *child;
33397c478bd9Sstevel@tonic-gate 
33407c478bd9Sstevel@tonic-gate 	for (bus_id = 10; bus_id < 20; bus_id++) {
33417c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "%d", bus_id);
33427c478bd9Sstevel@tonic-gate 		if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID,
33437c478bd9Sstevel@tonic-gate 		    &child)) != NDI_SUCCESS) {
33447c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
33457c478bd9Sstevel@tonic-gate 		}
33467c478bd9Sstevel@tonic-gate 
33477c478bd9Sstevel@tonic-gate 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
33487c478bd9Sstevel@tonic-gate 		    "bus-addr", name) != DDI_PROP_SUCCESS) {
33497c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(child);
33507c478bd9Sstevel@tonic-gate 			if (return_dip != NULL)
33517c478bd9Sstevel@tonic-gate 				*return_dip = (dev_info_t *)NULL;
33527c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
33537c478bd9Sstevel@tonic-gate 		}
33547c478bd9Sstevel@tonic-gate 
33557c478bd9Sstevel@tonic-gate 		if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
33567c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
33577c478bd9Sstevel@tonic-gate 		}
33587c478bd9Sstevel@tonic-gate 	}
33597c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
33607c478bd9Sstevel@tonic-gate }
33617c478bd9Sstevel@tonic-gate 
33627c478bd9Sstevel@tonic-gate static int
strtoi(char * str)33637c478bd9Sstevel@tonic-gate strtoi(char *str)
33647c478bd9Sstevel@tonic-gate {
33657c478bd9Sstevel@tonic-gate 	int c;
33667c478bd9Sstevel@tonic-gate 	int val;
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate 	for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
33697c478bd9Sstevel@tonic-gate 		val *= 10;
33707c478bd9Sstevel@tonic-gate 		val += c - '0';
33717c478bd9Sstevel@tonic-gate 	}
33727c478bd9Sstevel@tonic-gate 	return (val);
33737c478bd9Sstevel@tonic-gate }
33747c478bd9Sstevel@tonic-gate 
3375b1dd958fScth #endif
33767c478bd9Sstevel@tonic-gate 
33777c478bd9Sstevel@tonic-gate static void
pshot_setup_autoattach(dev_info_t * devi)33787c478bd9Sstevel@tonic-gate pshot_setup_autoattach(dev_info_t *devi)
33797c478bd9Sstevel@tonic-gate {
33807c478bd9Sstevel@tonic-gate 	dev_info_t *l1child, *l2child;
33817c478bd9Sstevel@tonic-gate 	int rv;
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child);
33847c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS) {
33857c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
33867c478bd9Sstevel@tonic-gate 		    "bus-addr", "0");
33877c478bd9Sstevel@tonic-gate 		rv =  ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID,
33887c478bd9Sstevel@tonic-gate 		    &l2child);
33897c478bd9Sstevel@tonic-gate 		if (rv == NDI_SUCCESS)
33907c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
33917c478bd9Sstevel@tonic-gate 			    l2child, "bus-addr", "99");
33927c478bd9Sstevel@tonic-gate 	}
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child);
33957c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
33967c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
33977c478bd9Sstevel@tonic-gate 		    "bus-addr", "99");
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child);
34007c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
34017c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
34027c478bd9Sstevel@tonic-gate 		    "bus-addr", "99");
34037c478bd9Sstevel@tonic-gate 
34047c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child);
34057c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
34067c478bd9Sstevel@tonic-gate 		(void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID,
34077c478bd9Sstevel@tonic-gate 		    &l2child);
34087c478bd9Sstevel@tonic-gate }
34097c478bd9Sstevel@tonic-gate 
34107c478bd9Sstevel@tonic-gate #ifdef PRUNE_SNUBS
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate #define	PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \
34137c478bd9Sstevel@tonic-gate 	(DEVI_PROM_NODE((d)->devi_nodeid)) && \
34147c478bd9Sstevel@tonic-gate 	((d)->devi_addr == NULL))
34157c478bd9Sstevel@tonic-gate /*
34167c478bd9Sstevel@tonic-gate  * test code to remove OBP nodes that have not attached
34177c478bd9Sstevel@tonic-gate  */
34187c478bd9Sstevel@tonic-gate static void
prune_snubs(const char * name)34197c478bd9Sstevel@tonic-gate prune_snubs(const char *name)
34207c478bd9Sstevel@tonic-gate {
34217c478bd9Sstevel@tonic-gate 	struct dev_info *nex_dip, *cdip, *cndip;
34227c478bd9Sstevel@tonic-gate 	int maj;
34237c478bd9Sstevel@tonic-gate 	int rv;
34247c478bd9Sstevel@tonic-gate 
34257c478bd9Sstevel@tonic-gate 	maj = ddi_name_to_major((char *)name);
34267c478bd9Sstevel@tonic-gate 	if (maj != -1) {
34277c478bd9Sstevel@tonic-gate 		nex_dip = (struct dev_info *)devnamesp[maj].dn_head;
34287c478bd9Sstevel@tonic-gate 		while (nex_dip != NULL) {
34297c478bd9Sstevel@tonic-gate 			cndip = ddi_get_child(nex_dip);
34307c478bd9Sstevel@tonic-gate 			while ((cdip = cndip) != NULL) {
34317c478bd9Sstevel@tonic-gate 				cndip = cdip->devi_sibling;
34327c478bd9Sstevel@tonic-gate 				if (PRUNE_THIS_NODE(cdip)) {
34337c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE,
34347c478bd9Sstevel@tonic-gate 					    "parent %s@%s pruning node %s",
34357c478bd9Sstevel@tonic-gate 					    nex_dip->devi_node_name,
34367c478bd9Sstevel@tonic-gate 					    nex_dip->devi_addr,
34377c478bd9Sstevel@tonic-gate 					    cdip->devi_node_name);
34387c478bd9Sstevel@tonic-gate 					rv = ndi_devi_offline(cdip,
34397c478bd9Sstevel@tonic-gate 					    NDI_DEVI_REMOVE);
34407c478bd9Sstevel@tonic-gate 					if (rv != NDI_SUCCESS)
34417c478bd9Sstevel@tonic-gate 						cmn_err(CE_NOTE,
34427c478bd9Sstevel@tonic-gate 						    "failed to prune node, "
34437c478bd9Sstevel@tonic-gate 						    "err %d", rv);
34447c478bd9Sstevel@tonic-gate 				}
34457c478bd9Sstevel@tonic-gate 			}
34467c478bd9Sstevel@tonic-gate 		nex_dip = nex_dip->devi_next;
34477c478bd9Sstevel@tonic-gate 		}
34487c478bd9Sstevel@tonic-gate 	}
34497c478bd9Sstevel@tonic-gate }
34507c478bd9Sstevel@tonic-gate 
34517c478bd9Sstevel@tonic-gate #endif /* PRUBE_SNUBS */
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate #ifdef KERNEL_DEVICE_TREE_WALKER
34547c478bd9Sstevel@tonic-gate static kthread_id_t pwt;
34557c478bd9Sstevel@tonic-gate static kmutex_t pwl;
34567c478bd9Sstevel@tonic-gate static kcondvar_t pwcv;
34577c478bd9Sstevel@tonic-gate 
34587c478bd9Sstevel@tonic-gate static void
pshot_walk_tree()34597c478bd9Sstevel@tonic-gate pshot_walk_tree()
34607c478bd9Sstevel@tonic-gate {
34617c478bd9Sstevel@tonic-gate 	static int pshot_devnode(dev_info_t *dip, void * arg);
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate 	dev_info_t *root = ddi_root_node();
34647c478bd9Sstevel@tonic-gate 	ddi_walk_devs(root, pshot_devnode, NULL);
34657c478bd9Sstevel@tonic-gate }
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate static void
pshot_walk_thread()34687c478bd9Sstevel@tonic-gate pshot_walk_thread()
34697c478bd9Sstevel@tonic-gate {
34707c478bd9Sstevel@tonic-gate 	static void pshot_timeout(void *arg);
34717c478bd9Sstevel@tonic-gate 	static kthread_id_t pwt;
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 	pwt = curthread;
34747c478bd9Sstevel@tonic-gate 	mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL);
34757c478bd9Sstevel@tonic-gate 	cv_init(&pwcv, NULL, CV_DRIVER, NULL);
34767c478bd9Sstevel@tonic-gate 
34777c478bd9Sstevel@tonic-gate 	while (1) {
34787c478bd9Sstevel@tonic-gate 		pshot_walk_tree();
34797c478bd9Sstevel@tonic-gate 		mutex_enter(&pwl);
34807c478bd9Sstevel@tonic-gate 		(void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000));
34817c478bd9Sstevel@tonic-gate 		cv_wait(&pwcv, &pwl);
34827c478bd9Sstevel@tonic-gate 		mutex_exit(&pwl);
34837c478bd9Sstevel@tonic-gate 	}
34847c478bd9Sstevel@tonic-gate }
34857c478bd9Sstevel@tonic-gate 
34867c478bd9Sstevel@tonic-gate static void
pshot_timeout(void * arg)34877c478bd9Sstevel@tonic-gate pshot_timeout(void *arg)
34887c478bd9Sstevel@tonic-gate {
34897c478bd9Sstevel@tonic-gate 	mutex_enter(&pwl);
34907c478bd9Sstevel@tonic-gate 	cv_signal(&pwcv);
34917c478bd9Sstevel@tonic-gate 	mutex_exit(&pwl);
34927c478bd9Sstevel@tonic-gate }
34937c478bd9Sstevel@tonic-gate 
34947c478bd9Sstevel@tonic-gate static int
pshot_devnode(dev_info_t * dip,void * arg)34957c478bd9Sstevel@tonic-gate pshot_devnode(dev_info_t *dip, void *arg)
34967c478bd9Sstevel@tonic-gate {
34977c478bd9Sstevel@tonic-gate 	dev_info_t *f_dip;
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 	if (dip != ddi_root_node()) {
35007c478bd9Sstevel@tonic-gate 		f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent,
35017c478bd9Sstevel@tonic-gate 		    DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr);
35027c478bd9Sstevel@tonic-gate 		if (f_dip != dip) {
35037c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!pshot_devnode: failed lookup"
350419397407SSherry Moore 			    "node (%s/%s@%s)\n",
350519397407SSherry Moore 			    DEVI(DEVI(dip)->devi_parent)->devi_node_name,
350619397407SSherry Moore 			    (DEVI(dip)->devi_node_name ?
350719397407SSherry Moore 			    DEVI(dip)->devi_node_name : "NULL"),
350819397407SSherry Moore 			    (DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr :
350919397407SSherry Moore 			    "NULL"));
35107c478bd9Sstevel@tonic-gate 		}
35117c478bd9Sstevel@tonic-gate 	}
35127c478bd9Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
35137c478bd9Sstevel@tonic-gate }
35147c478bd9Sstevel@tonic-gate #endif /* KERNEL_DEVICE_TREE_WALKER */
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate #ifdef DEBUG
35177c478bd9Sstevel@tonic-gate static void
pshot_event_cb_test(dev_info_t * dip,ddi_eventcookie_t cookie,void * arg,void * bus_impldata)35187c478bd9Sstevel@tonic-gate pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie,
3519*d5ebc493SDan Cross     void *arg, void *bus_impldata)
35207c478bd9Sstevel@tonic-gate {
35217c478bd9Sstevel@tonic-gate 	pshot_t *softstate = (pshot_t *)arg;
35227c478bd9Sstevel@tonic-gate 	int event_tag;
35237c478bd9Sstevel@tonic-gate 
35247c478bd9Sstevel@tonic-gate 	/* look up the event */
35257c478bd9Sstevel@tonic-gate 	event_tag = NDI_EVENT_TAG(cookie);
35267c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot_event_cb_test:\n\t"
35277c478bd9Sstevel@tonic-gate 	    "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
35287c478bd9Sstevel@tonic-gate 	    "arg = 0x%p bus_impl = 0x%p\n",
35297c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie),
35307c478bd9Sstevel@tonic-gate 	    event_tag, (void *)softstate, (void *)bus_impldata);
35317c478bd9Sstevel@tonic-gate 
35327c478bd9Sstevel@tonic-gate }
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate static void
pshot_event_test(void * arg)35357c478bd9Sstevel@tonic-gate pshot_event_test(void *arg)
35367c478bd9Sstevel@tonic-gate {
35377c478bd9Sstevel@tonic-gate 	pshot_t *pshot = (pshot_t *)arg;
35387c478bd9Sstevel@tonic-gate 	ndi_event_hdl_t hdl;
35397c478bd9Sstevel@tonic-gate 	ndi_event_set_t	events;
35407c478bd9Sstevel@tonic-gate 	int i, rval;
35417c478bd9Sstevel@tonic-gate 
35427c478bd9Sstevel@tonic-gate 	(void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP);
35437c478bd9Sstevel@tonic-gate 
35447c478bd9Sstevel@tonic-gate 	events.ndi_events_version = NDI_EVENTS_REV1;
35457c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
35467c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
35477c478bd9Sstevel@tonic-gate 
35487c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
35497c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35507c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35517c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35527c478bd9Sstevel@tonic-gate 
35537c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
35547c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35557c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35567c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35577c478bd9Sstevel@tonic-gate 
35587c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
35597c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35607c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
35617c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate 
35647c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
35657c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35667c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
35677c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35687c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35697c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35707c478bd9Sstevel@tonic-gate 
35717c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
35727c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35737c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
35747c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
35757c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35767c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35777c478bd9Sstevel@tonic-gate 
35787c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
35797c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35807c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
35817c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35827c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
35837c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35847c478bd9Sstevel@tonic-gate 
35857c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
35867c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35877c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
35887c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35897c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
35907c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35917c478bd9Sstevel@tonic-gate 
35927c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
35937c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
35947c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
35957c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
35967c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
35977c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
35987c478bd9Sstevel@tonic-gate 
35997c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
36007c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36017c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
36027c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36037c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
36047c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding first 2 events\n");
36077c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36087c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
36097c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36107c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36117c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36127c478bd9Sstevel@tonic-gate 
36137c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n");
36147c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36157c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
36167c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36177c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36187c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  middle 2 events\n");
36217c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36227c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
36237c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
36247c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36257c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding those 2 events back\n");
36287c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36297c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
36307c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
36317c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
36327c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
36337c478bd9Sstevel@tonic-gate 
36347c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  2 events\n");
36357c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36367c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
36377c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
36387c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36397c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36407c478bd9Sstevel@tonic-gate 
36417c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
36427c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36437c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
36447c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36457c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36467c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36497c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36507c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
36517c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[2];
36527c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36537c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36567c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36577c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
36587c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[3];
36597c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36607c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36617c478bd9Sstevel@tonic-gate 
36627c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36637c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36647c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
36657c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[6];
36667c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36677c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36687c478bd9Sstevel@tonic-gate 
36697c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
36707c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36717c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
36727c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[7];
36737c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
36747c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
36777c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
36787c478bd9Sstevel@tonic-gate 
36797c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
36807c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36817c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
36827c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
36837c478bd9Sstevel@tonic-gate 
36847c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: adding 8 callbacks\n");
36857c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
36867c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
36877c478bd9Sstevel@tonic-gate 		rval = ndi_event_add_callback(hdl, pshot->dip,
368819397407SSherry Moore 		    ndi_event_tag_to_cookie(hdl,
368919397407SSherry Moore 		    pshot_test_events[i].ndi_event_tag),
369019397407SSherry Moore 		    pshot_event_cb_test,
369119397407SSherry Moore 		    (void *)(uintptr_t)pshot_test_events[i].ndi_event_tag,
369219397407SSherry Moore 		    NDI_SLEEP, &pshot->test_callback_cache[i]);
36937c478bd9Sstevel@tonic-gate 		ASSERT(rval == NDI_SUCCESS);
36947c478bd9Sstevel@tonic-gate 	}
36957c478bd9Sstevel@tonic-gate 
36967c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: event callbacks\n");
36977c478bd9Sstevel@tonic-gate 
36987c478bd9Sstevel@tonic-gate 	for (i = 10; i < 18; i++) {
36997c478bd9Sstevel@tonic-gate 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate 		rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie,
37027c478bd9Sstevel@tonic-gate 		    (void *)hdl);
37037c478bd9Sstevel@tonic-gate 
37047c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
370519397407SSherry Moore 		    i, rval);
37067c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
37077c478bd9Sstevel@tonic-gate 	}
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: redo event callbacks\n");
37107c478bd9Sstevel@tonic-gate 
37117c478bd9Sstevel@tonic-gate 	for (i = 10; i < 18; i++) {
37127c478bd9Sstevel@tonic-gate 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
37137c478bd9Sstevel@tonic-gate 
37147c478bd9Sstevel@tonic-gate 		rval = ndi_event_run_callbacks(hdl,
371519397407SSherry Moore 		    pshot->dip, cookie, (void *)hdl);
37167c478bd9Sstevel@tonic-gate 
37177c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
371819397407SSherry Moore 		    i, rval);
37197c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
37207c478bd9Sstevel@tonic-gate 	}
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: removing 8 callbacks\n");
37237c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
37247c478bd9Sstevel@tonic-gate 
37257c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
37267c478bd9Sstevel@tonic-gate 		(void) ndi_event_remove_callback(hdl,
37277c478bd9Sstevel@tonic-gate 		    pshot->test_callback_cache[i]);
37287c478bd9Sstevel@tonic-gate 
37297c478bd9Sstevel@tonic-gate 		pshot->test_callback_cache[i] = 0;
37307c478bd9Sstevel@tonic-gate 	}
37317c478bd9Sstevel@tonic-gate 
37327c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: freeing handle with bound set\n");
37337c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
37347c478bd9Sstevel@tonic-gate 
37357c478bd9Sstevel@tonic-gate 	rval =	ndi_event_free_hdl(hdl);
37367c478bd9Sstevel@tonic-gate 
37377c478bd9Sstevel@tonic-gate 	ASSERT(rval == NDI_SUCCESS);
37387c478bd9Sstevel@tonic-gate 
37397c478bd9Sstevel@tonic-gate }
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate void
pshot_event_test_post_one(void * arg)37427c478bd9Sstevel@tonic-gate pshot_event_test_post_one(void *arg)
37437c478bd9Sstevel@tonic-gate {
37447c478bd9Sstevel@tonic-gate 	pshot_t	*pshot = (pshot_t *)arg;
37457c478bd9Sstevel@tonic-gate 	int rval;
37467c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
37477c478bd9Sstevel@tonic-gate 
37487c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n",
374919397407SSherry Moore 	    pshot->instance);
37507c478bd9Sstevel@tonic-gate 
37517c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST,
37527c478bd9Sstevel@tonic-gate 	    &cookie) != DDI_SUCCESS) {
37537c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found");
37547c478bd9Sstevel@tonic-gate 		return;
37557c478bd9Sstevel@tonic-gate 	}
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 	rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL);
37587c478bd9Sstevel@tonic-gate 
37597c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n",
376019397407SSherry Moore 	    pshot->instance, rval);
37617c478bd9Sstevel@tonic-gate 
37627c478bd9Sstevel@tonic-gate 	(void) timeout(pshot_event_test_post_one, (void *)pshot,
376319397407SSherry Moore 	    pshot->instance * drv_usectohz(60000000));
37647c478bd9Sstevel@tonic-gate 
37657c478bd9Sstevel@tonic-gate }
37667c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3767