xref: /titanic_50/usr/src/uts/common/io/pshot.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * pseudo bus nexus driver
29*7c478bd9Sstevel@tonic-gate  * hotplug framework test facility
30*7c478bd9Sstevel@tonic-gate  */
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * The pshot driver can be used to exercise the i/o framework together
35*7c478bd9Sstevel@tonic-gate  * with devfs by configuring an arbitrarily complex device tree.
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * The pshot driver is rooted at /devices/pshot.  The following commands
38*7c478bd9Sstevel@tonic-gate  * illustrate the operation of devfs together with pshot's bus_config.
39*7c478bd9Sstevel@tonic-gate  * The first command demonstrates that, like the magician showing there's
40*7c478bd9Sstevel@tonic-gate  * nothing up his sleeve, /devices/pshot is empty.  The second command
41*7c478bd9Sstevel@tonic-gate  * conjures up a branch of pshot nodes.  Note that pshot's bus_config is
42*7c478bd9Sstevel@tonic-gate  * called sequentially by devfs for each node, as part of the pathname
43*7c478bd9Sstevel@tonic-gate  * resolution, and that each pshot node is fully configured and
44*7c478bd9Sstevel@tonic-gate  * attached before that node's bus_config is called to configure the
45*7c478bd9Sstevel@tonic-gate  * next child down the tree.  The final result is a "disk" node configured
46*7c478bd9Sstevel@tonic-gate  * at the bottom of the named hierarchy of pshot nodes.
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  *	#
49*7c478bd9Sstevel@tonic-gate  *	# ls /devices/pshot
50*7c478bd9Sstevel@tonic-gate  *	#
51*7c478bd9Sstevel@tonic-gate  *	# ls -ld /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
52*7c478bd9Sstevel@tonic-gate  *	drwxr-xr-x   2 root     sys          512 Feb  6 15:10
53*7c478bd9Sstevel@tonic-gate  *		/devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
54*7c478bd9Sstevel@tonic-gate  *
55*7c478bd9Sstevel@tonic-gate  * pshot supports some unique behaviors as aids for test error cases.
56*7c478bd9Sstevel@tonic-gate  *
57*7c478bd9Sstevel@tonic-gate  * Match these special address formats to behavior:
58*7c478bd9Sstevel@tonic-gate  *
59*7c478bd9Sstevel@tonic-gate  *	err.*		- induce bus_config error
60*7c478bd9Sstevel@tonic-gate  *	delay		- induce 1 second of bus_config delay time
61*7c478bd9Sstevel@tonic-gate  *	delay,n		- induce n seconds of bus_config delay time
62*7c478bd9Sstevel@tonic-gate  *	wait		- induce 1 second of bus_config wait time
63*7c478bd9Sstevel@tonic-gate  *	wait,n		- induce n seconds of bus_config wait time
64*7c478bd9Sstevel@tonic-gate  *	failinit.*	- induce error at INITCHILD
65*7c478bd9Sstevel@tonic-gate  *	failprobe.*	- induce error at probe
66*7c478bd9Sstevel@tonic-gate  *	failattach.*	- induce error at attach
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG)
70*7c478bd9Sstevel@tonic-gate #define	DEBUG	1
71*7c478bd9Sstevel@tonic-gate #endif
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
74*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
78*7c478bd9Sstevel@tonic-gate #include <sys/open.h>
79*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
80*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
81*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
82*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
83*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
84*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
85*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
86*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
87*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
88*7c478bd9Sstevel@tonic-gate #include <sys/devctl.h>
89*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
90*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
91*7c478bd9Sstevel@tonic-gate #include <sys/pshot.h>
92*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate static int pshot_log		= 0;
95*7c478bd9Sstevel@tonic-gate static int pshot_devctl_debug	= 0;
96*7c478bd9Sstevel@tonic-gate static int pshot_debug_busy	= 0;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate static void *pshot_softstatep;
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate static int pshot_prop_autoattach;
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #define	MAXPWR	3
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * device configuration data
107*7c478bd9Sstevel@tonic-gate  */
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /* should keep in sync with current release */
110*7c478bd9Sstevel@tonic-gate static struct {
111*7c478bd9Sstevel@tonic-gate 	char *name;
112*7c478bd9Sstevel@tonic-gate 	char *val;
113*7c478bd9Sstevel@tonic-gate } pshot_nodetypes[] = {
114*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL", DDI_NT_SERIAL},
115*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB},
116*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO},
117*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO},
118*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON},
119*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK", DDI_NT_BLOCK},
120*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN},
121*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN},
122*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_CD", DDI_NT_CD},
123*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN},
124*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_FD", DDI_NT_FD},
125*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE},
126*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE},
127*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_TAPE", DDI_NT_TAPE},
128*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_NET", DDI_NT_NET},
129*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_DISPLAY", DDI_NT_DISPLAY},
130*7c478bd9Sstevel@tonic-gate 	{"DDI_PSEUDO", DDI_PSEUDO},
131*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_AUDIO", DDI_NT_AUDIO},
132*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_MOUSE", DDI_NT_MOUSE},
133*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD},
134*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_PARALLEL", DDI_NT_PARALLEL},
135*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_PRINTER", DDI_NT_PRINTER},
136*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_UGEN", DDI_NT_UGEN},
137*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_NEXUS", DDI_NT_NEXUS},
138*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS},
139*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT},
140*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT},
141*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT},
142*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT},
143*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT},
144*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT},
145*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC},
146*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_SMARTCARD_READER", DDI_NT_SMARTCARD_READER},
147*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC},
148*7c478bd9Sstevel@tonic-gate 	{"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH},
149*7c478bd9Sstevel@tonic-gate 	{ NULL, NULL }
150*7c478bd9Sstevel@tonic-gate };
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate /* Node name */
153*7c478bd9Sstevel@tonic-gate static char *pshot_compat_diskname = "cdisk";
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate /* Compatible names... */
156*7c478bd9Sstevel@tonic-gate static char *pshot_compat_psramdisks[] = {
157*7c478bd9Sstevel@tonic-gate 	"psramhead",
158*7c478bd9Sstevel@tonic-gate 	"psramrom",
159*7c478bd9Sstevel@tonic-gate 	"psramdisk",
160*7c478bd9Sstevel@tonic-gate 	"psramd",
161*7c478bd9Sstevel@tonic-gate 	"psramwhat"
162*7c478bd9Sstevel@tonic-gate };
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate /*
165*7c478bd9Sstevel@tonic-gate  * devices "natively" supported by pshot (i.e. included with SUNWiotu)
166*7c478bd9Sstevel@tonic-gate  * used to initialize pshot_devices with
167*7c478bd9Sstevel@tonic-gate  */
168*7c478bd9Sstevel@tonic-gate static pshot_device_t pshot_stock_devices[] = {
169*7c478bd9Sstevel@tonic-gate 	{"disk",	DDI_NT_BLOCK,		"gen_drv"},
170*7c478bd9Sstevel@tonic-gate 	{"disk_chan",	DDI_NT_BLOCK_CHAN,	"gen_drv"},
171*7c478bd9Sstevel@tonic-gate 	{"disk_wwn",	DDI_NT_BLOCK_WWN,	"gen_drv"},
172*7c478bd9Sstevel@tonic-gate 	{"disk_cdrom",	DDI_NT_CD,		"gen_drv"},
173*7c478bd9Sstevel@tonic-gate 	{"disk_cdrom.chan", DDI_NT_CD_CHAN,	"gen_drv"},
174*7c478bd9Sstevel@tonic-gate /* Note: use bad_drv to force attach errors */
175*7c478bd9Sstevel@tonic-gate 	{"disk_fd",	DDI_NT_FD,		"bad_drv"},
176*7c478bd9Sstevel@tonic-gate 	{"tape",	DDI_NT_TAPE,		"gen_drv"},
177*7c478bd9Sstevel@tonic-gate 	{"net",		DDI_NT_NET,		"gen_drv"},
178*7c478bd9Sstevel@tonic-gate 	{"display",	DDI_NT_DISPLAY,		"gen_drv"},
179*7c478bd9Sstevel@tonic-gate 	{"pseudo",	DDI_PSEUDO,		"gen_drv"},
180*7c478bd9Sstevel@tonic-gate 	{"audio",	DDI_NT_AUDIO,		"gen_drv"},
181*7c478bd9Sstevel@tonic-gate 	{"mouse",	DDI_NT_MOUSE,		"gen_drv"},
182*7c478bd9Sstevel@tonic-gate 	{"keyboard",	DDI_NT_KEYBOARD,	"gen_drv"},
183*7c478bd9Sstevel@tonic-gate 	{"nexus",	DDI_NT_NEXUS,		"pshot"}
184*7c478bd9Sstevel@tonic-gate };
185*7c478bd9Sstevel@tonic-gate #define	PSHOT_N_STOCK_DEVICES \
186*7c478bd9Sstevel@tonic-gate 	(sizeof (pshot_stock_devices) / sizeof (pshot_device_t))
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate static pshot_device_t *pshot_devices = NULL;
189*7c478bd9Sstevel@tonic-gate static size_t pshot_devices_len = 0;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /* protects <pshot_devices>, <pshot_devices_len> */
192*7c478bd9Sstevel@tonic-gate static kmutex_t pshot_devices_lock;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate /*
196*7c478bd9Sstevel@tonic-gate  * event testing
197*7c478bd9Sstevel@tonic-gate  */
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_ndi_event_defs[] = {
200*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_OFFLINE, PSHOT_EVENT_NAME_DEV_OFFLINE,
201*7c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_DEV_RESET, PSHOT_EVENT_NAME_DEV_RESET,
204*7c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_RESET, PSHOT_EVENT_NAME_BUS_RESET,
207*7c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_QUIESCE, PSHOT_EVENT_NAME_BUS_QUIESCE,
210*7c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_UNQUIESCE, PSHOT_EVENT_NAME_BUS_UNQUIESCE,
213*7c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_TEST_POST, PSHOT_EVENT_NAME_BUS_TEST_POST,
216*7c478bd9Sstevel@tonic-gate 	EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }
217*7c478bd9Sstevel@tonic-gate };
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate #define	PSHOT_N_NDI_EVENTS \
221*7c478bd9Sstevel@tonic-gate 	(sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t))
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events[] = {
226*7c478bd9Sstevel@tonic-gate { 10, "test event 0", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
227*7c478bd9Sstevel@tonic-gate { 11, "test event 1", EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
228*7c478bd9Sstevel@tonic-gate { 12, "test event 2", EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
229*7c478bd9Sstevel@tonic-gate { 13, "test event 3", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
230*7c478bd9Sstevel@tonic-gate { 14, "test event 4", EPL_KERNEL, NDI_EVENT_POST_TO_ALL},
231*7c478bd9Sstevel@tonic-gate { 15, "test event 5", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
232*7c478bd9Sstevel@tonic-gate { 16, "test event 6", EPL_KERNEL, NDI_EVENT_POST_TO_ALL },
233*7c478bd9Sstevel@tonic-gate { 17, "test event 7", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }
234*7c478bd9Sstevel@tonic-gate };
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events_high[] = {
237*7c478bd9Sstevel@tonic-gate { 20, "test event high 0", EPL_HIGHLEVEL, NDI_EVENT_POST_TO_ALL}
238*7c478bd9Sstevel@tonic-gate };
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate #define	PSHOT_N_TEST_EVENTS \
241*7c478bd9Sstevel@tonic-gate 	(sizeof (pshot_test_events)/sizeof (ndi_event_definition_t))
242*7c478bd9Sstevel@tonic-gate #endif
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate struct register_events {
245*7c478bd9Sstevel@tonic-gate 	char		*event_name;
246*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t event_cookie;
247*7c478bd9Sstevel@tonic-gate 	void	(*event_callback)
248*7c478bd9Sstevel@tonic-gate 			(dev_info_t *,
249*7c478bd9Sstevel@tonic-gate 			ddi_eventcookie_t,
250*7c478bd9Sstevel@tonic-gate 			void *arg,
251*7c478bd9Sstevel@tonic-gate 			void *impldata);
252*7c478bd9Sstevel@tonic-gate 	ddi_callback_id_t cb_id;
253*7c478bd9Sstevel@tonic-gate };
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate struct register_events pshot_register_events[] = {
256*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 },
257*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 },
258*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 },
259*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 },
260*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 },
261*7c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 }
262*7c478bd9Sstevel@tonic-gate };
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate #define	PSHOT_N_DDI_EVENTS \
265*7c478bd9Sstevel@tonic-gate 	(sizeof (pshot_register_events) / sizeof (struct register_events))
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate static struct register_events pshot_register_test[] = {
271*7c478bd9Sstevel@tonic-gate { "test event 0", 0, pshot_event_cb_test, 0},
272*7c478bd9Sstevel@tonic-gate { "test event 1", 0, pshot_event_cb_test, 0},
273*7c478bd9Sstevel@tonic-gate { "test event 2", 0, pshot_event_cb_test, 0},
274*7c478bd9Sstevel@tonic-gate { "test event 3", 0, pshot_event_cb_test, 0},
275*7c478bd9Sstevel@tonic-gate { "test event 4", 0, pshot_event_cb_test, 0},
276*7c478bd9Sstevel@tonic-gate { "test event 5", 0, pshot_event_cb_test, 0},
277*7c478bd9Sstevel@tonic-gate { "test event 6", 0, pshot_event_cb_test, 0},
278*7c478bd9Sstevel@tonic-gate { "test event 7", 0, pshot_event_cb_test, 0}
279*7c478bd9Sstevel@tonic-gate };
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate static struct register_events pshot_register_high_test[] = {
283*7c478bd9Sstevel@tonic-gate 	{"test event high 0", 0, pshot_event_cb_test, 0}
284*7c478bd9Sstevel@tonic-gate };
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate static struct {
289*7c478bd9Sstevel@tonic-gate 	int ioctl_int;
290*7c478bd9Sstevel@tonic-gate 	char *ioctl_char;
291*7c478bd9Sstevel@tonic-gate } pshot_devctls[] = {
292*7c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"},
293*7c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"},
294*7c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"},
295*7c478bd9Sstevel@tonic-gate 	{DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"},
296*7c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"},
297*7c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"},
298*7c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"},
299*7c478bd9Sstevel@tonic-gate 	{DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"},
300*7c478bd9Sstevel@tonic-gate 	{0, NULL}
301*7c478bd9Sstevel@tonic-gate };
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate static struct bus_ops pshot_bus_ops = {
304*7c478bd9Sstevel@tonic-gate 	BUSO_REV,			/* busops_rev */
305*7c478bd9Sstevel@tonic-gate 	nullbusmap,			/* bus_map */
306*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_get_intrspec */
307*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_add_interspec */
308*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_remove_interspec */
309*7c478bd9Sstevel@tonic-gate 	i_ddi_map_fault,		/* bus_map_fault */
310*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_map,			/* bus_dma_map */
311*7c478bd9Sstevel@tonic-gate 	ddi_no_dma_allochdl,		/* bus_dma_allochdl */
312*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_freehdl */
313*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_bindhdl */
314*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_unbindhdl */
315*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_flush */
316*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_win */
317*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_dma_ctl */
318*7c478bd9Sstevel@tonic-gate 	pshot_ctl,			/* bus_ctl */
319*7c478bd9Sstevel@tonic-gate 	ddi_bus_prop_op,		/* bus_prop_op */
320*7c478bd9Sstevel@tonic-gate 	pshot_get_eventcookie,		/* bus_get_eventcookie */
321*7c478bd9Sstevel@tonic-gate 	pshot_add_eventcall,		/* bus_add_eventcall */
322*7c478bd9Sstevel@tonic-gate 	pshot_remove_eventcall,		/* bus_remove_event */
323*7c478bd9Sstevel@tonic-gate 	pshot_post_event,		/* bus_post_event */
324*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_intr_ctl */
325*7c478bd9Sstevel@tonic-gate 	pshot_bus_config,		/* bus_config */
326*7c478bd9Sstevel@tonic-gate 	pshot_bus_unconfig,		/* bus_unconfig */
327*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_init */
328*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_fini */
329*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_enter */
330*7c478bd9Sstevel@tonic-gate 	NULL,				/* bus_fm_access_exit */
331*7c478bd9Sstevel@tonic-gate 	pshot_bus_power,		/* bus_power */
332*7c478bd9Sstevel@tonic-gate 	pshot_bus_introp		/* bus_intr_op */
333*7c478bd9Sstevel@tonic-gate };
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate static struct cb_ops pshot_cb_ops = {
336*7c478bd9Sstevel@tonic-gate 	pshot_open,			/* open */
337*7c478bd9Sstevel@tonic-gate 	pshot_close,			/* close */
338*7c478bd9Sstevel@tonic-gate 	nodev,				/* strategy */
339*7c478bd9Sstevel@tonic-gate 	nodev,				/* print */
340*7c478bd9Sstevel@tonic-gate 	nodev,				/* dump */
341*7c478bd9Sstevel@tonic-gate 	nodev,				/* read */
342*7c478bd9Sstevel@tonic-gate 	nodev,				/* write */
343*7c478bd9Sstevel@tonic-gate 	pshot_ioctl,			/* ioctl */
344*7c478bd9Sstevel@tonic-gate 	nodev,				/* devmap */
345*7c478bd9Sstevel@tonic-gate 	nodev,				/* mmap */
346*7c478bd9Sstevel@tonic-gate 	nodev,				/* segmap */
347*7c478bd9Sstevel@tonic-gate 	nochpoll,			/* poll */
348*7c478bd9Sstevel@tonic-gate 	ddi_prop_op,			/* prop_op */
349*7c478bd9Sstevel@tonic-gate 	NULL,				/* streamtab */
350*7c478bd9Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* flags */
351*7c478bd9Sstevel@tonic-gate 	CB_REV,				/* cb_rev */
352*7c478bd9Sstevel@tonic-gate 	nodev,				/* aread */
353*7c478bd9Sstevel@tonic-gate 	nodev,				/* awrite */
354*7c478bd9Sstevel@tonic-gate };
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate static struct dev_ops pshot_ops = {
357*7c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
358*7c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
359*7c478bd9Sstevel@tonic-gate 	pshot_info,		/* getinfo */
360*7c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
361*7c478bd9Sstevel@tonic-gate 	pshot_probe,		/* probe */
362*7c478bd9Sstevel@tonic-gate 	pshot_attach,		/* attach */
363*7c478bd9Sstevel@tonic-gate 	pshot_detach,		/* detach */
364*7c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
365*7c478bd9Sstevel@tonic-gate 	&pshot_cb_ops,		/* driver operations */
366*7c478bd9Sstevel@tonic-gate 	&pshot_bus_ops,		/* bus operations */
367*7c478bd9Sstevel@tonic-gate 	pshot_power		/* power */
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate };
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate /*
373*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
374*7c478bd9Sstevel@tonic-gate  */
375*7c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
376*7c478bd9Sstevel@tonic-gate 	&mod_driverops,
377*7c478bd9Sstevel@tonic-gate 	"pshotnex %I%",
378*7c478bd9Sstevel@tonic-gate 	&pshot_ops,
379*7c478bd9Sstevel@tonic-gate };
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
382*7c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
383*7c478bd9Sstevel@tonic-gate };
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate /*
387*7c478bd9Sstevel@tonic-gate  * pshot_devices is set up on the first attach and destroyed on fini
388*7c478bd9Sstevel@tonic-gate  *
389*7c478bd9Sstevel@tonic-gate  * therefore PSHOT_PROP_DEV* properties may be set just for the root device,
390*7c478bd9Sstevel@tonic-gate  * instead of being set globably, in pshot.conf by specifying the properties
391*7c478bd9Sstevel@tonic-gate  * on a single line in the form:
392*7c478bd9Sstevel@tonic-gate  *	name="pshot" parent="/" <dev props ..>
393*7c478bd9Sstevel@tonic-gate  * to unclutter a device tree snapshot.
394*7c478bd9Sstevel@tonic-gate  * this of course produces a long single line that may wrap around several
395*7c478bd9Sstevel@tonic-gate  * times on screen
396*7c478bd9Sstevel@tonic-gate  */
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate int
399*7c478bd9Sstevel@tonic-gate _init(void)
400*7c478bd9Sstevel@tonic-gate {
401*7c478bd9Sstevel@tonic-gate 	int rv;
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	rv = ddi_soft_state_init(&pshot_softstatep, sizeof (pshot_t), 0);
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	if (rv != DDI_SUCCESS)
406*7c478bd9Sstevel@tonic-gate 		return (rv);
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	mutex_init(&pshot_devices_lock, NULL, MUTEX_DRIVER, NULL);
409*7c478bd9Sstevel@tonic-gate 	pshot_devices = NULL;
410*7c478bd9Sstevel@tonic-gate 	pshot_devices_len = 0;
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	if ((rv = mod_install(&modlinkage)) != 0) {
413*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&pshot_softstatep);
414*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&pshot_devices_lock);
415*7c478bd9Sstevel@tonic-gate 	}
416*7c478bd9Sstevel@tonic-gate 	return (rv);
417*7c478bd9Sstevel@tonic-gate }
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate int
420*7c478bd9Sstevel@tonic-gate _fini(void)
421*7c478bd9Sstevel@tonic-gate {
422*7c478bd9Sstevel@tonic-gate 	int rv;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	if ((rv = mod_remove(&modlinkage)) != 0)
425*7c478bd9Sstevel@tonic-gate 		return (rv);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini(&pshot_softstatep);
428*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&pshot_devices_lock);
429*7c478bd9Sstevel@tonic-gate 	if (pshot_devices)
430*7c478bd9Sstevel@tonic-gate 		pshot_devices_free(pshot_devices, pshot_devices_len);
431*7c478bd9Sstevel@tonic-gate 	return (0);
432*7c478bd9Sstevel@tonic-gate }
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate int
435*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
436*7c478bd9Sstevel@tonic-gate {
437*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
442*7c478bd9Sstevel@tonic-gate static int
443*7c478bd9Sstevel@tonic-gate pshot_probe(dev_info_t *devi)
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(devi);
446*7c478bd9Sstevel@tonic-gate 	char	*bus_addr;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	/*
449*7c478bd9Sstevel@tonic-gate 	 * Hook for tests to force probe fail
450*7c478bd9Sstevel@tonic-gate 	 */
451*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
452*7c478bd9Sstevel@tonic-gate 	    &bus_addr) == DDI_PROP_SUCCESS) {
453*7c478bd9Sstevel@tonic-gate 		if (strncmp(bus_addr, "failprobe", 9) == 0) {
454*7c478bd9Sstevel@tonic-gate 			if (pshot_debug)
455*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: "
456*7c478bd9Sstevel@tonic-gate 				    "%s forced probe failure\n",
457*7c478bd9Sstevel@tonic-gate 				    instance, bus_addr);
458*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(bus_addr);
459*7c478bd9Sstevel@tonic-gate 			return (DDI_PROBE_FAILURE);
460*7c478bd9Sstevel@tonic-gate 		}
461*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
462*7c478bd9Sstevel@tonic-gate 	}
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
465*7c478bd9Sstevel@tonic-gate }
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
469*7c478bd9Sstevel@tonic-gate static int
470*7c478bd9Sstevel@tonic-gate pshot_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
471*7c478bd9Sstevel@tonic-gate {
472*7c478bd9Sstevel@tonic-gate 	int instance;
473*7c478bd9Sstevel@tonic-gate 	minor_t minor;
474*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	minor = getminor((dev_t)arg);
477*7c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(minor);
478*7c478bd9Sstevel@tonic-gate 	switch (infocmd) {
479*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
480*7c478bd9Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
481*7c478bd9Sstevel@tonic-gate 		if (pshot == NULL) {
482*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot_info: get soft state failed "
483*7c478bd9Sstevel@tonic-gate 			    "on minor %u, instance %d", minor, instance);
484*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 		*result = (void *)pshot->dip;
487*7c478bd9Sstevel@tonic-gate 		break;
488*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
489*7c478bd9Sstevel@tonic-gate 		*result = (void *)(uintptr_t)instance;
490*7c478bd9Sstevel@tonic-gate 		break;
491*7c478bd9Sstevel@tonic-gate 	default:
492*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_info: unrecognized cmd 0x%x on "
493*7c478bd9Sstevel@tonic-gate 		    "minor %u, instance %d", infocmd, minor, instance);
494*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
495*7c478bd9Sstevel@tonic-gate 	}
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate static int
502*7c478bd9Sstevel@tonic-gate pshot_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
503*7c478bd9Sstevel@tonic-gate {
504*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(devi);
505*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
506*7c478bd9Sstevel@tonic-gate 	int rval, i;
507*7c478bd9Sstevel@tonic-gate 	int prop_flags = DDI_PROP_DONTPASS | DDI_PROP_NOTPROM;
508*7c478bd9Sstevel@tonic-gate 	char *bus_addr;
509*7c478bd9Sstevel@tonic-gate 	char *pm_comp[] = {
510*7c478bd9Sstevel@tonic-gate 		"NAME=bus",
511*7c478bd9Sstevel@tonic-gate 		"0=B3",
512*7c478bd9Sstevel@tonic-gate 		"1=B2",
513*7c478bd9Sstevel@tonic-gate 		"2=B1",
514*7c478bd9Sstevel@tonic-gate 		"3=B0"};
515*7c478bd9Sstevel@tonic-gate 	char *pm_hw_state = {"needs-suspend-resume"};
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	pshot_prop_autoattach = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
518*7c478bd9Sstevel@tonic-gate 	    prop_flags, "autoattach", 0);
519*7c478bd9Sstevel@tonic-gate 
520*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
523*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
524*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "attach: %s%d/pshot%d\n",
525*7c478bd9Sstevel@tonic-gate 				ddi_get_name(ddi_get_parent(devi)),
526*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(ddi_get_parent(devi)),
527*7c478bd9Sstevel@tonic-gate 				instance);
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 		/*
530*7c478bd9Sstevel@tonic-gate 		 * Hook for tests to force attach fail
531*7c478bd9Sstevel@tonic-gate 		 */
532*7c478bd9Sstevel@tonic-gate 		if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
533*7c478bd9Sstevel@tonic-gate 		    &bus_addr) == DDI_PROP_SUCCESS) && bus_addr != NULL) {
534*7c478bd9Sstevel@tonic-gate 			if (strncmp(bus_addr, "failattach", 10) == 0) {
535*7c478bd9Sstevel@tonic-gate 				if (pshot_debug)
536*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: "
537*7c478bd9Sstevel@tonic-gate 					    "%s forced attach failure\n",
538*7c478bd9Sstevel@tonic-gate 					    instance, bus_addr);
539*7c478bd9Sstevel@tonic-gate 				ddi_prop_free(bus_addr);
540*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
541*7c478bd9Sstevel@tonic-gate 			}
542*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(bus_addr);
543*7c478bd9Sstevel@tonic-gate 		}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 		/*
546*7c478bd9Sstevel@tonic-gate 		 * minor nodes setup
547*7c478bd9Sstevel@tonic-gate 		 */
548*7c478bd9Sstevel@tonic-gate 		if (ddi_soft_state_zalloc(pshot_softstatep, instance) !=
549*7c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
550*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
551*7c478bd9Sstevel@tonic-gate 		}
552*7c478bd9Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
553*7c478bd9Sstevel@tonic-gate 		pshot->dip = devi;
554*7c478bd9Sstevel@tonic-gate 		pshot->instance = instance;
555*7c478bd9Sstevel@tonic-gate 		mutex_init(&pshot->lock, NULL, MUTEX_DRIVER, NULL);
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 		/* set each minor, then create on dip all together */
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 		i = PSHOT_NODENUM_DEVCTL;
560*7c478bd9Sstevel@tonic-gate 		pshot->nodes[i].pshot = pshot;
561*7c478bd9Sstevel@tonic-gate 		pshot->nodes[i].minor = pshot_minor_encode(instance, i);
562*7c478bd9Sstevel@tonic-gate 		(void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_DEVCTL,
563*7c478bd9Sstevel@tonic-gate 		    PSHOT_MAX_MINOR_NAMELEN);
564*7c478bd9Sstevel@tonic-gate 
565*7c478bd9Sstevel@tonic-gate 		i = PSHOT_NODENUM_TESTCTL;
566*7c478bd9Sstevel@tonic-gate 		pshot->nodes[i].pshot = pshot;
567*7c478bd9Sstevel@tonic-gate 		pshot->nodes[i].minor = pshot_minor_encode(instance, i);
568*7c478bd9Sstevel@tonic-gate 		(void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_TESTCTL,
569*7c478bd9Sstevel@tonic-gate 		    PSHOT_MAX_MINOR_NAMELEN);
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 		/* this assumes contiguous a filling */
572*7c478bd9Sstevel@tonic-gate 		for (i = 0; i <= PSHOT_MAX_NODENUM; i++) {
573*7c478bd9Sstevel@tonic-gate 			if (ddi_create_minor_node(devi, pshot->nodes[i].name,
574*7c478bd9Sstevel@tonic-gate 			    S_IFCHR, pshot->nodes[i].minor, DDI_NT_NEXUS, 0) !=
575*7c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
576*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "attach: cannot create "
577*7c478bd9Sstevel@tonic-gate 				    "minor %s", pshot->nodes[i].name);
578*7c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
579*7c478bd9Sstevel@tonic-gate 			}
580*7c478bd9Sstevel@tonic-gate 		}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 		/*
583*7c478bd9Sstevel@tonic-gate 		 * pshot_devices setup
584*7c478bd9Sstevel@tonic-gate 		 */
585*7c478bd9Sstevel@tonic-gate 		if (pshot_devices_setup(devi)) {
586*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "attach: pshot devices setup "
587*7c478bd9Sstevel@tonic-gate 			    "failed");
588*7c478bd9Sstevel@tonic-gate 			goto FAIL_ATTACH;
589*7c478bd9Sstevel@tonic-gate 		}
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 		/*
592*7c478bd9Sstevel@tonic-gate 		 * events setup
593*7c478bd9Sstevel@tonic-gate 		 */
594*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
595*7c478bd9Sstevel@tonic-gate 			rval =	ddi_get_eventcookie(devi,
596*7c478bd9Sstevel@tonic-gate 			    pshot_register_events[i].event_name,
597*7c478bd9Sstevel@tonic-gate 			    &pshot_register_events[i].event_cookie);
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 			if (pshot_debug)
600*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: event=%s:"
601*7c478bd9Sstevel@tonic-gate 				    "ddi_get_eventcookie rval=%d\n",
602*7c478bd9Sstevel@tonic-gate 				    instance,
603*7c478bd9Sstevel@tonic-gate 				    pshot_register_events[i].event_name, rval);
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 			if (rval == DDI_SUCCESS) {
606*7c478bd9Sstevel@tonic-gate 				rval = ddi_add_event_handler(devi,
607*7c478bd9Sstevel@tonic-gate 				    pshot_register_events[i].event_cookie,
608*7c478bd9Sstevel@tonic-gate 				    pshot_register_events[i].event_callback,
609*7c478bd9Sstevel@tonic-gate 				    (void *)pshot,
610*7c478bd9Sstevel@tonic-gate 				    &pshot->callback_cache[i]);
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 				if (pshot_debug)
613*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: event=%s: "
614*7c478bd9Sstevel@tonic-gate 					    "ddi_add_event_handler rval=%d\n",
615*7c478bd9Sstevel@tonic-gate 					    instance,
616*7c478bd9Sstevel@tonic-gate 					    pshot_register_events[i].event_name,
617*7c478bd9Sstevel@tonic-gate 					    rval);
618*7c478bd9Sstevel@tonic-gate 			}
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
622*7c478bd9Sstevel@tonic-gate 		if (pshot_event_test_enable) {
623*7c478bd9Sstevel@tonic-gate 			pshot_event_test((void *)pshot);
624*7c478bd9Sstevel@tonic-gate 			(void) timeout(pshot_event_test_post_one, (void *)pshot,
625*7c478bd9Sstevel@tonic-gate 			    instance * drv_usectohz(60000000));
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate #endif
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 		/*
630*7c478bd9Sstevel@tonic-gate 		 * allocate an ndi event handle
631*7c478bd9Sstevel@tonic-gate 		 */
632*7c478bd9Sstevel@tonic-gate 		if (ndi_event_alloc_hdl(devi, NULL, &pshot->ndi_event_hdl,
633*7c478bd9Sstevel@tonic-gate 		    NDI_SLEEP) != NDI_SUCCESS) {
634*7c478bd9Sstevel@tonic-gate 			goto FAIL_ATTACH;
635*7c478bd9Sstevel@tonic-gate 		}
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 		pshot->ndi_events.ndi_events_version = NDI_EVENTS_REV1;
638*7c478bd9Sstevel@tonic-gate 		pshot->ndi_events.ndi_n_events = PSHOT_N_NDI_EVENTS;
639*7c478bd9Sstevel@tonic-gate 		pshot->ndi_events.ndi_event_defs = pshot_ndi_event_defs;
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 		if (ndi_event_bind_set(pshot->ndi_event_hdl, &pshot->ndi_events,
642*7c478bd9Sstevel@tonic-gate 		    NDI_SLEEP) != NDI_SUCCESS) {
643*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d bind set failed\n",
644*7c478bd9Sstevel@tonic-gate 				instance);
645*7c478bd9Sstevel@tonic-gate 		}
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 		/*
648*7c478bd9Sstevel@tonic-gate 		 * setup a test for nexus auto-attach iff we are
649*7c478bd9Sstevel@tonic-gate 		 * a second level pshot node (parent == /SUNW,pshot)
650*7c478bd9Sstevel@tonic-gate 		 * enable by setting "autoattach=1" in pshot.conf
651*7c478bd9Sstevel@tonic-gate 		 */
652*7c478bd9Sstevel@tonic-gate 		if ((PARENT_IS_PSHOT(devi)) && (pshot_prop_autoattach != 0) &&
653*7c478bd9Sstevel@tonic-gate 		    (ddi_get_instance(ddi_get_parent(devi))) == 0)
654*7c478bd9Sstevel@tonic-gate 			pshot_setup_autoattach(devi);
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 		/*
657*7c478bd9Sstevel@tonic-gate 		 * initialize internal state to idle: busy = 0,
658*7c478bd9Sstevel@tonic-gate 		 * power level = -1
659*7c478bd9Sstevel@tonic-gate 		 */
660*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
661*7c478bd9Sstevel@tonic-gate 		pshot->busy = 0;
662*7c478bd9Sstevel@tonic-gate 		pshot->busy_ioctl = 0;
663*7c478bd9Sstevel@tonic-gate 		pshot->level = -1;
664*7c478bd9Sstevel@tonic-gate 		pshot->state &= ~STRICT_PARENT;
665*7c478bd9Sstevel@tonic-gate 		pshot->state |= PM_SUPPORTED;
666*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 		/*
669*7c478bd9Sstevel@tonic-gate 		 * Create the "pm-want-child-notification?" property
670*7c478bd9Sstevel@tonic-gate 		 * for the root node /devices/pshot
671*7c478bd9Sstevel@tonic-gate 		 */
672*7c478bd9Sstevel@tonic-gate 		if (instance == 0) {
673*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
674*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:\n\t"
675*7c478bd9Sstevel@tonic-gate 				    " create the"
676*7c478bd9Sstevel@tonic-gate 				    " \"pm-want-child-notification?\" property"
677*7c478bd9Sstevel@tonic-gate 				    " for the root node\n", instance);
678*7c478bd9Sstevel@tonic-gate 			}
679*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, devi, 0,
680*7c478bd9Sstevel@tonic-gate 			    "pm-want-child-notification?", NULL, 0)
681*7c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
682*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d:\n\t"
683*7c478bd9Sstevel@tonic-gate 				    " unable to create the"
684*7c478bd9Sstevel@tonic-gate 				    " \"pm-want-child-notification?\""
685*7c478bd9Sstevel@tonic-gate 				    " property", ddi_get_name(devi),
686*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
689*7c478bd9Sstevel@tonic-gate 			}
690*7c478bd9Sstevel@tonic-gate 		}
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 		/*
693*7c478bd9Sstevel@tonic-gate 		 * Check if the pm-want-child-notification? property was
694*7c478bd9Sstevel@tonic-gate 		 * created in pshot_bus_config_setup_nexus() by the parent.
695*7c478bd9Sstevel@tonic-gate 		 * Set the STRICT_PARENT flag if not.
696*7c478bd9Sstevel@tonic-gate 		 */
697*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
698*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
699*7c478bd9Sstevel@tonic-gate 		    "pm-want-child-notification?") != 1) {
700*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
701*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
702*7c478bd9Sstevel@tonic-gate 				    " STRICT PARENT\n", instance);
703*7c478bd9Sstevel@tonic-gate 			}
704*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
705*7c478bd9Sstevel@tonic-gate 			pshot->state |= STRICT_PARENT;
706*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
707*7c478bd9Sstevel@tonic-gate 		} else {
708*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
709*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
710*7c478bd9Sstevel@tonic-gate 				    " INVOLVED PARENT\n", instance);
711*7c478bd9Sstevel@tonic-gate 			}
712*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
713*7c478bd9Sstevel@tonic-gate 			pshot->state &= ~STRICT_PARENT;
714*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
715*7c478bd9Sstevel@tonic-gate 		}
716*7c478bd9Sstevel@tonic-gate 
717*7c478bd9Sstevel@tonic-gate 		/*
718*7c478bd9Sstevel@tonic-gate 		 * create the pm-components property: one component
719*7c478bd9Sstevel@tonic-gate 		 * with 4 power levels.
720*7c478bd9Sstevel@tonic-gate 		 * - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict:
721*7c478bd9Sstevel@tonic-gate 		 * "no-pm-components" property
722*7c478bd9Sstevel@tonic-gate 		 */
723*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
724*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
725*7c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 0) {
726*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
727*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
728*7c478bd9Sstevel@tonic-gate 				    " create the \"pm_components\" property\n",
729*7c478bd9Sstevel@tonic-gate 				    instance);
730*7c478bd9Sstevel@tonic-gate 			}
731*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
732*7c478bd9Sstevel@tonic-gate 			    "pm-components", pm_comp, 5) != DDI_PROP_SUCCESS) {
733*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
734*7c478bd9Sstevel@tonic-gate 				    " unable to create the \"pm-components\""
735*7c478bd9Sstevel@tonic-gate 				    " property", ddi_get_name(devi),
736*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
739*7c478bd9Sstevel@tonic-gate 			}
740*7c478bd9Sstevel@tonic-gate 		} else {
741*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
742*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
743*7c478bd9Sstevel@tonic-gate 				    " NO-PM_COMPONENTS PARENT\n", instance);
744*7c478bd9Sstevel@tonic-gate 			}
745*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
746*7c478bd9Sstevel@tonic-gate 			pshot->state &= ~PM_SUPPORTED;
747*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
748*7c478bd9Sstevel@tonic-gate 		}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 		/*
751*7c478bd9Sstevel@tonic-gate 		 * create the property needed to get DDI_SUSPEND
752*7c478bd9Sstevel@tonic-gate 		 * and DDI_RESUME calls
753*7c478bd9Sstevel@tonic-gate 		 */
754*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
755*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
756*7c478bd9Sstevel@tonic-gate 			    " create pm-hardware-state property\n",
757*7c478bd9Sstevel@tonic-gate 			    instance);
758*7c478bd9Sstevel@tonic-gate 		}
759*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
760*7c478bd9Sstevel@tonic-gate 		    "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
761*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
762*7c478bd9Sstevel@tonic-gate 			    " unable to create the \"pm-hardware-state\""
763*7c478bd9Sstevel@tonic-gate 			    " property", ddi_get_name(devi),
764*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(devi));
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 			goto FAIL_ATTACH;
767*7c478bd9Sstevel@tonic-gate 		}
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 		/*
770*7c478bd9Sstevel@tonic-gate 		 * set power level to max via pm_raise_power(),
771*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
772*7c478bd9Sstevel@tonic-gate 		 */
773*7c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
774*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
775*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
776*7c478bd9Sstevel@tonic-gate 				    " raise power to MAXPWR\n", instance);
777*7c478bd9Sstevel@tonic-gate 			}
778*7c478bd9Sstevel@tonic-gate 			if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
779*7c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
780*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_ATTACH:"
781*7c478bd9Sstevel@tonic-gate 				    " pm_raise_power failed",
782*7c478bd9Sstevel@tonic-gate 				    ddi_get_name(devi),
783*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 				goto FAIL_ATTACH;
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 			}
788*7c478bd9Sstevel@tonic-gate 		}
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 		if (pshot_log)
791*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d attached\n", instance);
792*7c478bd9Sstevel@tonic-gate 		ddi_report_dev(devi);
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
795*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
796*7c478bd9Sstevel@tonic-gate FAIL_ATTACH:
797*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
798*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&pshot->lock);
799*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(pshot_softstatep, instance);
800*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
803*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
804*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resuming\n",
805*7c478bd9Sstevel@tonic-gate 			    instance);
806*7c478bd9Sstevel@tonic-gate 		}
807*7c478bd9Sstevel@tonic-gate 		pshot = ddi_get_soft_state(pshot_softstatep, instance);
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 		/*
810*7c478bd9Sstevel@tonic-gate 		 * set power level to max via pm_raise_power(),
811*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
812*7c478bd9Sstevel@tonic-gate 		 */
813*7c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
814*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
815*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_RESUME:"
816*7c478bd9Sstevel@tonic-gate 				    " raise power to MAXPWR\n", instance);
817*7c478bd9Sstevel@tonic-gate 			}
818*7c478bd9Sstevel@tonic-gate 			if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
819*7c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
820*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_RESUME:"
821*7c478bd9Sstevel@tonic-gate 				    " pm_raise_power failed",
822*7c478bd9Sstevel@tonic-gate 				    ddi_get_name(devi),
823*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
824*7c478bd9Sstevel@tonic-gate 			}
825*7c478bd9Sstevel@tonic-gate 		}
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
828*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resumed\n",
829*7c478bd9Sstevel@tonic-gate 			    instance);
830*7c478bd9Sstevel@tonic-gate 		}
831*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	default:
834*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
835*7c478bd9Sstevel@tonic-gate 	}
836*7c478bd9Sstevel@tonic-gate }
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate static int
839*7c478bd9Sstevel@tonic-gate pshot_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(devi);
842*7c478bd9Sstevel@tonic-gate 	int i, rval;
843*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
844*7c478bd9Sstevel@tonic-gate 	int level_tmp;
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate 	if (pshot == NULL)
847*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
852*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
853*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_DETACH\n", instance);
854*7c478bd9Sstevel@tonic-gate 		/*
855*7c478bd9Sstevel@tonic-gate 		 * power off component 0
856*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
857*7c478bd9Sstevel@tonic-gate 		 */
858*7c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
859*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
860*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_DETACH:"
861*7c478bd9Sstevel@tonic-gate 				    " power off\n", instance);
862*7c478bd9Sstevel@tonic-gate 			}
863*7c478bd9Sstevel@tonic-gate 			if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
864*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t"
865*7c478bd9Sstevel@tonic-gate 				    "pm_lower_power failed for comp 0 to"
866*7c478bd9Sstevel@tonic-gate 				    " level 0", ddi_get_name(devi),
867*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(devi));
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
870*7c478bd9Sstevel@tonic-gate 			}
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate 			/*
873*7c478bd9Sstevel@tonic-gate 			 * Check if the power level is actually OFF.
874*7c478bd9Sstevel@tonic-gate 			 * Issue pm_power_has_changed if not.
875*7c478bd9Sstevel@tonic-gate 			 */
876*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
877*7c478bd9Sstevel@tonic-gate 			if (pshot->level != 0) {
878*7c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
879*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE, "pshot%d:"
880*7c478bd9Sstevel@tonic-gate 					    " DDI_DETACH: power off via"
881*7c478bd9Sstevel@tonic-gate 					    " pm_power_has_changed instead\n",
882*7c478bd9Sstevel@tonic-gate 					    instance);
883*7c478bd9Sstevel@tonic-gate 				}
884*7c478bd9Sstevel@tonic-gate 				level_tmp = pshot->level;
885*7c478bd9Sstevel@tonic-gate 				pshot->level = 0;
886*7c478bd9Sstevel@tonic-gate 				if (pm_power_has_changed(pshot->dip, 0, 0) !=
887*7c478bd9Sstevel@tonic-gate 				    DDI_SUCCESS) {
888*7c478bd9Sstevel@tonic-gate 					if (pshot_debug) {
889*7c478bd9Sstevel@tonic-gate 						cmn_err(CE_NOTE, "pshot%d:"
890*7c478bd9Sstevel@tonic-gate 						    " DDI_DETACH:"
891*7c478bd9Sstevel@tonic-gate 						    " pm_power_has_changed"
892*7c478bd9Sstevel@tonic-gate 						    " failed\n", instance);
893*7c478bd9Sstevel@tonic-gate 					}
894*7c478bd9Sstevel@tonic-gate 					pshot->level = level_tmp;
895*7c478bd9Sstevel@tonic-gate 					mutex_exit(&pshot->lock);
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
898*7c478bd9Sstevel@tonic-gate 				}
899*7c478bd9Sstevel@tonic-gate 			}
900*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
901*7c478bd9Sstevel@tonic-gate 		}
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
904*7c478bd9Sstevel@tonic-gate 			if (pshot->callback_cache[i] != NULL) {
905*7c478bd9Sstevel@tonic-gate 				rval = ddi_remove_event_handler(
906*7c478bd9Sstevel@tonic-gate 				    pshot->callback_cache[i]);
907*7c478bd9Sstevel@tonic-gate 				ASSERT(rval == DDI_SUCCESS);
908*7c478bd9Sstevel@tonic-gate 			}
909*7c478bd9Sstevel@tonic-gate 		}
910*7c478bd9Sstevel@tonic-gate 
911*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
912*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) {
913*7c478bd9Sstevel@tonic-gate 			if (pshot->test_callback_cache[i] != NULL) {
914*7c478bd9Sstevel@tonic-gate 				rval = ddi_remove_event_handler(
915*7c478bd9Sstevel@tonic-gate 				    pshot->test_callback_cache[i]);
916*7c478bd9Sstevel@tonic-gate 				ASSERT(rval == DDI_SUCCESS);
917*7c478bd9Sstevel@tonic-gate 			}
918*7c478bd9Sstevel@tonic-gate 		}
919*7c478bd9Sstevel@tonic-gate #endif
920*7c478bd9Sstevel@tonic-gate 		rval = ndi_event_free_hdl(pshot->ndi_event_hdl);
921*7c478bd9Sstevel@tonic-gate 		ASSERT(rval == DDI_SUCCESS);
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 		if (pshot_log)
924*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d detached\n", instance);
925*7c478bd9Sstevel@tonic-gate 
926*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(devi, NULL);
927*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&pshot->lock);
928*7c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(pshot_softstatep, instance);
929*7c478bd9Sstevel@tonic-gate 		break;
930*7c478bd9Sstevel@tonic-gate 
931*7c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
932*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
933*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND\n", instance);
934*7c478bd9Sstevel@tonic-gate 		/*
935*7c478bd9Sstevel@tonic-gate 		 * fail the suspend if FAIL_SUSPEND_FLAG is set.
936*7c478bd9Sstevel@tonic-gate 		 * clear the FAIL_SUSPEND_FLAG flag
937*7c478bd9Sstevel@tonic-gate 		 */
938*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
939*7c478bd9Sstevel@tonic-gate 		if (pshot->state & FAIL_SUSPEND_FLAG) {
940*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
941*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
942*7c478bd9Sstevel@tonic-gate 				" FAIL_SUSPEND_FLAG set, fail suspend\n",
943*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(devi));
944*7c478bd9Sstevel@tonic-gate 			}
945*7c478bd9Sstevel@tonic-gate 			pshot->state &= ~FAIL_SUSPEND_FLAG;
946*7c478bd9Sstevel@tonic-gate 			rval = DDI_FAILURE;
947*7c478bd9Sstevel@tonic-gate 		} else {
948*7c478bd9Sstevel@tonic-gate 			rval = DDI_SUCCESS;
949*7c478bd9Sstevel@tonic-gate 		}
950*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 		/*
953*7c478bd9Sstevel@tonic-gate 		 * power OFF via pm_power_has_changed
954*7c478bd9Sstevel@tonic-gate 		 */
955*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
956*7c478bd9Sstevel@tonic-gate 		if (pshot->state & PM_SUPPORTED) {
957*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
958*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND:"
959*7c478bd9Sstevel@tonic-gate 				    " power off via pm_power_has_changed\n",
960*7c478bd9Sstevel@tonic-gate 				    instance);
961*7c478bd9Sstevel@tonic-gate 			}
962*7c478bd9Sstevel@tonic-gate 			level_tmp = pshot->level;
963*7c478bd9Sstevel@tonic-gate 			pshot->level = 0;
964*7c478bd9Sstevel@tonic-gate 			if (pm_power_has_changed(pshot->dip, 0, 0) !=
965*7c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
966*7c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
967*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE, "pshot%d:"
968*7c478bd9Sstevel@tonic-gate 					    " DDI_SUSPEND:"
969*7c478bd9Sstevel@tonic-gate 					    " pm_power_has_changed failed\n",
970*7c478bd9Sstevel@tonic-gate 					    instance);
971*7c478bd9Sstevel@tonic-gate 				}
972*7c478bd9Sstevel@tonic-gate 				pshot->level = level_tmp;
973*7c478bd9Sstevel@tonic-gate 				rval = DDI_FAILURE;
974*7c478bd9Sstevel@tonic-gate 			}
975*7c478bd9Sstevel@tonic-gate 		}
976*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
977*7c478bd9Sstevel@tonic-gate 		return (rval);
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	default:
980*7c478bd9Sstevel@tonic-gate 		break;
981*7c478bd9Sstevel@tonic-gate 	}
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
984*7c478bd9Sstevel@tonic-gate }
985*7c478bd9Sstevel@tonic-gate 
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate /*
988*7c478bd9Sstevel@tonic-gate  * returns number of bits to represent <val>
989*7c478bd9Sstevel@tonic-gate  */
990*7c478bd9Sstevel@tonic-gate static size_t
991*7c478bd9Sstevel@tonic-gate pshot_numbits(size_t val)
992*7c478bd9Sstevel@tonic-gate {
993*7c478bd9Sstevel@tonic-gate 	size_t bitcnt;
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	if (val == 0)
996*7c478bd9Sstevel@tonic-gate 		return (0);
997*7c478bd9Sstevel@tonic-gate 	for (bitcnt = 1; 1 << bitcnt < val; bitcnt++)
998*7c478bd9Sstevel@tonic-gate 		;
999*7c478bd9Sstevel@tonic-gate 	return (bitcnt);
1000*7c478bd9Sstevel@tonic-gate }
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate /*
1003*7c478bd9Sstevel@tonic-gate  * returns a minor number encoded with instance <inst> and an index <nodenum>
1004*7c478bd9Sstevel@tonic-gate  * that identifies the minor node for this instance
1005*7c478bd9Sstevel@tonic-gate  */
1006*7c478bd9Sstevel@tonic-gate static minor_t
1007*7c478bd9Sstevel@tonic-gate pshot_minor_encode(int inst, minor_t nodenum)
1008*7c478bd9Sstevel@tonic-gate {
1009*7c478bd9Sstevel@tonic-gate 	return (((minor_t)inst << PSHOT_NODENUM_BITS()) |
1010*7c478bd9Sstevel@tonic-gate 	    (((1 << PSHOT_NODENUM_BITS()) - 1) & nodenum));
1011*7c478bd9Sstevel@tonic-gate }
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate /*
1014*7c478bd9Sstevel@tonic-gate  * returns instance of <minor>
1015*7c478bd9Sstevel@tonic-gate  */
1016*7c478bd9Sstevel@tonic-gate static int
1017*7c478bd9Sstevel@tonic-gate pshot_minor_decode_inst(minor_t minor)
1018*7c478bd9Sstevel@tonic-gate {
1019*7c478bd9Sstevel@tonic-gate 	return (minor >> PSHOT_NODENUM_BITS());
1020*7c478bd9Sstevel@tonic-gate }
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate /*
1023*7c478bd9Sstevel@tonic-gate  * returns node number indexing a minor node for the instance in <minor>
1024*7c478bd9Sstevel@tonic-gate  */
1025*7c478bd9Sstevel@tonic-gate static minor_t
1026*7c478bd9Sstevel@tonic-gate pshot_minor_decode_nodenum(minor_t minor)
1027*7c478bd9Sstevel@tonic-gate {
1028*7c478bd9Sstevel@tonic-gate 	return (minor & ((1 << PSHOT_NODENUM_BITS()) - 1));
1029*7c478bd9Sstevel@tonic-gate }
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate /*
1033*7c478bd9Sstevel@tonic-gate  * pshot_bus_introp: pshot convert an interrupt number to an
1034*7c478bd9Sstevel@tonic-gate  *			   interrupt. NO OP for pseudo drivers.
1035*7c478bd9Sstevel@tonic-gate  */
1036*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1037*7c478bd9Sstevel@tonic-gate static int
1038*7c478bd9Sstevel@tonic-gate pshot_bus_introp(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1039*7c478bd9Sstevel@tonic-gate     ddi_intr_handle_impl_t *hdlp, void *result)
1040*7c478bd9Sstevel@tonic-gate {
1041*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
1042*7c478bd9Sstevel@tonic-gate }
1043*7c478bd9Sstevel@tonic-gate static int
1044*7c478bd9Sstevel@tonic-gate pshot_ctl(dev_info_t *dip, dev_info_t *rdip,
1045*7c478bd9Sstevel@tonic-gate     ddi_ctl_enum_t ctlop, void *arg, void *result)
1046*7c478bd9Sstevel@tonic-gate {
1047*7c478bd9Sstevel@tonic-gate 	int instance;
1048*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
1049*7c478bd9Sstevel@tonic-gate 	char *childname;
1050*7c478bd9Sstevel@tonic-gate 	int childinstance;
1051*7c478bd9Sstevel@tonic-gate 	char *name;
1052*7c478bd9Sstevel@tonic-gate 	int circ;
1053*7c478bd9Sstevel@tonic-gate 	struct attachspec *as;
1054*7c478bd9Sstevel@tonic-gate 	struct detachspec *ds;
1055*7c478bd9Sstevel@tonic-gate 	int rval = DDI_SUCCESS;
1056*7c478bd9Sstevel@tonic-gate 	int no_pm_components_child;
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate 	name = ddi_get_name(dip);
1059*7c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
1060*7c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
1061*7c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
1062*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1063*7c478bd9Sstevel@tonic-gate 	}
1064*7c478bd9Sstevel@tonic-gate 
1065*7c478bd9Sstevel@tonic-gate 	switch (ctlop) {
1066*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTDEV:
1067*7c478bd9Sstevel@tonic-gate 		if (rdip == (dev_info_t *)0)
1068*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
1069*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?pshot-device: %s%d\n",
1070*7c478bd9Sstevel@tonic-gate 		    ddi_get_name(rdip), ddi_get_instance(rdip));
1071*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INITCHILD:
1074*7c478bd9Sstevel@tonic-gate 	{
1075*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1078*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "initchild %s%d/%s%d state 0x%x\n",
1079*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), ddi_get_instance(dip),
1080*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(child), ddi_get_instance(child),
1081*7c478bd9Sstevel@tonic-gate 			    DEVI(child)->devi_state);
1082*7c478bd9Sstevel@tonic-gate 		}
1083*7c478bd9Sstevel@tonic-gate 
1084*7c478bd9Sstevel@tonic-gate 		return (pshot_initchild(dip, child));
1085*7c478bd9Sstevel@tonic-gate 	}
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_UNINITCHILD:
1088*7c478bd9Sstevel@tonic-gate 	{
1089*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)arg;
1090*7c478bd9Sstevel@tonic-gate 
1091*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1092*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "uninitchild %s%d/%s%d state 0x%x\n",
1093*7c478bd9Sstevel@tonic-gate 			    ddi_get_name(dip), ddi_get_instance(dip),
1094*7c478bd9Sstevel@tonic-gate 			    ddi_node_name(child), ddi_get_instance(child),
1095*7c478bd9Sstevel@tonic-gate 			    DEVI(child)->devi_state);
1096*7c478bd9Sstevel@tonic-gate 		}
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate 		return (pshot_uninitchild(dip, child));
1099*7c478bd9Sstevel@tonic-gate 	}
1100*7c478bd9Sstevel@tonic-gate 
1101*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DMAPMAPC:
1102*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REPORTINT:
1103*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_REGSIZE:
1104*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NREGS:
1105*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_NINTRS:
1106*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SIDDEV:
1107*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_SLAVEONLY:
1108*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_AFFINITY:
1109*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_INTR_HILEVEL:
1110*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_XLATE_INTRS:
1111*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_POKE:
1112*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PEEK:
1113*7c478bd9Sstevel@tonic-gate 		/*
1114*7c478bd9Sstevel@tonic-gate 		 * These ops correspond to functions that "shouldn't" be called
1115*7c478bd9Sstevel@tonic-gate 		 * by a pseudo driver.  So we whine when we're called.
1116*7c478bd9Sstevel@tonic-gate 		 */
1117*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
1118*7c478bd9Sstevel@tonic-gate 			ddi_get_name(dip), ddi_get_instance(dip),
1119*7c478bd9Sstevel@tonic-gate 			ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
1120*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_ATTACH:
1123*7c478bd9Sstevel@tonic-gate 	{
1124*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)rdip;
1125*7c478bd9Sstevel@tonic-gate 		childname = ddi_node_name(child);
1126*7c478bd9Sstevel@tonic-gate 		childinstance = ddi_get_instance(child);
1127*7c478bd9Sstevel@tonic-gate 		as = (struct attachspec *)arg;
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 		no_pm_components_child = 0;
1130*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1131*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1132*7c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 1) {
1133*7c478bd9Sstevel@tonic-gate 			no_pm_components_child = 1;
1134*7c478bd9Sstevel@tonic-gate 		}
1135*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1136*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n",
1137*7c478bd9Sstevel@tonic-gate 			    name, instance, childname, childinstance,
1138*7c478bd9Sstevel@tonic-gate 			    no_pm_components_child);
1139*7c478bd9Sstevel@tonic-gate 		}
1140*7c478bd9Sstevel@tonic-gate 
1141*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(dip, &circ);
1142*7c478bd9Sstevel@tonic-gate 
1143*7c478bd9Sstevel@tonic-gate 		switch (as->when) {
1144*7c478bd9Sstevel@tonic-gate 		case DDI_PRE:
1145*7c478bd9Sstevel@tonic-gate 			/*
1146*7c478bd9Sstevel@tonic-gate 			 * Mark nexus busy before a child attaches.
1147*7c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1148*7c478bd9Sstevel@tonic-gate 			 * - pshot@XXX,nopm_strict)
1149*7c478bd9Sstevel@tonic-gate 			 */
1150*7c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED))
1151*7c478bd9Sstevel@tonic-gate 				break;
1152*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1153*7c478bd9Sstevel@tonic-gate 			++(pshot->busy);
1154*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1155*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
1156*7c478bd9Sstevel@tonic-gate 				    " ctl_attach_pre: busy for %s%d:"
1157*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
1158*7c478bd9Sstevel@tonic-gate 				    childname, childinstance,
1159*7c478bd9Sstevel@tonic-gate 				    pshot->busy);
1160*7c478bd9Sstevel@tonic-gate 			}
1161*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1162*7c478bd9Sstevel@tonic-gate 			rval = pm_busy_component(dip, 0);
1163*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1164*7c478bd9Sstevel@tonic-gate 			break;
1165*7c478bd9Sstevel@tonic-gate 		case DDI_POST:
1166*7c478bd9Sstevel@tonic-gate 			/*
1167*7c478bd9Sstevel@tonic-gate 			 * Mark nexus idle after a child attaches.
1168*7c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
1169*7c478bd9Sstevel@tonic-gate 			 * - also skip if this is not a stict parent and
1170*7c478bd9Sstevel@tonic-gate 			 * - the child is a tape device or a no-pm-components
1171*7c478bd9Sstevel@tonic-gate 			 * - nexus node.
1172*7c478bd9Sstevel@tonic-gate 			 */
1173*7c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED) ||
1174*7c478bd9Sstevel@tonic-gate 			    (strcmp(childname, "tape") == 0 &&
1175*7c478bd9Sstevel@tonic-gate 			    !(pshot->state & STRICT_PARENT)) ||
1176*7c478bd9Sstevel@tonic-gate 			    no_pm_components_child)
1177*7c478bd9Sstevel@tonic-gate 				break;
1178*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1179*7c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
1180*7c478bd9Sstevel@tonic-gate 			--pshot->busy;
1181*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1182*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
1183*7c478bd9Sstevel@tonic-gate 				    " ctl_attach_post: idle for %s%d:"
1184*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
1185*7c478bd9Sstevel@tonic-gate 				    childname, childinstance,
1186*7c478bd9Sstevel@tonic-gate 				    pshot->busy);
1187*7c478bd9Sstevel@tonic-gate 			}
1188*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1189*7c478bd9Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
1190*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1191*7c478bd9Sstevel@tonic-gate 			break;
1192*7c478bd9Sstevel@tonic-gate 		}
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(dip, circ);
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 		return (rval);
1197*7c478bd9Sstevel@tonic-gate 	}
1198*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_BTOP:
1199*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_BTOPR:
1200*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DETACH:
1201*7c478bd9Sstevel@tonic-gate 		{
1202*7c478bd9Sstevel@tonic-gate 		dev_info_t *child = (dev_info_t *)rdip;
1203*7c478bd9Sstevel@tonic-gate 		childname = ddi_node_name(child);
1204*7c478bd9Sstevel@tonic-gate 		childinstance = ddi_get_instance(child);
1205*7c478bd9Sstevel@tonic-gate 		ds = (struct detachspec *)arg;
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 		no_pm_components_child = 0;
1208*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1209*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1210*7c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 1) {
1211*7c478bd9Sstevel@tonic-gate 			no_pm_components_child = 1;
1212*7c478bd9Sstevel@tonic-gate 		}
1213*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1214*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
1215*7c478bd9Sstevel@tonic-gate 			    "%s%d: ctl_detach %s%d [%d]\n",
1216*7c478bd9Sstevel@tonic-gate 			    name, instance, childname, childinstance,
1217*7c478bd9Sstevel@tonic-gate 			    no_pm_components_child);
1218*7c478bd9Sstevel@tonic-gate 		}
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 		ndi_devi_enter(dip, &circ);
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 		switch (ds->when) {
1223*7c478bd9Sstevel@tonic-gate 		case DDI_PRE:
1224*7c478bd9Sstevel@tonic-gate 			/*
1225*7c478bd9Sstevel@tonic-gate 			 * Mark nexus busy before a child detaches.
1226*7c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1227*7c478bd9Sstevel@tonic-gate 			 * - pshot@XXX,nopm_strict), or if the child is a
1228*7c478bd9Sstevel@tonic-gate 			 * - no-pm-components nexus node.
1229*7c478bd9Sstevel@tonic-gate 			 */
1230*7c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED) ||
1231*7c478bd9Sstevel@tonic-gate 			    (strcmp(childname, "tape") == 0 &&
1232*7c478bd9Sstevel@tonic-gate 			    !(pshot->state & STRICT_PARENT)) ||
1233*7c478bd9Sstevel@tonic-gate 			    no_pm_components_child)
1234*7c478bd9Sstevel@tonic-gate 				break;
1235*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1236*7c478bd9Sstevel@tonic-gate 			++(pshot->busy);
1237*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1238*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
1239*7c478bd9Sstevel@tonic-gate 				    " ctl_detach_pre: busy for %s%d:"
1240*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
1241*7c478bd9Sstevel@tonic-gate 				    childname, childinstance,
1242*7c478bd9Sstevel@tonic-gate 				    pshot->busy);
1243*7c478bd9Sstevel@tonic-gate 			}
1244*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1245*7c478bd9Sstevel@tonic-gate 			rval = pm_busy_component(dip, 0);
1246*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1247*7c478bd9Sstevel@tonic-gate 
1248*7c478bd9Sstevel@tonic-gate 			break;
1249*7c478bd9Sstevel@tonic-gate 		case DDI_POST:
1250*7c478bd9Sstevel@tonic-gate 			/*
1251*7c478bd9Sstevel@tonic-gate 			 * Mark nexus idle after a child detaches.
1252*7c478bd9Sstevel@tonic-gate 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1253*7c478bd9Sstevel@tonic-gate 			 */
1254*7c478bd9Sstevel@tonic-gate 			if (!(pshot->state & PM_SUPPORTED))
1255*7c478bd9Sstevel@tonic-gate 				break;
1256*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1257*7c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
1258*7c478bd9Sstevel@tonic-gate 			--pshot->busy;
1259*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1260*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
1261*7c478bd9Sstevel@tonic-gate 				    " ctl_detach_post: idle for %s%d:"
1262*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
1263*7c478bd9Sstevel@tonic-gate 				    childname, childinstance,
1264*7c478bd9Sstevel@tonic-gate 				    pshot->busy);
1265*7c478bd9Sstevel@tonic-gate 			}
1266*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1267*7c478bd9Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
1268*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 			/*
1271*7c478bd9Sstevel@tonic-gate 			 * Mark the driver idle if the NO_INVOL_FLAG
1272*7c478bd9Sstevel@tonic-gate 			 * is set. This is needed to make sure the
1273*7c478bd9Sstevel@tonic-gate 			 * parent is idle after the child detaches
1274*7c478bd9Sstevel@tonic-gate 			 * without calling pm_lower_power().
1275*7c478bd9Sstevel@tonic-gate 			 * Clear the NO_INVOL_FLAG.
1276*7c478bd9Sstevel@tonic-gate 			 * - also mark idle if a tape device has detached
1277*7c478bd9Sstevel@tonic-gate 			 */
1278*7c478bd9Sstevel@tonic-gate 			if (!(pshot->state & NO_INVOL_FLAG))
1279*7c478bd9Sstevel@tonic-gate 				break;
1280*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1281*7c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
1282*7c478bd9Sstevel@tonic-gate 			--pshot->busy;
1283*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1284*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d:"
1285*7c478bd9Sstevel@tonic-gate 				    " ctl_detach_post: NO_INVOL:"
1286*7c478bd9Sstevel@tonic-gate 				    " idle for %s%d: busy = %d\n",
1287*7c478bd9Sstevel@tonic-gate 				    name, instance, childname,
1288*7c478bd9Sstevel@tonic-gate 				    childinstance, pshot->busy);
1289*7c478bd9Sstevel@tonic-gate 			}
1290*7c478bd9Sstevel@tonic-gate 			pshot->state &= ~NO_INVOL_FLAG;
1291*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1292*7c478bd9Sstevel@tonic-gate 			rval = pm_idle_component(dip, 0);
1293*7c478bd9Sstevel@tonic-gate 			ASSERT(rval == DDI_SUCCESS);
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate 			break;
1296*7c478bd9Sstevel@tonic-gate 		}
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 		ndi_devi_exit(dip, circ);
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 		return (rval);
1301*7c478bd9Sstevel@tonic-gate 	}
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_DVMAPAGESIZE:
1304*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_IOMIN:
1305*7c478bd9Sstevel@tonic-gate 	case DDI_CTLOPS_PTOB:
1306*7c478bd9Sstevel@tonic-gate 	default:
1307*7c478bd9Sstevel@tonic-gate 		/*
1308*7c478bd9Sstevel@tonic-gate 		 * The ops that we pass up (default).  We pass up memory
1309*7c478bd9Sstevel@tonic-gate 		 * allocation oriented ops that we receive - these may be
1310*7c478bd9Sstevel@tonic-gate 		 * associated with pseudo HBA drivers below us with target
1311*7c478bd9Sstevel@tonic-gate 		 * drivers below them that use ddi memory allocation
1312*7c478bd9Sstevel@tonic-gate 		 * interfaces like scsi_alloc_consistent_buf.
1313*7c478bd9Sstevel@tonic-gate 		 */
1314*7c478bd9Sstevel@tonic-gate 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1315*7c478bd9Sstevel@tonic-gate 	}
1316*7c478bd9Sstevel@tonic-gate }
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
1319*7c478bd9Sstevel@tonic-gate static int
1320*7c478bd9Sstevel@tonic-gate pshot_power(dev_info_t *dip, int cmpt, int level)
1321*7c478bd9Sstevel@tonic-gate {
1322*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
1323*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
1324*7c478bd9Sstevel@tonic-gate 	char *name = ddi_node_name(dip);
1325*7c478bd9Sstevel@tonic-gate 	int circ;
1326*7c478bd9Sstevel@tonic-gate 	int rv;
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
1329*7c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1332*7c478bd9Sstevel@tonic-gate 	}
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(dip, &circ);
1335*7c478bd9Sstevel@tonic-gate 
1336*7c478bd9Sstevel@tonic-gate 	/*
1337*7c478bd9Sstevel@tonic-gate 	 * set POWER_FLAG when power() is called.
1338*7c478bd9Sstevel@tonic-gate 	 * ioctl(DEVCT_PM_POWER) is a clear on read call.
1339*7c478bd9Sstevel@tonic-gate 	 */
1340*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
1341*7c478bd9Sstevel@tonic-gate 	pshot->state |= POWER_FLAG;
1342*7c478bd9Sstevel@tonic-gate 	/*
1343*7c478bd9Sstevel@tonic-gate 	 * refuse to power OFF if the component is busy
1344*7c478bd9Sstevel@tonic-gate 	 */
1345*7c478bd9Sstevel@tonic-gate 	if (pshot->busy != 0 && pshot->level > level) {
1346*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE"
1347*7c478bd9Sstevel@tonic-gate 		    " (%d->%d), DEVICE NOT IDLE: busy = %d",
1348*7c478bd9Sstevel@tonic-gate 		    name, instance, pshot->level, level, pshot->busy);
1349*7c478bd9Sstevel@tonic-gate 		rv = DDI_FAILURE;
1350*7c478bd9Sstevel@tonic-gate 	} else {
1351*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1352*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n",
1353*7c478bd9Sstevel@tonic-gate 			    name, instance, cmpt, pshot->level, level);
1354*7c478bd9Sstevel@tonic-gate 		}
1355*7c478bd9Sstevel@tonic-gate 		pshot->level = level;
1356*7c478bd9Sstevel@tonic-gate 		rv = DDI_SUCCESS;
1357*7c478bd9Sstevel@tonic-gate 	}
1358*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(dip, circ);
1361*7c478bd9Sstevel@tonic-gate 
1362*7c478bd9Sstevel@tonic-gate 	return (rv);
1363*7c478bd9Sstevel@tonic-gate }
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate /*ARGSUSED0*/
1366*7c478bd9Sstevel@tonic-gate static int
1367*7c478bd9Sstevel@tonic-gate pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1368*7c478bd9Sstevel@tonic-gate     void *arg, void *result)
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate {
1371*7c478bd9Sstevel@tonic-gate 	int 				ret;
1372*7c478bd9Sstevel@tonic-gate 	int 				instance = ddi_get_instance(dip);
1373*7c478bd9Sstevel@tonic-gate 	char				*name = ddi_node_name(dip);
1374*7c478bd9Sstevel@tonic-gate 	pshot_t 			*pshot;
1375*7c478bd9Sstevel@tonic-gate 	pm_bp_child_pwrchg_t		*bpc;
1376*7c478bd9Sstevel@tonic-gate 	pm_bp_nexus_pwrup_t		bpn;
1377*7c478bd9Sstevel@tonic-gate 	pm_bp_has_changed_t		*bphc;
1378*7c478bd9Sstevel@tonic-gate 	int				pwrup_res;
1379*7c478bd9Sstevel@tonic-gate 	int				ret_failed = 0;
1380*7c478bd9Sstevel@tonic-gate 	int				pwrup_res_failed = 0;
1381*7c478bd9Sstevel@tonic-gate 
1382*7c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
1383*7c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
1384*7c478bd9Sstevel@tonic-gate 
1385*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1386*7c478bd9Sstevel@tonic-gate 	}
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	switch (op) {
1389*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_PRE_NOTIFICATION:
1390*7c478bd9Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
1391*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1392*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1393*7c478bd9Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d)\n",
1394*7c478bd9Sstevel@tonic-gate 			    name, instance, ddi_node_name(bpc->bpc_dip),
1395*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
1396*7c478bd9Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_olevel,
1397*7c478bd9Sstevel@tonic-gate 			    bpc->bpc_nlevel);
1398*7c478bd9Sstevel@tonic-gate 		}
1399*7c478bd9Sstevel@tonic-gate 
1400*7c478bd9Sstevel@tonic-gate 		/*
1401*7c478bd9Sstevel@tonic-gate 		 * mark parent busy if old_level is either -1 or 0,
1402*7c478bd9Sstevel@tonic-gate 		 * and new level is == MAXPWR
1403*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1404*7c478bd9Sstevel@tonic-gate 		 */
1405*7c478bd9Sstevel@tonic-gate 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1406*7c478bd9Sstevel@tonic-gate 		    bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) {
1407*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1408*7c478bd9Sstevel@tonic-gate 			++(pshot->busy);
1409*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1410*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
1411*7c478bd9Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
1412*7c478bd9Sstevel@tonic-gate 				    " busy parent for %s%d (%d->%d): "
1413*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n",
1414*7c478bd9Sstevel@tonic-gate 				    name, instance,
1415*7c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
1416*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
1417*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel,
1418*7c478bd9Sstevel@tonic-gate 				    pshot->busy);
1419*7c478bd9Sstevel@tonic-gate 			}
1420*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1421*7c478bd9Sstevel@tonic-gate 			ret = pm_busy_component(dip, 0);
1422*7c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
1423*7c478bd9Sstevel@tonic-gate 		}
1424*7c478bd9Sstevel@tonic-gate 
1425*7c478bd9Sstevel@tonic-gate 		/*
1426*7c478bd9Sstevel@tonic-gate 		 * if new_level > 0, power up parent, if not already at
1427*7c478bd9Sstevel@tonic-gate 		 * MAXPWR, via pm_busop_bus_power
1428*7c478bd9Sstevel@tonic-gate 		 * - skip for the no-pm nexus (pshot@XXX,nopm)
1429*7c478bd9Sstevel@tonic-gate 		 */
1430*7c478bd9Sstevel@tonic-gate 		if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 &&
1431*7c478bd9Sstevel@tonic-gate 		    pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) {
1432*7c478bd9Sstevel@tonic-gate 			/*
1433*7c478bd9Sstevel@tonic-gate 			 * stuff the bpn struct
1434*7c478bd9Sstevel@tonic-gate 			 */
1435*7c478bd9Sstevel@tonic-gate 			bpn.bpn_comp = 0;
1436*7c478bd9Sstevel@tonic-gate 			bpn.bpn_level = MAXPWR;
1437*7c478bd9Sstevel@tonic-gate 			bpn.bpn_private = bpc->bpc_private;
1438*7c478bd9Sstevel@tonic-gate 			bpn.bpn_dip = dip;
1439*7c478bd9Sstevel@tonic-gate 
1440*7c478bd9Sstevel@tonic-gate 			/*
1441*7c478bd9Sstevel@tonic-gate 			 * ask pm to power parent up
1442*7c478bd9Sstevel@tonic-gate 			 */
1443*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
1444*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1445*7c478bd9Sstevel@tonic-gate 				    " pm_busop_bus_power on parent for %s%d"
1446*7c478bd9Sstevel@tonic-gate 				    " (%d->%d): enter", name, instance,
1447*7c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
1448*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
1449*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
1450*7c478bd9Sstevel@tonic-gate 			}
1451*7c478bd9Sstevel@tonic-gate 			ret = pm_busop_bus_power(dip, impl_arg,
1452*7c478bd9Sstevel@tonic-gate 			    BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1453*7c478bd9Sstevel@tonic-gate 			    (void *)&pwrup_res);
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 			/*
1456*7c478bd9Sstevel@tonic-gate 			 * check the return status individually,
1457*7c478bd9Sstevel@tonic-gate 			 * idle parent and exit if either failed.
1458*7c478bd9Sstevel@tonic-gate 			 */
1459*7c478bd9Sstevel@tonic-gate 			if (ret != DDI_SUCCESS) {
1460*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1461*7c478bd9Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
1462*7c478bd9Sstevel@tonic-gate 				    " pm_busop_bus_power FAILED (ret) FOR"
1463*7c478bd9Sstevel@tonic-gate 				    " %s%d (%d->%d)",
1464*7c478bd9Sstevel@tonic-gate 				    name, instance,
1465*7c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
1466*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
1467*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
1468*7c478bd9Sstevel@tonic-gate 				ret_failed = 1;
1469*7c478bd9Sstevel@tonic-gate 			}
1470*7c478bd9Sstevel@tonic-gate 			if (pwrup_res != DDI_SUCCESS) {
1471*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1472*7c478bd9Sstevel@tonic-gate 				    "%s%d: pre_bus_power:"
1473*7c478bd9Sstevel@tonic-gate 				    " pm_busop_bus_power FAILED (pwrup_res)"
1474*7c478bd9Sstevel@tonic-gate 				    " FOR %s%d (%d->%d)",
1475*7c478bd9Sstevel@tonic-gate 				    name, instance,
1476*7c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
1477*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
1478*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel);
1479*7c478bd9Sstevel@tonic-gate 				pwrup_res_failed = 1;
1480*7c478bd9Sstevel@tonic-gate 			}
1481*7c478bd9Sstevel@tonic-gate 			if (ret_failed || pwrup_res_failed) {
1482*7c478bd9Sstevel@tonic-gate 				/*
1483*7c478bd9Sstevel@tonic-gate 				 * decrement the busy count if it
1484*7c478bd9Sstevel@tonic-gate 				 * had been incremented.
1485*7c478bd9Sstevel@tonic-gate 				 */
1486*7c478bd9Sstevel@tonic-gate 				if ((bpc->bpc_comp == 0 &&
1487*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_nlevel == MAXPWR &&
1488*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel <= 0) &&
1489*7c478bd9Sstevel@tonic-gate 				    (pshot->state & PM_SUPPORTED)) {
1490*7c478bd9Sstevel@tonic-gate 					mutex_enter(&pshot->lock);
1491*7c478bd9Sstevel@tonic-gate 					ASSERT(pshot->busy > 0);
1492*7c478bd9Sstevel@tonic-gate 					--(pshot->busy);
1493*7c478bd9Sstevel@tonic-gate 					if (pshot_debug_busy) {
1494*7c478bd9Sstevel@tonic-gate 						cmn_err(CE_CONT, "%s%d:"
1495*7c478bd9Sstevel@tonic-gate 						    " pm_busop_bus_power"
1496*7c478bd9Sstevel@tonic-gate 						    " failed: idle parent for"
1497*7c478bd9Sstevel@tonic-gate 						    " %s%d (%d->%d):"
1498*7c478bd9Sstevel@tonic-gate 						    " busy = %d\n",
1499*7c478bd9Sstevel@tonic-gate 						    name, instance,
1500*7c478bd9Sstevel@tonic-gate 						    ddi_node_name(
1501*7c478bd9Sstevel@tonic-gate 						    bpc->bpc_dip),
1502*7c478bd9Sstevel@tonic-gate 						    ddi_get_instance(
1503*7c478bd9Sstevel@tonic-gate 						    bpc->bpc_dip),
1504*7c478bd9Sstevel@tonic-gate 						    bpc->bpc_olevel,
1505*7c478bd9Sstevel@tonic-gate 						    bpc->bpc_nlevel,
1506*7c478bd9Sstevel@tonic-gate 						    pshot->busy);
1507*7c478bd9Sstevel@tonic-gate 					}
1508*7c478bd9Sstevel@tonic-gate 					mutex_exit(&pshot->lock);
1509*7c478bd9Sstevel@tonic-gate 					ret = pm_idle_component(dip, 0);
1510*7c478bd9Sstevel@tonic-gate 					ASSERT(ret == DDI_SUCCESS);
1511*7c478bd9Sstevel@tonic-gate 				}
1512*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate 			} else {
1515*7c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
1516*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT,
1517*7c478bd9Sstevel@tonic-gate 					    "%s%d: pre_bus_power:"
1518*7c478bd9Sstevel@tonic-gate 					    " pm_busop_bus_power on parent"
1519*7c478bd9Sstevel@tonic-gate 					    " for %s%d (%d->%d)\n",
1520*7c478bd9Sstevel@tonic-gate 					    name, instance,
1521*7c478bd9Sstevel@tonic-gate 					    ddi_node_name(bpc->bpc_dip),
1522*7c478bd9Sstevel@tonic-gate 					    ddi_get_instance(bpc->bpc_dip),
1523*7c478bd9Sstevel@tonic-gate 					    bpc->bpc_olevel, bpc->bpc_nlevel);
1524*7c478bd9Sstevel@tonic-gate 				}
1525*7c478bd9Sstevel@tonic-gate 			}
1526*7c478bd9Sstevel@tonic-gate 		}
1527*7c478bd9Sstevel@tonic-gate 		break;
1528*7c478bd9Sstevel@tonic-gate 
1529*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_POST_NOTIFICATION:
1530*7c478bd9Sstevel@tonic-gate 		bpc = (pm_bp_child_pwrchg_t *)arg;
1531*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1532*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: post_bus_power:"
1533*7c478bd9Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d) result %d\n",
1534*7c478bd9Sstevel@tonic-gate 			    name, instance, ddi_node_name(bpc->bpc_dip),
1535*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
1536*7c478bd9Sstevel@tonic-gate 			    bpc->bpc_comp, bpc->bpc_olevel,
1537*7c478bd9Sstevel@tonic-gate 			    bpc->bpc_nlevel, *(int *)result);
1538*7c478bd9Sstevel@tonic-gate 		}
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 		/*
1541*7c478bd9Sstevel@tonic-gate 		 * handle pm_busop_bus_power() failure case.
1542*7c478bd9Sstevel@tonic-gate 		 * mark parent idle if had been marked busy.
1543*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1544*7c478bd9Sstevel@tonic-gate 		 */
1545*7c478bd9Sstevel@tonic-gate 		if (*(int *)result != DDI_SUCCESS) {
1546*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1547*7c478bd9Sstevel@tonic-gate 			    "pshot%d: post_bus_power_failed:"
1548*7c478bd9Sstevel@tonic-gate 			    " pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
1549*7c478bd9Sstevel@tonic-gate 			    instance, ddi_node_name(bpc->bpc_dip),
1550*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bpc->bpc_dip),
1551*7c478bd9Sstevel@tonic-gate 			    bpc->bpc_olevel, bpc->bpc_nlevel);
1552*7c478bd9Sstevel@tonic-gate 
1553*7c478bd9Sstevel@tonic-gate 			if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1554*7c478bd9Sstevel@tonic-gate 			    bpc->bpc_olevel <= 0) &&
1555*7c478bd9Sstevel@tonic-gate 			    (pshot->state & PM_SUPPORTED)) {
1556*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pshot->lock);
1557*7c478bd9Sstevel@tonic-gate 				ASSERT(pshot->busy > 0);
1558*7c478bd9Sstevel@tonic-gate 				--(pshot->busy);
1559*7c478bd9Sstevel@tonic-gate 				if (pshot_debug_busy) {
1560*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "%s%d:"
1561*7c478bd9Sstevel@tonic-gate 					    " post_bus_power_failed:"
1562*7c478bd9Sstevel@tonic-gate 					    " idle parent for %s%d"
1563*7c478bd9Sstevel@tonic-gate 					    " (%d->%d): busy = %d\n",
1564*7c478bd9Sstevel@tonic-gate 					    name, instance,
1565*7c478bd9Sstevel@tonic-gate 					    ddi_node_name(bpc->bpc_dip),
1566*7c478bd9Sstevel@tonic-gate 					    ddi_get_instance(bpc->bpc_dip),
1567*7c478bd9Sstevel@tonic-gate 					    bpc->bpc_olevel, bpc->bpc_nlevel,
1568*7c478bd9Sstevel@tonic-gate 					    pshot->busy);
1569*7c478bd9Sstevel@tonic-gate 				}
1570*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pshot->lock);
1571*7c478bd9Sstevel@tonic-gate 				ret = pm_idle_component(dip, 0);
1572*7c478bd9Sstevel@tonic-gate 				ASSERT(ret == DDI_SUCCESS);
1573*7c478bd9Sstevel@tonic-gate 			}
1574*7c478bd9Sstevel@tonic-gate 		}
1575*7c478bd9Sstevel@tonic-gate 
1576*7c478bd9Sstevel@tonic-gate 		/*
1577*7c478bd9Sstevel@tonic-gate 		 * Mark nexus idle when a child's comp 0
1578*7c478bd9Sstevel@tonic-gate 		 * is set to level 0 from level 1, 2, or 3 only.
1579*7c478bd9Sstevel@tonic-gate 		 * And only if result arg == DDI_SUCCESS.
1580*7c478bd9Sstevel@tonic-gate 		 * This will leave the parent busy when the child
1581*7c478bd9Sstevel@tonic-gate 		 * does not call pm_lower_power() on detach after
1582*7c478bd9Sstevel@tonic-gate 		 * unsetting the NO_LOWER_POWER flag.
1583*7c478bd9Sstevel@tonic-gate 		 * If so, need to notify the parent to mark itself
1584*7c478bd9Sstevel@tonic-gate 		 * idle anyway, else the no-involumtary-power-cycles
1585*7c478bd9Sstevel@tonic-gate 		 * test cases will report false passes!
1586*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1587*7c478bd9Sstevel@tonic-gate 		 */
1588*7c478bd9Sstevel@tonic-gate 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 &&
1589*7c478bd9Sstevel@tonic-gate 		    !(bpc->bpc_olevel <= 0) &&
1590*7c478bd9Sstevel@tonic-gate 		    *(int *)result == DDI_SUCCESS) &&
1591*7c478bd9Sstevel@tonic-gate 		    (pshot->state & PM_SUPPORTED)) {
1592*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1593*7c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
1594*7c478bd9Sstevel@tonic-gate 			--(pshot->busy);
1595*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1596*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
1597*7c478bd9Sstevel@tonic-gate 				    "%s%d: post_bus_power:"
1598*7c478bd9Sstevel@tonic-gate 				    " idle parent for %s%d (%d->%d):"
1599*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
1600*7c478bd9Sstevel@tonic-gate 				    ddi_node_name(bpc->bpc_dip),
1601*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bpc->bpc_dip),
1602*7c478bd9Sstevel@tonic-gate 				    bpc->bpc_olevel, bpc->bpc_nlevel,
1603*7c478bd9Sstevel@tonic-gate 				    pshot->busy);
1604*7c478bd9Sstevel@tonic-gate 			}
1605*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1606*7c478bd9Sstevel@tonic-gate 			ret = pm_idle_component(dip, 0);
1607*7c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
1608*7c478bd9Sstevel@tonic-gate 		}
1609*7c478bd9Sstevel@tonic-gate 		break;
1610*7c478bd9Sstevel@tonic-gate 
1611*7c478bd9Sstevel@tonic-gate 	case BUS_POWER_HAS_CHANGED:
1612*7c478bd9Sstevel@tonic-gate 		bphc = (pm_bp_has_changed_t *)arg;
1613*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1614*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "%s%d: has_changed_bus_power:"
1615*7c478bd9Sstevel@tonic-gate 			    " %s%d comp %d (%d->%d) result %d\n",
1616*7c478bd9Sstevel@tonic-gate 			    name, instance, ddi_node_name(bphc->bphc_dip),
1617*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(bphc->bphc_dip),
1618*7c478bd9Sstevel@tonic-gate 			    bphc->bphc_comp, bphc->bphc_olevel,
1619*7c478bd9Sstevel@tonic-gate 			    bphc->bphc_nlevel, *(int *)result);
1620*7c478bd9Sstevel@tonic-gate 		}
1621*7c478bd9Sstevel@tonic-gate 
1622*7c478bd9Sstevel@tonic-gate 		/*
1623*7c478bd9Sstevel@tonic-gate 		 * Mark nexus idle when a child's comp 0
1624*7c478bd9Sstevel@tonic-gate 		 * is set to level 0 from levels 1, 2, or 3 only.
1625*7c478bd9Sstevel@tonic-gate 		 *
1626*7c478bd9Sstevel@tonic-gate 		 * If powering up child leaf/nexus nodes via
1627*7c478bd9Sstevel@tonic-gate 		 * pm_power_has_changed() calls, first issue
1628*7c478bd9Sstevel@tonic-gate 		 * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
1629*7c478bd9Sstevel@tonic-gate 		 * before powering the parent up, then power up the
1630*7c478bd9Sstevel@tonic-gate 		 * child node.
1631*7c478bd9Sstevel@tonic-gate 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1632*7c478bd9Sstevel@tonic-gate 		 */
1633*7c478bd9Sstevel@tonic-gate 		if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 &&
1634*7c478bd9Sstevel@tonic-gate 		    !(bphc->bphc_olevel <= 0)) &&
1635*7c478bd9Sstevel@tonic-gate 		    pshot->state & PM_SUPPORTED) {
1636*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
1637*7c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
1638*7c478bd9Sstevel@tonic-gate 			--(pshot->busy);
1639*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
1640*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT,
1641*7c478bd9Sstevel@tonic-gate 				    "%s%d: has_changed_bus_power:"
1642*7c478bd9Sstevel@tonic-gate 				    " idle parent for %s%d (%d->%d):"
1643*7c478bd9Sstevel@tonic-gate 				    " busy = %d\n", name, instance,
1644*7c478bd9Sstevel@tonic-gate 				    ddi_node_name(bphc->bphc_dip),
1645*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(bphc->bphc_dip),
1646*7c478bd9Sstevel@tonic-gate 				    bphc->bphc_olevel,
1647*7c478bd9Sstevel@tonic-gate 				    bphc->bphc_nlevel, pshot->busy);
1648*7c478bd9Sstevel@tonic-gate 			}
1649*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
1650*7c478bd9Sstevel@tonic-gate 			ret = pm_idle_component(dip, 0);
1651*7c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
1652*7c478bd9Sstevel@tonic-gate 		}
1653*7c478bd9Sstevel@tonic-gate 		break;
1654*7c478bd9Sstevel@tonic-gate 
1655*7c478bd9Sstevel@tonic-gate 	default:
1656*7c478bd9Sstevel@tonic-gate 		return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 	}
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1661*7c478bd9Sstevel@tonic-gate }
1662*7c478bd9Sstevel@tonic-gate 
1663*7c478bd9Sstevel@tonic-gate static int
1664*7c478bd9Sstevel@tonic-gate pshot_initchild(dev_info_t *dip, dev_info_t *child)
1665*7c478bd9Sstevel@tonic-gate {
1666*7c478bd9Sstevel@tonic-gate 	char	name[64];
1667*7c478bd9Sstevel@tonic-gate 	char	*bus_addr;
1668*7c478bd9Sstevel@tonic-gate 	char	*c_nodename;
1669*7c478bd9Sstevel@tonic-gate 	int	bus_id;
1670*7c478bd9Sstevel@tonic-gate 	dev_info_t *enum_child;
1671*7c478bd9Sstevel@tonic-gate 	int	enum_base;
1672*7c478bd9Sstevel@tonic-gate 	int	enum_extent;
1673*7c478bd9Sstevel@tonic-gate 
1674*7c478bd9Sstevel@tonic-gate 
1675*7c478bd9Sstevel@tonic-gate 	/* check for bus_enum node */
1676*7c478bd9Sstevel@tonic-gate 
1677*7c478bd9Sstevel@tonic-gate #ifdef	NOT_USED
1678*7c478bd9Sstevel@tonic-gate 	if (impl_ddi_merge_child(child) != DDI_SUCCESS)
1679*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1680*7c478bd9Sstevel@tonic-gate #endif
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 	enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1683*7c478bd9Sstevel@tonic-gate 	    "busid_ebase", 0);
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate 	enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child,
1686*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "busid_range", 0);
1687*7c478bd9Sstevel@tonic-gate 
1688*7c478bd9Sstevel@tonic-gate 	/*
1689*7c478bd9Sstevel@tonic-gate 	 * bus enumeration node
1690*7c478bd9Sstevel@tonic-gate 	 */
1691*7c478bd9Sstevel@tonic-gate 	if ((enum_base != 0) && (enum_extent != 0))	{
1692*7c478bd9Sstevel@tonic-gate 		c_nodename = ddi_node_name(child);
1693*7c478bd9Sstevel@tonic-gate 		bus_id = enum_base;
1694*7c478bd9Sstevel@tonic-gate 		for (; bus_id < enum_extent; bus_id++) {
1695*7c478bd9Sstevel@tonic-gate 			if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID,
1696*7c478bd9Sstevel@tonic-gate 			    &enum_child) != NDI_SUCCESS)
1697*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate 			(void) sprintf(name, "%d", bus_id);
1700*7c478bd9Sstevel@tonic-gate 			if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child,
1701*7c478bd9Sstevel@tonic-gate 			    "bus-addr", name) != DDI_PROP_SUCCESS) {
1702*7c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(enum_child);
1703*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
1704*7c478bd9Sstevel@tonic-gate 			}
1705*7c478bd9Sstevel@tonic-gate 
1706*7c478bd9Sstevel@tonic-gate 			if (ndi_devi_online(enum_child, 0) !=
1707*7c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
1708*7c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(enum_child);
1709*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
1710*7c478bd9Sstevel@tonic-gate 			}
1711*7c478bd9Sstevel@tonic-gate 		}
1712*7c478bd9Sstevel@tonic-gate 		/*
1713*7c478bd9Sstevel@tonic-gate 		 * fail the enumeration node itself
1714*7c478bd9Sstevel@tonic-gate 		 */
1715*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1716*7c478bd9Sstevel@tonic-gate 	}
1717*7c478bd9Sstevel@tonic-gate 
1718*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr",
1719*7c478bd9Sstevel@tonic-gate 	    &bus_addr) != DDI_PROP_SUCCESS) {
1720*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)",
1721*7c478bd9Sstevel@tonic-gate 		    ddi_node_name(child));
1722*7c478bd9Sstevel@tonic-gate 		return (DDI_NOT_WELL_FORMED);
1723*7c478bd9Sstevel@tonic-gate 	}
1724*7c478bd9Sstevel@tonic-gate 
1725*7c478bd9Sstevel@tonic-gate 	if (strlen(bus_addr) == 0) {
1726*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)",
1727*7c478bd9Sstevel@tonic-gate 		    ddi_node_name(child));
1728*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
1729*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1730*7c478bd9Sstevel@tonic-gate 	}
1731*7c478bd9Sstevel@tonic-gate 
1732*7c478bd9Sstevel@tonic-gate 	if (strncmp(bus_addr, "failinit", 8) == 0) {
1733*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
1734*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
1735*7c478bd9Sstevel@tonic-gate 			    "pshot%d: %s forced INITCHILD failure\n",
1736*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(dip), bus_addr);
1737*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(bus_addr);
1738*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1739*7c478bd9Sstevel@tonic-gate 	}
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate 	if (pshot_log) {
1742*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "initchild %s%d/%s@%s\n",
1743*7c478bd9Sstevel@tonic-gate 			ddi_get_name(dip), ddi_get_instance(dip),
1744*7c478bd9Sstevel@tonic-gate 			ddi_node_name(child), bus_addr);
1745*7c478bd9Sstevel@tonic-gate 	}
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, bus_addr);
1748*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(bus_addr);
1749*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1750*7c478bd9Sstevel@tonic-gate }
1751*7c478bd9Sstevel@tonic-gate 
1752*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1753*7c478bd9Sstevel@tonic-gate static int
1754*7c478bd9Sstevel@tonic-gate pshot_uninitchild(dev_info_t *dip, dev_info_t *child)
1755*7c478bd9Sstevel@tonic-gate {
1756*7c478bd9Sstevel@tonic-gate 	ddi_set_name_addr(child, NULL);
1757*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1758*7c478bd9Sstevel@tonic-gate }
1759*7c478bd9Sstevel@tonic-gate 
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate /*
1762*7c478bd9Sstevel@tonic-gate  * devctl IOCTL support
1763*7c478bd9Sstevel@tonic-gate  */
1764*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1765*7c478bd9Sstevel@tonic-gate static int
1766*7c478bd9Sstevel@tonic-gate pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1767*7c478bd9Sstevel@tonic-gate {
1768*7c478bd9Sstevel@tonic-gate 	int instance;
1769*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
1770*7c478bd9Sstevel@tonic-gate 
1771*7c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1772*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1773*7c478bd9Sstevel@tonic-gate 
1774*7c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(*devp));
1775*7c478bd9Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1776*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1777*7c478bd9Sstevel@tonic-gate 
1778*7c478bd9Sstevel@tonic-gate 	/*
1779*7c478bd9Sstevel@tonic-gate 	 * Access is currently determined on a per-instance basis.
1780*7c478bd9Sstevel@tonic-gate 	 * If we want per-node, then need to add state and lock members to
1781*7c478bd9Sstevel@tonic-gate 	 * pshot_minor_t
1782*7c478bd9Sstevel@tonic-gate 	 */
1783*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
1784*7c478bd9Sstevel@tonic-gate 	if (((flags & FEXCL) && (pshot->state & IS_OPEN)) ||
1785*7c478bd9Sstevel@tonic-gate 	    (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) {
1786*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
1787*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
1788*7c478bd9Sstevel@tonic-gate 	}
1789*7c478bd9Sstevel@tonic-gate 	pshot->state |= IS_OPEN;
1790*7c478bd9Sstevel@tonic-gate 	if (flags & FEXCL)
1791*7c478bd9Sstevel@tonic-gate 		pshot->state |= IS_OPEN_EXCL;
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
1794*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d open\n", instance);
1795*7c478bd9Sstevel@tonic-gate 
1796*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
1797*7c478bd9Sstevel@tonic-gate 	return (0);
1798*7c478bd9Sstevel@tonic-gate }
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate /*
1801*7c478bd9Sstevel@tonic-gate  * pshot_close
1802*7c478bd9Sstevel@tonic-gate  */
1803*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1804*7c478bd9Sstevel@tonic-gate static int
1805*7c478bd9Sstevel@tonic-gate pshot_close(dev_t dev, int flag, int otyp, cred_t *credp)
1806*7c478bd9Sstevel@tonic-gate {
1807*7c478bd9Sstevel@tonic-gate 	int instance;
1808*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
1809*7c478bd9Sstevel@tonic-gate 
1810*7c478bd9Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
1811*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1812*7c478bd9Sstevel@tonic-gate 
1813*7c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(dev));
1814*7c478bd9Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1815*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot->lock);
1818*7c478bd9Sstevel@tonic-gate 	pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL);
1819*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot->lock);
1820*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
1821*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d closed\n", instance);
1822*7c478bd9Sstevel@tonic-gate 	return (0);
1823*7c478bd9Sstevel@tonic-gate }
1824*7c478bd9Sstevel@tonic-gate 
1825*7c478bd9Sstevel@tonic-gate 
1826*7c478bd9Sstevel@tonic-gate /*
1827*7c478bd9Sstevel@tonic-gate  * pshot_ioctl: redirects to appropriate command handler based on various
1828*7c478bd9Sstevel@tonic-gate  * 	criteria
1829*7c478bd9Sstevel@tonic-gate  */
1830*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1831*7c478bd9Sstevel@tonic-gate static int
1832*7c478bd9Sstevel@tonic-gate pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1833*7c478bd9Sstevel@tonic-gate     int *rvalp)
1834*7c478bd9Sstevel@tonic-gate {
1835*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot;
1836*7c478bd9Sstevel@tonic-gate 	int instance;
1837*7c478bd9Sstevel@tonic-gate 	minor_t nodenum;
1838*7c478bd9Sstevel@tonic-gate 	char *nodename;
1839*7c478bd9Sstevel@tonic-gate 
1840*7c478bd9Sstevel@tonic-gate 	instance = pshot_minor_decode_inst(getminor(dev));
1841*7c478bd9Sstevel@tonic-gate 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1842*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1843*7c478bd9Sstevel@tonic-gate 
1844*7c478bd9Sstevel@tonic-gate 	nodenum = pshot_minor_decode_nodenum(getminor(dev));
1845*7c478bd9Sstevel@tonic-gate 	nodename = pshot->nodes[nodenum].name;
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
1848*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
1849*7c478bd9Sstevel@tonic-gate 		    "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
1850*7c478bd9Sstevel@tonic-gate 		    instance, (void *)dev, cmd, (void *)arg, mode);
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate 	if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0)
1853*7c478bd9Sstevel@tonic-gate 		return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp,
1854*7c478bd9Sstevel@tonic-gate 		    rvalp));
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 	if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0)
1857*7c478bd9Sstevel@tonic-gate 		return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp,
1858*7c478bd9Sstevel@tonic-gate 		    rvalp));
1859*7c478bd9Sstevel@tonic-gate 
1860*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u",
1861*7c478bd9Sstevel@tonic-gate 	    pshot->nodes[nodenum].minor);
1862*7c478bd9Sstevel@tonic-gate 	return (ENXIO);
1863*7c478bd9Sstevel@tonic-gate }
1864*7c478bd9Sstevel@tonic-gate 
1865*7c478bd9Sstevel@tonic-gate 
1866*7c478bd9Sstevel@tonic-gate /*
1867*7c478bd9Sstevel@tonic-gate  * pshot_devctl: handle DEVCTL operations
1868*7c478bd9Sstevel@tonic-gate  */
1869*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1870*7c478bd9Sstevel@tonic-gate static int
1871*7c478bd9Sstevel@tonic-gate pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
1872*7c478bd9Sstevel@tonic-gate     cred_t *credp, int *rvalp)
1873*7c478bd9Sstevel@tonic-gate {
1874*7c478bd9Sstevel@tonic-gate 	dev_info_t *self;
1875*7c478bd9Sstevel@tonic-gate 	dev_info_t *child = NULL;
1876*7c478bd9Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
1877*7c478bd9Sstevel@tonic-gate 	uint_t state;
1878*7c478bd9Sstevel@tonic-gate 	int rv = 0;
1879*7c478bd9Sstevel@tonic-gate 	uint_t flags;
1880*7c478bd9Sstevel@tonic-gate 	int instance;
1881*7c478bd9Sstevel@tonic-gate 	int i;
1882*7c478bd9Sstevel@tonic-gate 	int ret;
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate 	self = pshot->dip;
1885*7c478bd9Sstevel@tonic-gate 
1886*7c478bd9Sstevel@tonic-gate 	flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0;
1887*7c478bd9Sstevel@tonic-gate 	instance = pshot->instance;
1888*7c478bd9Sstevel@tonic-gate 
1889*7c478bd9Sstevel@tonic-gate 	/*
1890*7c478bd9Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
1891*7c478bd9Sstevel@tonic-gate 	 */
1892*7c478bd9Sstevel@tonic-gate 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
1893*7c478bd9Sstevel@tonic-gate 		if (pshot_devctls[i].ioctl_int == cmd) {
1894*7c478bd9Sstevel@tonic-gate 			if (pshot_debug)
1895*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d devctl: %s",
1896*7c478bd9Sstevel@tonic-gate 				    instance, pshot_devctls[i].ioctl_char);
1897*7c478bd9Sstevel@tonic-gate 		}
1898*7c478bd9Sstevel@tonic-gate 	}
1899*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1900*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
1901*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
1902*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
1903*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_REMOVE:
1904*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
1905*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_DEV_CREATE:
1906*7c478bd9Sstevel@tonic-gate 		rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags);
1907*7c478bd9Sstevel@tonic-gate 		if (pshot_debug && rv != 0) {
1908*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:"
1909*7c478bd9Sstevel@tonic-gate 			    " failed, rv = %d", instance, rv);
1910*7c478bd9Sstevel@tonic-gate 		}
1911*7c478bd9Sstevel@tonic-gate 
1912*7c478bd9Sstevel@tonic-gate 		return (rv);
1913*7c478bd9Sstevel@tonic-gate 	}
1914*7c478bd9Sstevel@tonic-gate 
1915*7c478bd9Sstevel@tonic-gate 	/*
1916*7c478bd9Sstevel@tonic-gate 	 * read devctl ioctl data
1917*7c478bd9Sstevel@tonic-gate 	 */
1918*7c478bd9Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1919*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1920*7c478bd9Sstevel@tonic-gate 
1921*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1922*7c478bd9Sstevel@tonic-gate 
1923*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
1924*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
1925*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
1926*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_DEVICE_RESET\n", instance);
1927*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
1928*7c478bd9Sstevel@tonic-gate 		    child, (void *)self);
1929*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
1930*7c478bd9Sstevel@tonic-gate 		break;
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
1933*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
1934*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
1935*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_BUS_QUIESCE\n", instance);
1936*7c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1937*7c478bd9Sstevel@tonic-gate 			if (state == BUS_QUIESCED) {
1938*7c478bd9Sstevel@tonic-gate 				break;
1939*7c478bd9Sstevel@tonic-gate 			}
1940*7c478bd9Sstevel@tonic-gate 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
1941*7c478bd9Sstevel@tonic-gate 		}
1942*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
1943*7c478bd9Sstevel@tonic-gate 		    child, (void *)self);
1944*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
1945*7c478bd9Sstevel@tonic-gate 
1946*7c478bd9Sstevel@tonic-gate 		break;
1947*7c478bd9Sstevel@tonic-gate 
1948*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
1949*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
1950*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
1951*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_BUS_UNQUIESCE\n", instance);
1952*7c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1953*7c478bd9Sstevel@tonic-gate 			if (state == BUS_ACTIVE) {
1954*7c478bd9Sstevel@tonic-gate 				break;
1955*7c478bd9Sstevel@tonic-gate 			}
1956*7c478bd9Sstevel@tonic-gate 		}
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 		/*
1959*7c478bd9Sstevel@tonic-gate 		 * quiesce the bus through bus-specific means
1960*7c478bd9Sstevel@tonic-gate 		 */
1961*7c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1962*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
1963*7c478bd9Sstevel@tonic-gate 		    child, (void *)self);
1964*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
1965*7c478bd9Sstevel@tonic-gate 		break;
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
1968*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
1969*7c478bd9Sstevel@tonic-gate 		/*
1970*7c478bd9Sstevel@tonic-gate 		 * no reset support for the pseudo bus
1971*7c478bd9Sstevel@tonic-gate 		 * but if there were....
1972*7c478bd9Sstevel@tonic-gate 		 */
1973*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
1974*7c478bd9Sstevel@tonic-gate 			child, (void *)self);
1975*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
1976*7c478bd9Sstevel@tonic-gate 		break;
1977*7c478bd9Sstevel@tonic-gate 
1978*7c478bd9Sstevel@tonic-gate 	/*
1979*7c478bd9Sstevel@tonic-gate 	 * PM related ioctls
1980*7c478bd9Sstevel@tonic-gate 	 */
1981*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUSY_COMP:
1982*7c478bd9Sstevel@tonic-gate 		/*
1983*7c478bd9Sstevel@tonic-gate 		 * mark component 0 busy.
1984*7c478bd9Sstevel@tonic-gate 		 * Keep track of ioctl updates to the busy count
1985*7c478bd9Sstevel@tonic-gate 		 * via pshot->busy_ioctl.
1986*7c478bd9Sstevel@tonic-gate 		 */
1987*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
1988*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
1989*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP\n", instance);
1990*7c478bd9Sstevel@tonic-gate 		}
1991*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
1992*7c478bd9Sstevel@tonic-gate 		++(pshot->busy);
1993*7c478bd9Sstevel@tonic-gate 		++(pshot->busy_ioctl);
1994*7c478bd9Sstevel@tonic-gate 		if (pshot_debug_busy) {
1995*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d:"
1996*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP comp 0 busy"
1997*7c478bd9Sstevel@tonic-gate 			    " %d busy_ioctl %d\n", instance, pshot->busy,
1998*7c478bd9Sstevel@tonic-gate 			    pshot->busy_ioctl);
1999*7c478bd9Sstevel@tonic-gate 		}
2000*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2001*7c478bd9Sstevel@tonic-gate 		ret = pm_busy_component(pshot->dip, 0);
2002*7c478bd9Sstevel@tonic-gate 		ASSERT(ret == DDI_SUCCESS);
2003*7c478bd9Sstevel@tonic-gate 
2004*7c478bd9Sstevel@tonic-gate 		break;
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUSY_COMP_TEST:
2007*7c478bd9Sstevel@tonic-gate 		/*
2008*7c478bd9Sstevel@tonic-gate 		 * test bus's busy state
2009*7c478bd9Sstevel@tonic-gate 		 */
2010*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2011*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2012*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP_TEST\n", instance);
2013*7c478bd9Sstevel@tonic-gate 		}
2014*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2015*7c478bd9Sstevel@tonic-gate 		state = pshot->busy;
2016*7c478bd9Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
2017*7c478bd9Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
2018*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
2019*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
2020*7c478bd9Sstevel@tonic-gate 			    instance);
2021*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2022*7c478bd9Sstevel@tonic-gate 		}
2023*7c478bd9Sstevel@tonic-gate 		if (pshot_debug_busy) {
2024*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:"
2025*7c478bd9Sstevel@tonic-gate 			    " comp 0 busy %d busy_ioctl %d\n", instance,
2026*7c478bd9Sstevel@tonic-gate 			    state, pshot->busy_ioctl);
2027*7c478bd9Sstevel@tonic-gate 		}
2028*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2029*7c478bd9Sstevel@tonic-gate 		break;
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_IDLE_COMP:
2032*7c478bd9Sstevel@tonic-gate 		/*
2033*7c478bd9Sstevel@tonic-gate 		 * mark component 0 idle.
2034*7c478bd9Sstevel@tonic-gate 		 * NOP if pshot->busy_ioctl <= 0.
2035*7c478bd9Sstevel@tonic-gate 		 */
2036*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2037*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2038*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_IDLE_COMP\n", instance);
2039*7c478bd9Sstevel@tonic-gate 		}
2040*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2041*7c478bd9Sstevel@tonic-gate 		if (pshot->busy_ioctl > 0) {
2042*7c478bd9Sstevel@tonic-gate 			ASSERT(pshot->busy > 0);
2043*7c478bd9Sstevel@tonic-gate 			--(pshot->busy);
2044*7c478bd9Sstevel@tonic-gate 			--(pshot->busy_ioctl);
2045*7c478bd9Sstevel@tonic-gate 			if (pshot_debug_busy) {
2046*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2047*7c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_IDLE_COM: comp 0"
2048*7c478bd9Sstevel@tonic-gate 				    " busy %d busy_ioctl %d\n", instance,
2049*7c478bd9Sstevel@tonic-gate 				    pshot->busy, pshot->busy_ioctl);
2050*7c478bd9Sstevel@tonic-gate 			}
2051*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
2052*7c478bd9Sstevel@tonic-gate 			ret = pm_idle_component(pshot->dip, 0);
2053*7c478bd9Sstevel@tonic-gate 			ASSERT(ret == DDI_SUCCESS);
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 		} else {
2056*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
2057*7c478bd9Sstevel@tonic-gate 		}
2058*7c478bd9Sstevel@tonic-gate 		break;
2059*7c478bd9Sstevel@tonic-gate 
2060*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_RAISE_PWR:
2061*7c478bd9Sstevel@tonic-gate 		/*
2062*7c478bd9Sstevel@tonic-gate 		 * raise component 0 to full power level MAXPWR via a
2063*7c478bd9Sstevel@tonic-gate 		 * pm_raise_power() call
2064*7c478bd9Sstevel@tonic-gate 		 */
2065*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2066*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2067*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_RAISE_PWR\n", instance);
2068*7c478bd9Sstevel@tonic-gate 		}
2069*7c478bd9Sstevel@tonic-gate 		if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) {
2070*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2071*7c478bd9Sstevel@tonic-gate 		} else {
2072*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
2073*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2074*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2075*7c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_RAISE_POWER: comp 0"
2076*7c478bd9Sstevel@tonic-gate 				    " to level %d\n", instance, pshot->level);
2077*7c478bd9Sstevel@tonic-gate 			}
2078*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
2079*7c478bd9Sstevel@tonic-gate 		}
2080*7c478bd9Sstevel@tonic-gate 		break;
2081*7c478bd9Sstevel@tonic-gate 
2082*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_LOWER_PWR:
2083*7c478bd9Sstevel@tonic-gate 		/*
2084*7c478bd9Sstevel@tonic-gate 		 * pm_lower_power() call for negative testing
2085*7c478bd9Sstevel@tonic-gate 		 * expected to fail.
2086*7c478bd9Sstevel@tonic-gate 		 */
2087*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2088*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2089*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_LOWER_PWR\n", instance);
2090*7c478bd9Sstevel@tonic-gate 		}
2091*7c478bd9Sstevel@tonic-gate 		if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
2092*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2093*7c478bd9Sstevel@tonic-gate 		} else {
2094*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pshot->lock);
2095*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2096*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2097*7c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_LOWER_POWER comp 0"
2098*7c478bd9Sstevel@tonic-gate 				    " to level %d\n", instance, pshot->level);
2099*7c478bd9Sstevel@tonic-gate 			}
2100*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pshot->lock);
2101*7c478bd9Sstevel@tonic-gate 		}
2102*7c478bd9Sstevel@tonic-gate 		break;
2103*7c478bd9Sstevel@tonic-gate 
2104*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_CHANGE_PWR_LOW:
2105*7c478bd9Sstevel@tonic-gate 		/*
2106*7c478bd9Sstevel@tonic-gate 		 * inform the PM framework that component 0 has changed
2107*7c478bd9Sstevel@tonic-gate 		 * power level to 0 via a pm_power_has_changed() call
2108*7c478bd9Sstevel@tonic-gate 		 */
2109*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2110*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2111*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
2112*7c478bd9Sstevel@tonic-gate 		}
2113*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2114*7c478bd9Sstevel@tonic-gate 		pshot->level = 0;
2115*7c478bd9Sstevel@tonic-gate 		if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) {
2116*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2117*7c478bd9Sstevel@tonic-gate 		} else {
2118*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2119*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2120*7c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
2121*7c478bd9Sstevel@tonic-gate 				    " level %d\n", instance, pshot->level);
2122*7c478bd9Sstevel@tonic-gate 			}
2123*7c478bd9Sstevel@tonic-gate 		}
2124*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2125*7c478bd9Sstevel@tonic-gate 		break;
2126*7c478bd9Sstevel@tonic-gate 
2127*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_CHANGE_PWR_HIGH:
2128*7c478bd9Sstevel@tonic-gate 		/*
2129*7c478bd9Sstevel@tonic-gate 		 * inform the PM framework that component 0 has changed
2130*7c478bd9Sstevel@tonic-gate 		 * power level to MAXPWR via a pm_power_has_changed() call
2131*7c478bd9Sstevel@tonic-gate 		 */
2132*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2133*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2134*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
2135*7c478bd9Sstevel@tonic-gate 		}
2136*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2137*7c478bd9Sstevel@tonic-gate 		pshot->level = MAXPWR;
2138*7c478bd9Sstevel@tonic-gate 		if (pm_power_has_changed(pshot->dip, 0, MAXPWR)
2139*7c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
2140*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2141*7c478bd9Sstevel@tonic-gate 		} else {
2142*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2143*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2144*7c478bd9Sstevel@tonic-gate 				    " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
2145*7c478bd9Sstevel@tonic-gate 				    " level %d\n", instance, pshot->level);
2146*7c478bd9Sstevel@tonic-gate 			}
2147*7c478bd9Sstevel@tonic-gate 		}
2148*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2149*7c478bd9Sstevel@tonic-gate 		break;
2150*7c478bd9Sstevel@tonic-gate 
2151*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_POWER:
2152*7c478bd9Sstevel@tonic-gate 		/*
2153*7c478bd9Sstevel@tonic-gate 		 * test if the pshot_power() routine has been called,
2154*7c478bd9Sstevel@tonic-gate 		 * then clear
2155*7c478bd9Sstevel@tonic-gate 		 */
2156*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2157*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2158*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
2159*7c478bd9Sstevel@tonic-gate 		}
2160*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2161*7c478bd9Sstevel@tonic-gate 		state = (pshot->state & POWER_FLAG) ? 1 : 0;
2162*7c478bd9Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
2163*7c478bd9Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
2164*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
2165*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER: copyout failed",
2166*7c478bd9Sstevel@tonic-gate 			    instance);
2167*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2168*7c478bd9Sstevel@tonic-gate 		}
2169*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2170*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:"
2171*7c478bd9Sstevel@tonic-gate 			    " POWER_FLAG = %d\n", instance, state);
2172*7c478bd9Sstevel@tonic-gate 		}
2173*7c478bd9Sstevel@tonic-gate 		pshot->state &= ~POWER_FLAG;
2174*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2175*7c478bd9Sstevel@tonic-gate 		break;
2176*7c478bd9Sstevel@tonic-gate 
2177*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_FAIL_SUSPEND:
2178*7c478bd9Sstevel@tonic-gate 		/*
2179*7c478bd9Sstevel@tonic-gate 		 * fail DDI_SUSPEND
2180*7c478bd9Sstevel@tonic-gate 		 */
2181*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2182*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2183*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_FAIL_SUSPEND\n", instance);
2184*7c478bd9Sstevel@tonic-gate 		}
2185*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2186*7c478bd9Sstevel@tonic-gate 		pshot->state |= FAIL_SUSPEND_FLAG;
2187*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2188*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2189*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n",
2190*7c478bd9Sstevel@tonic-gate 			    instance);
2191*7c478bd9Sstevel@tonic-gate 		}
2192*7c478bd9Sstevel@tonic-gate 		break;
2193*7c478bd9Sstevel@tonic-gate 
2194*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUS_STRICT_TEST:
2195*7c478bd9Sstevel@tonic-gate 		/*
2196*7c478bd9Sstevel@tonic-gate 		 * test the STRICT_PARENT flag:
2197*7c478bd9Sstevel@tonic-gate 		 *	set => STRICT PARENT
2198*7c478bd9Sstevel@tonic-gate 		 *	not set => INVOLVED PARENT
2199*7c478bd9Sstevel@tonic-gate 		 */
2200*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2201*7c478bd9Sstevel@tonic-gate 		state = (pshot->state & STRICT_PARENT) ? 1 : 0;
2202*7c478bd9Sstevel@tonic-gate 		if (copyout(&state, dcp->cpyout_buf,
2203*7c478bd9Sstevel@tonic-gate 		    sizeof (uint_t)) != 0) {
2204*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "pshot%d devctl:"
2205*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
2206*7c478bd9Sstevel@tonic-gate 			    instance);
2207*7c478bd9Sstevel@tonic-gate 			rv = EINVAL;
2208*7c478bd9Sstevel@tonic-gate 		}
2209*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2210*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2211*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
2212*7c478bd9Sstevel@tonic-gate 			    instance, ((state == 0) ? "INVOLVED" : "STRICT"));
2213*7c478bd9Sstevel@tonic-gate 		}
2214*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2215*7c478bd9Sstevel@tonic-gate 		break;
2216*7c478bd9Sstevel@tonic-gate 
2217*7c478bd9Sstevel@tonic-gate 	case DEVCTL_PM_BUS_NO_INVOL:
2218*7c478bd9Sstevel@tonic-gate 		/*
2219*7c478bd9Sstevel@tonic-gate 		 * Set the NO_INVOL_FLAG flag to
2220*7c478bd9Sstevel@tonic-gate 		 * notify the driver that the child will not
2221*7c478bd9Sstevel@tonic-gate 		 * call pm_lower_power() on detach.
2222*7c478bd9Sstevel@tonic-gate 		 * The driver needs to mark itself idle twice
2223*7c478bd9Sstevel@tonic-gate 		 * during DDI_CTLOPS_DETACH (post).
2224*7c478bd9Sstevel@tonic-gate 		 */
2225*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2226*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d devctl:"
2227*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_BUS_NO_INVOL\n", instance);
2228*7c478bd9Sstevel@tonic-gate 		}
2229*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pshot->lock);
2230*7c478bd9Sstevel@tonic-gate 		pshot->state |= NO_INVOL_FLAG;
2231*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pshot->lock);
2232*7c478bd9Sstevel@tonic-gate 		break;
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 	default:
2235*7c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
2236*7c478bd9Sstevel@tonic-gate 	}
2237*7c478bd9Sstevel@tonic-gate 
2238*7c478bd9Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
2239*7c478bd9Sstevel@tonic-gate 	return (rv);
2240*7c478bd9Sstevel@tonic-gate }
2241*7c478bd9Sstevel@tonic-gate 
2242*7c478bd9Sstevel@tonic-gate 
2243*7c478bd9Sstevel@tonic-gate /*
2244*7c478bd9Sstevel@tonic-gate  * pshot_testctl: handle other test operations
2245*7c478bd9Sstevel@tonic-gate  *	- If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
2246*7c478bd9Sstevel@tonic-gate  *	  child to direct the DEVCTL to, if applicable;
2247*7c478bd9Sstevel@tonic-gate  *	  furthermore, any cmd here can be sent by layered ioctls (unlike
2248*7c478bd9Sstevel@tonic-gate  *	  those to pshot_devctl() which must come from userland)
2249*7c478bd9Sstevel@tonic-gate  */
2250*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
2251*7c478bd9Sstevel@tonic-gate static int
2252*7c478bd9Sstevel@tonic-gate pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
2253*7c478bd9Sstevel@tonic-gate     cred_t *credp, int *rvalp)
2254*7c478bd9Sstevel@tonic-gate {
2255*7c478bd9Sstevel@tonic-gate 	dev_info_t *self;
2256*7c478bd9Sstevel@tonic-gate 	dev_info_t *child = NULL;
2257*7c478bd9Sstevel@tonic-gate 	uint_t state;
2258*7c478bd9Sstevel@tonic-gate 	int rv = 0;
2259*7c478bd9Sstevel@tonic-gate 	int instance;
2260*7c478bd9Sstevel@tonic-gate 	int i;
2261*7c478bd9Sstevel@tonic-gate 
2262*7c478bd9Sstevel@tonic-gate 	/* uint_t flags; */
2263*7c478bd9Sstevel@tonic-gate 
2264*7c478bd9Sstevel@tonic-gate 	/* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
2265*7c478bd9Sstevel@tonic-gate 	self = pshot->dip;
2266*7c478bd9Sstevel@tonic-gate 	instance = pshot->instance;
2267*7c478bd9Sstevel@tonic-gate 
2268*7c478bd9Sstevel@tonic-gate 	if (cmd & DEVCTL_IOC) {
2269*7c478bd9Sstevel@tonic-gate 		child = e_ddi_hold_devi_by_dev((dev_t)arg, 0);
2270*7c478bd9Sstevel@tonic-gate 	}
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
2273*7c478bd9Sstevel@tonic-gate 		if (pshot_devctls[i].ioctl_int == cmd) {
2274*7c478bd9Sstevel@tonic-gate 			if (pshot_debug)
2275*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d devctl: %s",
2276*7c478bd9Sstevel@tonic-gate 				    instance, pshot_devctls[i].ioctl_char);
2277*7c478bd9Sstevel@tonic-gate 		}
2278*7c478bd9Sstevel@tonic-gate 	}
2279*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
2280*7c478bd9Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
2281*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
2282*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
2283*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
2284*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
2285*7c478bd9Sstevel@tonic-gate 		    child, (void *)self);
2286*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
2287*7c478bd9Sstevel@tonic-gate 		break;
2288*7c478bd9Sstevel@tonic-gate 
2289*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
2290*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
2291*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
2292*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
2293*7c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2294*7c478bd9Sstevel@tonic-gate 			if (state == BUS_QUIESCED) {
2295*7c478bd9Sstevel@tonic-gate 				break;
2296*7c478bd9Sstevel@tonic-gate 			}
2297*7c478bd9Sstevel@tonic-gate 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
2298*7c478bd9Sstevel@tonic-gate 		}
2299*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
2300*7c478bd9Sstevel@tonic-gate 		    child, (void *)self);
2301*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
2302*7c478bd9Sstevel@tonic-gate 
2303*7c478bd9Sstevel@tonic-gate 		break;
2304*7c478bd9Sstevel@tonic-gate 
2305*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
2306*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
2307*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d testctl:"
2308*7c478bd9Sstevel@tonic-gate 			    " DEVCTL_PM_POWER\n", instance);
2309*7c478bd9Sstevel@tonic-gate 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2310*7c478bd9Sstevel@tonic-gate 			if (state == BUS_ACTIVE) {
2311*7c478bd9Sstevel@tonic-gate 				break;
2312*7c478bd9Sstevel@tonic-gate 			}
2313*7c478bd9Sstevel@tonic-gate 		}
2314*7c478bd9Sstevel@tonic-gate 
2315*7c478bd9Sstevel@tonic-gate 		/*
2316*7c478bd9Sstevel@tonic-gate 		 * quiesce the bus through bus-specific means
2317*7c478bd9Sstevel@tonic-gate 		 */
2318*7c478bd9Sstevel@tonic-gate 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
2319*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
2320*7c478bd9Sstevel@tonic-gate 		    child, (void *)self);
2321*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
2322*7c478bd9Sstevel@tonic-gate 		break;
2323*7c478bd9Sstevel@tonic-gate 
2324*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
2325*7c478bd9Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
2326*7c478bd9Sstevel@tonic-gate 		/*
2327*7c478bd9Sstevel@tonic-gate 		 * no reset support for the pseudo bus
2328*7c478bd9Sstevel@tonic-gate 		 * but if there were....
2329*7c478bd9Sstevel@tonic-gate 		 */
2330*7c478bd9Sstevel@tonic-gate 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
2331*7c478bd9Sstevel@tonic-gate 			child, (void *)self);
2332*7c478bd9Sstevel@tonic-gate 		ASSERT(rv == NDI_SUCCESS);
2333*7c478bd9Sstevel@tonic-gate 		break;
2334*7c478bd9Sstevel@tonic-gate 
2335*7c478bd9Sstevel@tonic-gate 	default:
2336*7c478bd9Sstevel@tonic-gate 		rv = ENOTTY;
2337*7c478bd9Sstevel@tonic-gate 	}
2338*7c478bd9Sstevel@tonic-gate 
2339*7c478bd9Sstevel@tonic-gate 	if (child != NULL)
2340*7c478bd9Sstevel@tonic-gate 		ddi_release_devi(child);
2341*7c478bd9Sstevel@tonic-gate 	return (rv);
2342*7c478bd9Sstevel@tonic-gate }
2343*7c478bd9Sstevel@tonic-gate 
2344*7c478bd9Sstevel@tonic-gate 
2345*7c478bd9Sstevel@tonic-gate static int
2346*7c478bd9Sstevel@tonic-gate pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
2347*7c478bd9Sstevel@tonic-gate 	char *eventname, ddi_eventcookie_t *event_cookiep)
2348*7c478bd9Sstevel@tonic-gate {
2349*7c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
2350*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2351*7c478bd9Sstevel@tonic-gate 
2352*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
2353*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "pshot%d: "
2354*7c478bd9Sstevel@tonic-gate 		"pshot_get_eventcookie:\n\t"
2355*7c478bd9Sstevel@tonic-gate 		"dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
2356*7c478bd9Sstevel@tonic-gate 		instance, (void *)dip, (void *)rdip,
2357*7c478bd9Sstevel@tonic-gate 		ddi_node_name(rdip), ddi_get_instance(rdip),
2358*7c478bd9Sstevel@tonic-gate 		eventname);
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate 
2361*7c478bd9Sstevel@tonic-gate 	return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl,
2362*7c478bd9Sstevel@tonic-gate 		rdip, eventname, event_cookiep, NDI_EVENT_NOPASS));
2363*7c478bd9Sstevel@tonic-gate }
2364*7c478bd9Sstevel@tonic-gate 
2365*7c478bd9Sstevel@tonic-gate static int
2366*7c478bd9Sstevel@tonic-gate pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
2367*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie,
2368*7c478bd9Sstevel@tonic-gate 	void (*callback)(), void *arg, ddi_callback_id_t *cb_id)
2369*7c478bd9Sstevel@tonic-gate {
2370*7c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
2371*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2372*7c478bd9Sstevel@tonic-gate 
2373*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
2374*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "pshot%d: "
2375*7c478bd9Sstevel@tonic-gate 	    "pshot_add_eventcall:\n\t"
2376*7c478bd9Sstevel@tonic-gate 	    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
2377*7c478bd9Sstevel@tonic-gate 	    "cb = 0x%p, arg = 0x%p\n",
2378*7c478bd9Sstevel@tonic-gate 	    instance, (void *)dip, (void *)rdip,
2379*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
2380*7c478bd9Sstevel@tonic-gate 	    NDI_EVENT_NAME(cookie), (void *)callback, arg);
2381*7c478bd9Sstevel@tonic-gate 
2382*7c478bd9Sstevel@tonic-gate 	/* add callback to our event handle */
2383*7c478bd9Sstevel@tonic-gate 	return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip,
2384*7c478bd9Sstevel@tonic-gate 		cookie, callback, arg, NDI_SLEEP, cb_id));
2385*7c478bd9Sstevel@tonic-gate }
2386*7c478bd9Sstevel@tonic-gate 
2387*7c478bd9Sstevel@tonic-gate static int
2388*7c478bd9Sstevel@tonic-gate pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
2389*7c478bd9Sstevel@tonic-gate {
2390*7c478bd9Sstevel@tonic-gate 
2391*7c478bd9Sstevel@tonic-gate 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
2392*7c478bd9Sstevel@tonic-gate 
2393*7c478bd9Sstevel@tonic-gate 	int instance = ddi_get_instance(dip);
2394*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2395*7c478bd9Sstevel@tonic-gate 
2396*7c478bd9Sstevel@tonic-gate 	ASSERT(cb);
2397*7c478bd9Sstevel@tonic-gate 
2398*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
2399*7c478bd9Sstevel@tonic-gate 	    cmn_err(CE_CONT, "pshot%d: "
2400*7c478bd9Sstevel@tonic-gate 	    "pshot_remove_eventcall:\n\t"
2401*7c478bd9Sstevel@tonic-gate 	    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
2402*7c478bd9Sstevel@tonic-gate 	    instance, (void *)dip, (void *)cb->ndi_evtcb_dip,
2403*7c478bd9Sstevel@tonic-gate 	    ddi_node_name(cb->ndi_evtcb_dip),
2404*7c478bd9Sstevel@tonic-gate 	    ddi_get_instance(cb->ndi_evtcb_dip), (void *)cb->ndi_evtcb_cookie,
2405*7c478bd9Sstevel@tonic-gate 	    NDI_EVENT_NAME(cb->ndi_evtcb_cookie));
2406*7c478bd9Sstevel@tonic-gate 
2407*7c478bd9Sstevel@tonic-gate 	return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id));
2408*7c478bd9Sstevel@tonic-gate }
2409*7c478bd9Sstevel@tonic-gate 
2410*7c478bd9Sstevel@tonic-gate static int
2411*7c478bd9Sstevel@tonic-gate pshot_post_event(dev_info_t *dip, dev_info_t *rdip,
2412*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie, void *impl_data)
2413*7c478bd9Sstevel@tonic-gate {
2414*7c478bd9Sstevel@tonic-gate 	int	instance = ddi_get_instance(dip);
2415*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
2418*7c478bd9Sstevel@tonic-gate 	    if (rdip) {
2419*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: "
2420*7c478bd9Sstevel@tonic-gate 		    "pshot_post_event:\n\t"
2421*7c478bd9Sstevel@tonic-gate 		    "dip = 0x%p rdip = 0x%p (%s%d\n\t"
2422*7c478bd9Sstevel@tonic-gate 		    "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
2423*7c478bd9Sstevel@tonic-gate 		    instance, (void *)dip, (void *)rdip,
2424*7c478bd9Sstevel@tonic-gate 		    ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
2425*7c478bd9Sstevel@tonic-gate 		    NDI_EVENT_NAME(cookie), impl_data);
2426*7c478bd9Sstevel@tonic-gate 	    } else {
2427*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: "
2428*7c478bd9Sstevel@tonic-gate 		    "pshot_post_event:\n\t"
2429*7c478bd9Sstevel@tonic-gate 		    "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
2430*7c478bd9Sstevel@tonic-gate 		    instance, (void *)dip, (void *)cookie,
2431*7c478bd9Sstevel@tonic-gate 		    NDI_EVENT_NAME(cookie), impl_data);
2432*7c478bd9Sstevel@tonic-gate 	    }
2433*7c478bd9Sstevel@tonic-gate 	}
2434*7c478bd9Sstevel@tonic-gate 
2435*7c478bd9Sstevel@tonic-gate 	/*  run callbacks for this event */
2436*7c478bd9Sstevel@tonic-gate 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip,
2437*7c478bd9Sstevel@tonic-gate 	    cookie, impl_data));
2438*7c478bd9Sstevel@tonic-gate }
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate /*
2441*7c478bd9Sstevel@tonic-gate  * the nexus driver will generate events
2442*7c478bd9Sstevel@tonic-gate  * that need to go to children
2443*7c478bd9Sstevel@tonic-gate  */
2444*7c478bd9Sstevel@tonic-gate static int
2445*7c478bd9Sstevel@tonic-gate pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child,
2446*7c478bd9Sstevel@tonic-gate 	void *bus_impldata)
2447*7c478bd9Sstevel@tonic-gate {
2448*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(
2449*7c478bd9Sstevel@tonic-gate 		pshot->ndi_event_hdl, event_tag);
2450*7c478bd9Sstevel@tonic-gate 
2451*7c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
2452*7c478bd9Sstevel@tonic-gate 		if (child) {
2453*7c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "pshot%d: "
2454*7c478bd9Sstevel@tonic-gate 			"pshot_event: event_tag = 0x%x (%s)\n\t"
2455*7c478bd9Sstevel@tonic-gate 			"child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
2456*7c478bd9Sstevel@tonic-gate 			pshot->instance, event_tag,
2457*7c478bd9Sstevel@tonic-gate 			ndi_event_tag_to_name(pshot->ndi_event_hdl, event_tag),
2458*7c478bd9Sstevel@tonic-gate 			(void *)child, ddi_node_name(child),
2459*7c478bd9Sstevel@tonic-gate 			ddi_get_instance(child), bus_impldata,
2460*7c478bd9Sstevel@tonic-gate 			ddi_node_name((dev_info_t *)bus_impldata),
2461*7c478bd9Sstevel@tonic-gate 			ddi_get_instance((dev_info_t *)bus_impldata));
2462*7c478bd9Sstevel@tonic-gate 		} else {
2463*7c478bd9Sstevel@tonic-gate 		    cmn_err(CE_CONT, "pshot%d: "
2464*7c478bd9Sstevel@tonic-gate 			"pshot_event: event_tag = 0x%x (%s)\n\t"
2465*7c478bd9Sstevel@tonic-gate 			"child = NULL,  bus_impl = 0x%p (%s%d)\n",
2466*7c478bd9Sstevel@tonic-gate 			pshot->instance, event_tag,
2467*7c478bd9Sstevel@tonic-gate 			ndi_event_tag_to_name(pshot->ndi_event_hdl, event_tag),
2468*7c478bd9Sstevel@tonic-gate 			bus_impldata,
2469*7c478bd9Sstevel@tonic-gate 			ddi_node_name((dev_info_t *)bus_impldata),
2470*7c478bd9Sstevel@tonic-gate 			ddi_get_instance((dev_info_t *)bus_impldata));
2471*7c478bd9Sstevel@tonic-gate 		}
2472*7c478bd9Sstevel@tonic-gate 	}
2473*7c478bd9Sstevel@tonic-gate 
2474*7c478bd9Sstevel@tonic-gate 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl,
2475*7c478bd9Sstevel@tonic-gate 		child, cookie, bus_impldata));
2476*7c478bd9Sstevel@tonic-gate }
2477*7c478bd9Sstevel@tonic-gate 
2478*7c478bd9Sstevel@tonic-gate 
2479*7c478bd9Sstevel@tonic-gate /*
2480*7c478bd9Sstevel@tonic-gate  * the pshot driver event notification callback
2481*7c478bd9Sstevel@tonic-gate  */
2482*7c478bd9Sstevel@tonic-gate static void
2483*7c478bd9Sstevel@tonic-gate pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
2484*7c478bd9Sstevel@tonic-gate 	void *arg, void *bus_impldata)
2485*7c478bd9Sstevel@tonic-gate {
2486*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = (pshot_t *)arg;
2487*7c478bd9Sstevel@tonic-gate 	int event_tag;
2488*7c478bd9Sstevel@tonic-gate 
2489*7c478bd9Sstevel@tonic-gate 	/* look up the event */
2490*7c478bd9Sstevel@tonic-gate 	event_tag = NDI_EVENT_TAG(cookie);
2491*7c478bd9Sstevel@tonic-gate 
2492*7c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
2493*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: "
2494*7c478bd9Sstevel@tonic-gate 		    "pshot_event_cb:\n\t"
2495*7c478bd9Sstevel@tonic-gate 		    "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
2496*7c478bd9Sstevel@tonic-gate 		    "arg = 0x%p bus_impl = 0x%p (%s%d)\n",
2497*7c478bd9Sstevel@tonic-gate 		    pshot->instance, (void *)dip, (void *)cookie,
2498*7c478bd9Sstevel@tonic-gate 		    NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata,
2499*7c478bd9Sstevel@tonic-gate 		    ddi_node_name((dev_info_t *)bus_impldata),
2500*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance((dev_info_t *)bus_impldata));
2501*7c478bd9Sstevel@tonic-gate 	}
2502*7c478bd9Sstevel@tonic-gate 
2503*7c478bd9Sstevel@tonic-gate 	switch (event_tag) {
2504*7c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_OFFLINE:
2505*7c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_RESET:
2506*7c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_QUIESCE:
2507*7c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_BUS_UNQUIESCE:
2508*7c478bd9Sstevel@tonic-gate 		/* notify all subscribers of the this event */
2509*7c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(pshot->ndi_event_hdl,
2510*7c478bd9Sstevel@tonic-gate 			NULL, cookie, bus_impldata);
2511*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2512*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: event=%s\n\t"
2513*7c478bd9Sstevel@tonic-gate 			"pshot_event_cb\n", pshot->instance,
2514*7c478bd9Sstevel@tonic-gate 			NDI_EVENT_NAME(cookie));
2515*7c478bd9Sstevel@tonic-gate 		}
2516*7c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
2517*7c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_TEST_POST:
2518*7c478bd9Sstevel@tonic-gate 	case PSHOT_EVENT_TAG_DEV_RESET:
2519*7c478bd9Sstevel@tonic-gate 	default:
2520*7c478bd9Sstevel@tonic-gate 		return;
2521*7c478bd9Sstevel@tonic-gate 	}
2522*7c478bd9Sstevel@tonic-gate }
2523*7c478bd9Sstevel@tonic-gate 
2524*7c478bd9Sstevel@tonic-gate static int
2525*7c478bd9Sstevel@tonic-gate pshot_bus_config(dev_info_t *parent, uint_t flags,
2526*7c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
2527*7c478bd9Sstevel@tonic-gate {
2528*7c478bd9Sstevel@tonic-gate 	int		rval;
2529*7c478bd9Sstevel@tonic-gate 	char		*devname;
2530*7c478bd9Sstevel@tonic-gate 	char		*devstr, *cname, *caddr;
2531*7c478bd9Sstevel@tonic-gate 	int		devstrlen;
2532*7c478bd9Sstevel@tonic-gate 	int		circ;
2533*7c478bd9Sstevel@tonic-gate 	pshot_t		*pshot;
2534*7c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(parent);
2535*7c478bd9Sstevel@tonic-gate 
2536*7c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
2537*7c478bd9Sstevel@tonic-gate 		flags |= NDI_DEVI_DEBUG;
2538*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
2539*7c478bd9Sstevel@tonic-gate 		    "pshot%d: bus_config %s flags=0x%x\n",
2540*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
2541*7c478bd9Sstevel@tonic-gate 		    (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags);
2542*7c478bd9Sstevel@tonic-gate 	}
2543*7c478bd9Sstevel@tonic-gate 
2544*7c478bd9Sstevel@tonic-gate 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
2545*7c478bd9Sstevel@tonic-gate 	if (pshot == NULL) {
2546*7c478bd9Sstevel@tonic-gate 
2547*7c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
2548*7c478bd9Sstevel@tonic-gate 	}
2549*7c478bd9Sstevel@tonic-gate 
2550*7c478bd9Sstevel@tonic-gate 	/*
2551*7c478bd9Sstevel@tonic-gate 	 * Hold the nexus across the bus_config
2552*7c478bd9Sstevel@tonic-gate 	 */
2553*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
2554*7c478bd9Sstevel@tonic-gate 
2555*7c478bd9Sstevel@tonic-gate 	switch (op) {
2556*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ONE:
2557*7c478bd9Sstevel@tonic-gate 
2558*7c478bd9Sstevel@tonic-gate 		/*
2559*7c478bd9Sstevel@tonic-gate 		 * lookup and hold child device, create if not found
2560*7c478bd9Sstevel@tonic-gate 		 */
2561*7c478bd9Sstevel@tonic-gate 		devname = (char *)arg;
2562*7c478bd9Sstevel@tonic-gate 		devstrlen = strlen(devname) + 1;
2563*7c478bd9Sstevel@tonic-gate 		devstr = i_ddi_strdup(devname, KM_SLEEP);
2564*7c478bd9Sstevel@tonic-gate 		i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2565*7c478bd9Sstevel@tonic-gate 
2566*7c478bd9Sstevel@tonic-gate 		/*
2567*7c478bd9Sstevel@tonic-gate 		 * The framework ensures that the node has
2568*7c478bd9Sstevel@tonic-gate 		 * a name but each nexus is responsible for
2569*7c478bd9Sstevel@tonic-gate 		 * the bus address name space.  This driver
2570*7c478bd9Sstevel@tonic-gate 		 * requires that a bus address be specified,
2571*7c478bd9Sstevel@tonic-gate 		 * as will most nexus drivers.
2572*7c478bd9Sstevel@tonic-gate 		 */
2573*7c478bd9Sstevel@tonic-gate 		ASSERT(cname && strlen(cname) > 0);
2574*7c478bd9Sstevel@tonic-gate 		if (caddr == NULL || strlen(caddr) == 0) {
2575*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2576*7c478bd9Sstevel@tonic-gate 			    "pshot%d: malformed name %s (no bus address)",
2577*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent), devname);
2578*7c478bd9Sstevel@tonic-gate 			kmem_free(devstr, devstrlen);
2579*7c478bd9Sstevel@tonic-gate 			ndi_devi_exit(parent, circ);
2580*7c478bd9Sstevel@tonic-gate 			return (NDI_FAILURE);
2581*7c478bd9Sstevel@tonic-gate 		}
2582*7c478bd9Sstevel@tonic-gate 
2583*7c478bd9Sstevel@tonic-gate 		/*
2584*7c478bd9Sstevel@tonic-gate 		 * Handle a few special cases for testing purposes
2585*7c478bd9Sstevel@tonic-gate 		 */
2586*7c478bd9Sstevel@tonic-gate 		rval = pshot_bus_config_test_specials(parent,
2587*7c478bd9Sstevel@tonic-gate 			devname, cname, caddr);
2588*7c478bd9Sstevel@tonic-gate 
2589*7c478bd9Sstevel@tonic-gate 		if (rval == NDI_SUCCESS) {
2590*7c478bd9Sstevel@tonic-gate 			/*
2591*7c478bd9Sstevel@tonic-gate 			 * Set up either a leaf or nexus device
2592*7c478bd9Sstevel@tonic-gate 			 */
2593*7c478bd9Sstevel@tonic-gate 			if (strcmp(cname, "pshot") == 0) {
2594*7c478bd9Sstevel@tonic-gate 				rval = pshot_bus_config_setup_nexus(parent,
2595*7c478bd9Sstevel@tonic-gate 				    cname, caddr);
2596*7c478bd9Sstevel@tonic-gate 			} else {
2597*7c478bd9Sstevel@tonic-gate 				rval = pshot_bus_config_setup_leaf(parent,
2598*7c478bd9Sstevel@tonic-gate 				    cname, caddr);
2599*7c478bd9Sstevel@tonic-gate 			}
2600*7c478bd9Sstevel@tonic-gate 		}
2601*7c478bd9Sstevel@tonic-gate 
2602*7c478bd9Sstevel@tonic-gate 		kmem_free(devstr, devstrlen);
2603*7c478bd9Sstevel@tonic-gate 		break;
2604*7c478bd9Sstevel@tonic-gate 
2605*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_DRIVER:
2606*7c478bd9Sstevel@tonic-gate 		rval = NDI_FAILURE;
2607*7c478bd9Sstevel@tonic-gate 		break;
2608*7c478bd9Sstevel@tonic-gate 
2609*7c478bd9Sstevel@tonic-gate 	case BUS_CONFIG_ALL:
2610*7c478bd9Sstevel@tonic-gate 		rval = NDI_SUCCESS;
2611*7c478bd9Sstevel@tonic-gate 		break;
2612*7c478bd9Sstevel@tonic-gate 
2613*7c478bd9Sstevel@tonic-gate 	default:
2614*7c478bd9Sstevel@tonic-gate 		rval = NDI_FAILURE;
2615*7c478bd9Sstevel@tonic-gate 		break;
2616*7c478bd9Sstevel@tonic-gate 	}
2617*7c478bd9Sstevel@tonic-gate 
2618*7c478bd9Sstevel@tonic-gate 	if (rval == NDI_SUCCESS)
2619*7c478bd9Sstevel@tonic-gate 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
2620*7c478bd9Sstevel@tonic-gate 
2621*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
2622*7c478bd9Sstevel@tonic-gate 
2623*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
2624*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: bus_config %s\n",
2625*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
2626*7c478bd9Sstevel@tonic-gate 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
2627*7c478bd9Sstevel@tonic-gate 
2628*7c478bd9Sstevel@tonic-gate 	return (rval);
2629*7c478bd9Sstevel@tonic-gate }
2630*7c478bd9Sstevel@tonic-gate 
2631*7c478bd9Sstevel@tonic-gate static int
2632*7c478bd9Sstevel@tonic-gate pshot_bus_unconfig(dev_info_t *parent, uint_t flags,
2633*7c478bd9Sstevel@tonic-gate     ddi_bus_config_op_t op, void *arg)
2634*7c478bd9Sstevel@tonic-gate {
2635*7c478bd9Sstevel@tonic-gate 	major_t		major;
2636*7c478bd9Sstevel@tonic-gate 	int		rval = NDI_SUCCESS;
2637*7c478bd9Sstevel@tonic-gate 	int		circ;
2638*7c478bd9Sstevel@tonic-gate 
2639*7c478bd9Sstevel@tonic-gate 	if (pshot_debug) {
2640*7c478bd9Sstevel@tonic-gate 		flags |= NDI_DEVI_DEBUG;
2641*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT,
2642*7c478bd9Sstevel@tonic-gate 		    "pshot%d: bus_unconfig %s flags=0x%x\n",
2643*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
2644*7c478bd9Sstevel@tonic-gate 		    (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags);
2645*7c478bd9Sstevel@tonic-gate 	}
2646*7c478bd9Sstevel@tonic-gate 
2647*7c478bd9Sstevel@tonic-gate 	/*
2648*7c478bd9Sstevel@tonic-gate 	 * Hold the nexus across the bus_unconfig
2649*7c478bd9Sstevel@tonic-gate 	 */
2650*7c478bd9Sstevel@tonic-gate 	ndi_devi_enter(parent, &circ);
2651*7c478bd9Sstevel@tonic-gate 
2652*7c478bd9Sstevel@tonic-gate 	switch (op) {
2653*7c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_ONE:
2654*7c478bd9Sstevel@tonic-gate 		/*
2655*7c478bd9Sstevel@tonic-gate 		 * Nothing special required here
2656*7c478bd9Sstevel@tonic-gate 		 */
2657*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2658*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2659*7c478bd9Sstevel@tonic-gate 			    " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent));
2660*7c478bd9Sstevel@tonic-gate 		}
2661*7c478bd9Sstevel@tonic-gate 		break;
2662*7c478bd9Sstevel@tonic-gate 
2663*7c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_DRIVER:
2664*7c478bd9Sstevel@tonic-gate 		if (pshot_debug > 0) {
2665*7c478bd9Sstevel@tonic-gate 			major = (major_t)(uintptr_t)arg;
2666*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
2667*7c478bd9Sstevel@tonic-gate 			    "pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
2668*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent),
2669*7c478bd9Sstevel@tonic-gate 			    ddi_major_to_name(major));
2670*7c478bd9Sstevel@tonic-gate 		}
2671*7c478bd9Sstevel@tonic-gate 		break;
2672*7c478bd9Sstevel@tonic-gate 
2673*7c478bd9Sstevel@tonic-gate 	case BUS_UNCONFIG_ALL:
2674*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2675*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2676*7c478bd9Sstevel@tonic-gate 			    " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent));
2677*7c478bd9Sstevel@tonic-gate 		}
2678*7c478bd9Sstevel@tonic-gate 		break;
2679*7c478bd9Sstevel@tonic-gate 
2680*7c478bd9Sstevel@tonic-gate 	default:
2681*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2682*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n",
2683*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent));
2684*7c478bd9Sstevel@tonic-gate 		}
2685*7c478bd9Sstevel@tonic-gate 		rval = NDI_FAILURE;
2686*7c478bd9Sstevel@tonic-gate 	}
2687*7c478bd9Sstevel@tonic-gate 
2688*7c478bd9Sstevel@tonic-gate 	if (rval == NDI_SUCCESS)
2689*7c478bd9Sstevel@tonic-gate 		rval = ndi_busop_bus_unconfig(parent, flags, op, arg);
2690*7c478bd9Sstevel@tonic-gate 
2691*7c478bd9Sstevel@tonic-gate 	ndi_devi_exit(parent, circ);
2692*7c478bd9Sstevel@tonic-gate 
2693*7c478bd9Sstevel@tonic-gate 	if (pshot_debug)
2694*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n",
2695*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent),
2696*7c478bd9Sstevel@tonic-gate 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
2697*7c478bd9Sstevel@tonic-gate 
2698*7c478bd9Sstevel@tonic-gate 	return (rval);
2699*7c478bd9Sstevel@tonic-gate }
2700*7c478bd9Sstevel@tonic-gate 
2701*7c478bd9Sstevel@tonic-gate static dev_info_t *
2702*7c478bd9Sstevel@tonic-gate pshot_findchild(dev_info_t *pdip, char *cname, char *caddr)
2703*7c478bd9Sstevel@tonic-gate {
2704*7c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
2705*7c478bd9Sstevel@tonic-gate 	char *addr;
2706*7c478bd9Sstevel@tonic-gate 
2707*7c478bd9Sstevel@tonic-gate 	ASSERT(cname != NULL && caddr != NULL);
2708*7c478bd9Sstevel@tonic-gate 	ASSERT(DEVI_BUSY_OWNED(pdip));
2709*7c478bd9Sstevel@tonic-gate 
2710*7c478bd9Sstevel@tonic-gate 	for (dip = ddi_get_child(pdip); dip != NULL;
2711*7c478bd9Sstevel@tonic-gate 	    dip = ddi_get_next_sibling(dip)) {
2712*7c478bd9Sstevel@tonic-gate 		if (strcmp(cname, ddi_node_name(dip)) != 0)
2713*7c478bd9Sstevel@tonic-gate 			continue;
2714*7c478bd9Sstevel@tonic-gate 
2715*7c478bd9Sstevel@tonic-gate 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
2716*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
2717*7c478bd9Sstevel@tonic-gate 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2718*7c478bd9Sstevel@tonic-gate 				if (strcmp(caddr, addr) == 0) {
2719*7c478bd9Sstevel@tonic-gate 					ddi_prop_free(addr);
2720*7c478bd9Sstevel@tonic-gate 					return (dip);
2721*7c478bd9Sstevel@tonic-gate 				}
2722*7c478bd9Sstevel@tonic-gate 				ddi_prop_free(addr);
2723*7c478bd9Sstevel@tonic-gate 			}
2724*7c478bd9Sstevel@tonic-gate 		} else {
2725*7c478bd9Sstevel@tonic-gate 			if (strcmp(caddr, addr) == 0)
2726*7c478bd9Sstevel@tonic-gate 				return (dip);
2727*7c478bd9Sstevel@tonic-gate 		}
2728*7c478bd9Sstevel@tonic-gate 	}
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate 	return (NULL);
2731*7c478bd9Sstevel@tonic-gate }
2732*7c478bd9Sstevel@tonic-gate 
2733*7c478bd9Sstevel@tonic-gate static void
2734*7c478bd9Sstevel@tonic-gate pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2735*7c478bd9Sstevel@tonic-gate     char *caddr)
2736*7c478bd9Sstevel@tonic-gate {
2737*7c478bd9Sstevel@tonic-gate 	char *extension;
2738*7c478bd9Sstevel@tonic-gate 
2739*7c478bd9Sstevel@tonic-gate 	/*
2740*7c478bd9Sstevel@tonic-gate 	 * extract the address extention
2741*7c478bd9Sstevel@tonic-gate 	 */
2742*7c478bd9Sstevel@tonic-gate 	extension = strstr(caddr, ",");
2743*7c478bd9Sstevel@tonic-gate 	if (extension != NULL) {
2744*7c478bd9Sstevel@tonic-gate 		++extension;
2745*7c478bd9Sstevel@tonic-gate 	} else {
2746*7c478bd9Sstevel@tonic-gate 		extension = "null";
2747*7c478bd9Sstevel@tonic-gate 	}
2748*7c478bd9Sstevel@tonic-gate 
2749*7c478bd9Sstevel@tonic-gate 	/*
2750*7c478bd9Sstevel@tonic-gate 	 * Create the "pm-want-child-notification?" property for all
2751*7c478bd9Sstevel@tonic-gate 	 * nodes that do not have the "pm_strict" or "nopm_strict"
2752*7c478bd9Sstevel@tonic-gate 	 * extension
2753*7c478bd9Sstevel@tonic-gate 	 */
2754*7c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "pm_strict") != 0 &&
2755*7c478bd9Sstevel@tonic-gate 	    strcmp(extension, "nopm_strict") != 0) {
2756*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2757*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2758*7c478bd9Sstevel@tonic-gate 		    "pm-want-child-notification?") == 0) {
2759*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2760*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2761*7c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tcreate the"
2762*7c478bd9Sstevel@tonic-gate 				    " \"pm-want-child-notification?\""
2763*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
2764*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
2765*7c478bd9Sstevel@tonic-gate 			}
2766*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2767*7c478bd9Sstevel@tonic-gate 			    "pm-want-child-notification?", NULL, 0)
2768*7c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
2769*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
2770*7c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tunable to create"
2771*7c478bd9Sstevel@tonic-gate 				    " the \"pm-want-child-notification?\""
2772*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s",
2773*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
2774*7c478bd9Sstevel@tonic-gate 			}
2775*7c478bd9Sstevel@tonic-gate 		}
2776*7c478bd9Sstevel@tonic-gate 	}
2777*7c478bd9Sstevel@tonic-gate 
2778*7c478bd9Sstevel@tonic-gate 	/*
2779*7c478bd9Sstevel@tonic-gate 	 * Create the "no-pm-components" property for all nodes
2780*7c478bd9Sstevel@tonic-gate 	 * with extension "nopm" or "nopm_strict"
2781*7c478bd9Sstevel@tonic-gate 	 */
2782*7c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "nopm") == 0 ||
2783*7c478bd9Sstevel@tonic-gate 	    strcmp(extension, "nopm_strict") == 0) {
2784*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2785*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2786*7c478bd9Sstevel@tonic-gate 		    "no-pm-components") == 0) {
2787*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2788*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2789*7c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tcreate the"
2790*7c478bd9Sstevel@tonic-gate 				    " \"no-pm-components\""
2791*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
2792*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
2793*7c478bd9Sstevel@tonic-gate 			}
2794*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2795*7c478bd9Sstevel@tonic-gate 			    "no-pm-components", NULL, 0)
2796*7c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
2797*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
2798*7c478bd9Sstevel@tonic-gate 				    " nexus_properties:\n\tunable to create"
2799*7c478bd9Sstevel@tonic-gate 				    " the \"no-pm-components\""
2800*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s",
2801*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(parent), cname, caddr);
2802*7c478bd9Sstevel@tonic-gate 			}
2803*7c478bd9Sstevel@tonic-gate 		}
2804*7c478bd9Sstevel@tonic-gate 	}
2805*7c478bd9Sstevel@tonic-gate }
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate static void
2808*7c478bd9Sstevel@tonic-gate pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2809*7c478bd9Sstevel@tonic-gate     char *caddr)
2810*7c478bd9Sstevel@tonic-gate {
2811*7c478bd9Sstevel@tonic-gate 	char *extension;
2812*7c478bd9Sstevel@tonic-gate 
2813*7c478bd9Sstevel@tonic-gate 	/*
2814*7c478bd9Sstevel@tonic-gate 	 * extract the address extention
2815*7c478bd9Sstevel@tonic-gate 	 */
2816*7c478bd9Sstevel@tonic-gate 	extension = strstr(caddr, ",");
2817*7c478bd9Sstevel@tonic-gate 	if (extension != NULL) {
2818*7c478bd9Sstevel@tonic-gate 		++extension;
2819*7c478bd9Sstevel@tonic-gate 	} else {
2820*7c478bd9Sstevel@tonic-gate 		extension = "null";
2821*7c478bd9Sstevel@tonic-gate 	}
2822*7c478bd9Sstevel@tonic-gate 
2823*7c478bd9Sstevel@tonic-gate 	/*
2824*7c478bd9Sstevel@tonic-gate 	 * Create the "no-involuntary-power-cycles" property for
2825*7c478bd9Sstevel@tonic-gate 	 * all leaf nodes with extension "no_invol"
2826*7c478bd9Sstevel@tonic-gate 	 */
2827*7c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "no_invol") == 0) {
2828*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2829*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2830*7c478bd9Sstevel@tonic-gate 		    "no-involuntary-power-cycles") == 0) {
2831*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2832*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2833*7c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tcreate the"
2834*7c478bd9Sstevel@tonic-gate 				    " \"no-involuntary-power-cycles\""
2835*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
2836*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
2837*7c478bd9Sstevel@tonic-gate 			}
2838*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
2839*7c478bd9Sstevel@tonic-gate 			    DDI_PROP_CANSLEEP,
2840*7c478bd9Sstevel@tonic-gate 			    "no-involuntary-power-cycles", NULL, 0)
2841*7c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
2842*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
2843*7c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tunable to create the"
2844*7c478bd9Sstevel@tonic-gate 				    " \"no-involuntary-power-cycles\""
2845*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s",
2846*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
2847*7c478bd9Sstevel@tonic-gate 			}
2848*7c478bd9Sstevel@tonic-gate 		}
2849*7c478bd9Sstevel@tonic-gate 	}
2850*7c478bd9Sstevel@tonic-gate 
2851*7c478bd9Sstevel@tonic-gate 	/*
2852*7c478bd9Sstevel@tonic-gate 	 * Create the "dependency-property" property for all leaf
2853*7c478bd9Sstevel@tonic-gate 	 * nodes with extension "dep_prop"
2854*7c478bd9Sstevel@tonic-gate 	 * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
2855*7c478bd9Sstevel@tonic-gate 	 */
2856*7c478bd9Sstevel@tonic-gate 	if (strcmp(extension, "dep_prop") == 0) {
2857*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2858*7c478bd9Sstevel@tonic-gate 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2859*7c478bd9Sstevel@tonic-gate 		    "dependency-property") == 0) {
2860*7c478bd9Sstevel@tonic-gate 			if (pshot_debug) {
2861*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "pshot%d:"
2862*7c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tcreate the"
2863*7c478bd9Sstevel@tonic-gate 				    " \"dependency-property\""
2864*7c478bd9Sstevel@tonic-gate 				    " property for %s@%s\n",
2865*7c478bd9Sstevel@tonic-gate 				    ddi_get_instance(parent), cname, caddr);
2866*7c478bd9Sstevel@tonic-gate 			}
2867*7c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
2868*7c478bd9Sstevel@tonic-gate 			    DDI_PROP_CANSLEEP, "dependency-property", NULL, 0)
2869*7c478bd9Sstevel@tonic-gate 			    != DDI_PROP_SUCCESS) {
2870*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "pshot%d:"
2871*7c478bd9Sstevel@tonic-gate 				    " leaf_properties:\n\tunable to create the"
2872*7c478bd9Sstevel@tonic-gate 				    " \"dependency-property\" property for"
2873*7c478bd9Sstevel@tonic-gate 				    " %s@%s", ddi_get_instance(parent),
2874*7c478bd9Sstevel@tonic-gate 				    cname, caddr);
2875*7c478bd9Sstevel@tonic-gate 			}
2876*7c478bd9Sstevel@tonic-gate 		}
2877*7c478bd9Sstevel@tonic-gate 	}
2878*7c478bd9Sstevel@tonic-gate }
2879*7c478bd9Sstevel@tonic-gate 
2880*7c478bd9Sstevel@tonic-gate /*
2881*7c478bd9Sstevel@tonic-gate  * BUS_CONFIG_ONE: setup a child nexus instance.
2882*7c478bd9Sstevel@tonic-gate  */
2883*7c478bd9Sstevel@tonic-gate static int
2884*7c478bd9Sstevel@tonic-gate pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr)
2885*7c478bd9Sstevel@tonic-gate {
2886*7c478bd9Sstevel@tonic-gate 	dev_info_t *child;
2887*7c478bd9Sstevel@tonic-gate 	int rval;
2888*7c478bd9Sstevel@tonic-gate 
2889*7c478bd9Sstevel@tonic-gate 	ASSERT(parent != 0);
2890*7c478bd9Sstevel@tonic-gate 	ASSERT(cname != NULL);
2891*7c478bd9Sstevel@tonic-gate 	ASSERT(caddr != NULL);
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	child = pshot_findchild(parent, cname, caddr);
2894*7c478bd9Sstevel@tonic-gate 	if (child) {
2895*7c478bd9Sstevel@tonic-gate 		if (pshot_debug) {
2896*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
2897*7c478bd9Sstevel@tonic-gate 			    "pshot%d: bus_config one %s@%s found\n",
2898*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent), cname, caddr);
2899*7c478bd9Sstevel@tonic-gate 		}
2900*7c478bd9Sstevel@tonic-gate 		/*
2901*7c478bd9Sstevel@tonic-gate 		 * create the "pm-want-child-notification?" property
2902*7c478bd9Sstevel@tonic-gate 		 * for this child, if it doesn't already exist
2903*7c478bd9Sstevel@tonic-gate 		 */
2904*7c478bd9Sstevel@tonic-gate 		(void) pshot_nexus_properties(parent, child, cname, caddr);
2905*7c478bd9Sstevel@tonic-gate 
2906*7c478bd9Sstevel@tonic-gate 		return (NDI_SUCCESS);
2907*7c478bd9Sstevel@tonic-gate 	}
2908*7c478bd9Sstevel@tonic-gate 
2909*7c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2910*7c478bd9Sstevel@tonic-gate 	ASSERT(child != NULL);
2911*7c478bd9Sstevel@tonic-gate 
2912*7c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2913*7c478bd9Sstevel@tonic-gate 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2914*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed",
2915*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent), cname, caddr);
2916*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
2917*7c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
2918*7c478bd9Sstevel@tonic-gate 	}
2919*7c478bd9Sstevel@tonic-gate 
2920*7c478bd9Sstevel@tonic-gate 	rval = ndi_devi_bind_driver(child, 0);
2921*7c478bd9Sstevel@tonic-gate 	if (rval != NDI_SUCCESS) {
2922*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
2923*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent), cname);
2924*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
2925*7c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
2926*7c478bd9Sstevel@tonic-gate 	}
2927*7c478bd9Sstevel@tonic-gate 
2928*7c478bd9Sstevel@tonic-gate 	/*
2929*7c478bd9Sstevel@tonic-gate 	 * create the "pm-want-child-notification?" property
2930*7c478bd9Sstevel@tonic-gate 	 */
2931*7c478bd9Sstevel@tonic-gate 	(void) pshot_nexus_properties(parent, child, cname, caddr);
2932*7c478bd9Sstevel@tonic-gate 
2933*7c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
2934*7c478bd9Sstevel@tonic-gate }
2935*7c478bd9Sstevel@tonic-gate 
2936*7c478bd9Sstevel@tonic-gate /*
2937*7c478bd9Sstevel@tonic-gate  * BUS_CONFIG_ONE: setup a child leaf device instance.
2938*7c478bd9Sstevel@tonic-gate  * for testing purposes, we will create nodes of a variety of types.
2939*7c478bd9Sstevel@tonic-gate  */
2940*7c478bd9Sstevel@tonic-gate static int
2941*7c478bd9Sstevel@tonic-gate pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr)
2942*7c478bd9Sstevel@tonic-gate {
2943*7c478bd9Sstevel@tonic-gate 	dev_info_t *child;
2944*7c478bd9Sstevel@tonic-gate 	char *compat_name;
2945*7c478bd9Sstevel@tonic-gate 	char *nodetype;
2946*7c478bd9Sstevel@tonic-gate 	int rval;
2947*7c478bd9Sstevel@tonic-gate 	int i;
2948*7c478bd9Sstevel@tonic-gate 
2949*7c478bd9Sstevel@tonic-gate 	ASSERT(parent != 0);
2950*7c478bd9Sstevel@tonic-gate 	ASSERT(cname != NULL);
2951*7c478bd9Sstevel@tonic-gate 	ASSERT(caddr != NULL);
2952*7c478bd9Sstevel@tonic-gate 
2953*7c478bd9Sstevel@tonic-gate 	/*
2954*7c478bd9Sstevel@tonic-gate 	 * if we already have a node with this name, return it
2955*7c478bd9Sstevel@tonic-gate 	 */
2956*7c478bd9Sstevel@tonic-gate 	if ((child = pshot_findchild(parent, cname, caddr)) != NULL) {
2957*7c478bd9Sstevel@tonic-gate 		/*
2958*7c478bd9Sstevel@tonic-gate 		 * create the "no-involuntary-power-cycles" or
2959*7c478bd9Sstevel@tonic-gate 		 * the "dependency-property" property, if they
2960*7c478bd9Sstevel@tonic-gate 		 * don't already exit
2961*7c478bd9Sstevel@tonic-gate 		 */
2962*7c478bd9Sstevel@tonic-gate 		(void) pshot_leaf_properties(parent, child, cname, caddr);
2963*7c478bd9Sstevel@tonic-gate 
2964*7c478bd9Sstevel@tonic-gate 		return (NDI_SUCCESS);
2965*7c478bd9Sstevel@tonic-gate 	}
2966*7c478bd9Sstevel@tonic-gate 
2967*7c478bd9Sstevel@tonic-gate 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2968*7c478bd9Sstevel@tonic-gate 	ASSERT(child != NULL);
2969*7c478bd9Sstevel@tonic-gate 
2970*7c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr",
2971*7c478bd9Sstevel@tonic-gate 	    caddr) != DDI_PROP_SUCCESS) {
2972*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
2973*7c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
2974*7c478bd9Sstevel@tonic-gate 	}
2975*7c478bd9Sstevel@tonic-gate 
2976*7c478bd9Sstevel@tonic-gate 	/*
2977*7c478bd9Sstevel@tonic-gate 	 * test compatible naming
2978*7c478bd9Sstevel@tonic-gate 	 * if the child nodename is "cdisk", attach the list of compatible
2979*7c478bd9Sstevel@tonic-gate 	 * named disks
2980*7c478bd9Sstevel@tonic-gate 	 */
2981*7c478bd9Sstevel@tonic-gate 	if (strcmp(cname, pshot_compat_diskname) == 0) {
2982*7c478bd9Sstevel@tonic-gate 		if ((ndi_prop_update_string_array(DDI_DEV_T_NONE,
2983*7c478bd9Sstevel@tonic-gate 		    child, "compatible", (char **)pshot_compat_psramdisks,
2984*7c478bd9Sstevel@tonic-gate 		    5)) != DDI_PROP_SUCCESS) {
2985*7c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(child);
2986*7c478bd9Sstevel@tonic-gate 			return (NDI_FAILURE);
2987*7c478bd9Sstevel@tonic-gate 		}
2988*7c478bd9Sstevel@tonic-gate 	} else {
2989*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < pshot_devices_len && pshot_devices[i].name;
2990*7c478bd9Sstevel@tonic-gate 		    i++) {
2991*7c478bd9Sstevel@tonic-gate 			if (strcmp(cname, pshot_devices[i].name) == 0) {
2992*7c478bd9Sstevel@tonic-gate 				compat_name = pshot_devices[i].compat;
2993*7c478bd9Sstevel@tonic-gate 				nodetype = pshot_devices[i].nodetype;
2994*7c478bd9Sstevel@tonic-gate 				if (pshot_debug) {
2995*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "pshot%d: %s %s %s\n",
2996*7c478bd9Sstevel@tonic-gate 					    ddi_get_instance(parent), cname,
2997*7c478bd9Sstevel@tonic-gate 					    compat_name, nodetype);
2998*7c478bd9Sstevel@tonic-gate 				}
2999*7c478bd9Sstevel@tonic-gate 				if ((ndi_prop_update_string_array(
3000*7c478bd9Sstevel@tonic-gate 				    DDI_DEV_T_NONE, child, "compatible",
3001*7c478bd9Sstevel@tonic-gate 				    &compat_name, 1)) != DDI_PROP_SUCCESS) {
3002*7c478bd9Sstevel@tonic-gate 					(void) ndi_devi_free(child);
3003*7c478bd9Sstevel@tonic-gate 					return (NDI_FAILURE);
3004*7c478bd9Sstevel@tonic-gate 				}
3005*7c478bd9Sstevel@tonic-gate 				if ((ndi_prop_update_string(
3006*7c478bd9Sstevel@tonic-gate 				    DDI_DEV_T_NONE, child, "node-type",
3007*7c478bd9Sstevel@tonic-gate 				    nodetype)) != DDI_PROP_SUCCESS) {
3008*7c478bd9Sstevel@tonic-gate 					(void) ndi_devi_free(child);
3009*7c478bd9Sstevel@tonic-gate 					return (NDI_FAILURE);
3010*7c478bd9Sstevel@tonic-gate 				}
3011*7c478bd9Sstevel@tonic-gate 			}
3012*7c478bd9Sstevel@tonic-gate 		}
3013*7c478bd9Sstevel@tonic-gate 	}
3014*7c478bd9Sstevel@tonic-gate 
3015*7c478bd9Sstevel@tonic-gate 	rval = ndi_devi_bind_driver(child, 0);
3016*7c478bd9Sstevel@tonic-gate 	if (rval != NDI_SUCCESS) {
3017*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
3018*7c478bd9Sstevel@tonic-gate 		    ddi_get_instance(parent), cname);
3019*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(child);
3020*7c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
3021*7c478bd9Sstevel@tonic-gate 	}
3022*7c478bd9Sstevel@tonic-gate 
3023*7c478bd9Sstevel@tonic-gate 	/*
3024*7c478bd9Sstevel@tonic-gate 	 * create the "no-involuntary-power-cycles" or
3025*7c478bd9Sstevel@tonic-gate 	 * the "dependency-property" property
3026*7c478bd9Sstevel@tonic-gate 	 */
3027*7c478bd9Sstevel@tonic-gate 	(void) pshot_leaf_properties(parent, child, cname, caddr);
3028*7c478bd9Sstevel@tonic-gate 
3029*7c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
3030*7c478bd9Sstevel@tonic-gate }
3031*7c478bd9Sstevel@tonic-gate 
3032*7c478bd9Sstevel@tonic-gate /*
3033*7c478bd9Sstevel@tonic-gate  * Handle some special cases for testing bus_config via pshot
3034*7c478bd9Sstevel@tonic-gate  *
3035*7c478bd9Sstevel@tonic-gate  * Match these special address formats to behavior:
3036*7c478bd9Sstevel@tonic-gate  *
3037*7c478bd9Sstevel@tonic-gate  *	err.*		- induce bus_config error
3038*7c478bd9Sstevel@tonic-gate  *	delay		- induce 1 second of bus_config delay time
3039*7c478bd9Sstevel@tonic-gate  *	delay,n		- induce n seconds of bus_config delay time
3040*7c478bd9Sstevel@tonic-gate  *	wait		- induce 1 second of bus_config wait time
3041*7c478bd9Sstevel@tonic-gate  *	wait,n		- induce n seconds of bus_config wait time
3042*7c478bd9Sstevel@tonic-gate  *	failinit.*	- induce error at INITCHILD
3043*7c478bd9Sstevel@tonic-gate  *	failprobe.*	- induce error at probe
3044*7c478bd9Sstevel@tonic-gate  *	failattach.*	- induce error at attach
3045*7c478bd9Sstevel@tonic-gate  */
3046*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3047*7c478bd9Sstevel@tonic-gate static int
3048*7c478bd9Sstevel@tonic-gate pshot_bus_config_test_specials(dev_info_t *parent, char *devname,
3049*7c478bd9Sstevel@tonic-gate 	char *cname, char *caddr)
3050*7c478bd9Sstevel@tonic-gate {
3051*7c478bd9Sstevel@tonic-gate 	char	*p;
3052*7c478bd9Sstevel@tonic-gate 	int	n;
3053*7c478bd9Sstevel@tonic-gate 
3054*7c478bd9Sstevel@tonic-gate 	if (strncmp(caddr, "err", 3) == 0) {
3055*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
3056*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
3057*7c478bd9Sstevel@tonic-gate 			    "pshot%d: %s forced failure\n",
3058*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(parent), devname);
3059*7c478bd9Sstevel@tonic-gate 		return (NDI_FAILURE);
3060*7c478bd9Sstevel@tonic-gate 	}
3061*7c478bd9Sstevel@tonic-gate 
3062*7c478bd9Sstevel@tonic-gate 	/*
3063*7c478bd9Sstevel@tonic-gate 	 * The delay and wait strings have the same effect.
3064*7c478bd9Sstevel@tonic-gate 	 * The "wait[,]" support should be removed once the
3065*7c478bd9Sstevel@tonic-gate 	 * devfs test suites are fixed.
3066*7c478bd9Sstevel@tonic-gate 	 * NOTE: delay should not be called from interrupt context
3067*7c478bd9Sstevel@tonic-gate 	 */
3068*7c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
3069*7c478bd9Sstevel@tonic-gate 
3070*7c478bd9Sstevel@tonic-gate 	if (strncmp(caddr, "delay,", 6) == 0) {
3071*7c478bd9Sstevel@tonic-gate 		p = caddr+6;
3072*7c478bd9Sstevel@tonic-gate 		n = stoi(&p);
3073*7c478bd9Sstevel@tonic-gate 		if (*p != 0)
3074*7c478bd9Sstevel@tonic-gate 			n = 1;
3075*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
3076*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
3077*7c478bd9Sstevel@tonic-gate 			    "pshot%d: %s delay %d second\n",
3078*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(parent), devname, n);
3079*7c478bd9Sstevel@tonic-gate 		delay(n * drv_usectohz(1000000));
3080*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(caddr, "delay", 5) == 0) {
3081*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
3082*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
3083*7c478bd9Sstevel@tonic-gate 			    "pshot%d: %s delay 1 second\n",
3084*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(parent), devname);
3085*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
3086*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(caddr, "wait,", 5) == 0) {
3087*7c478bd9Sstevel@tonic-gate 		p = caddr+5;
3088*7c478bd9Sstevel@tonic-gate 		n = stoi(&p);
3089*7c478bd9Sstevel@tonic-gate 		if (*p != 0)
3090*7c478bd9Sstevel@tonic-gate 			n = 1;
3091*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
3092*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
3093*7c478bd9Sstevel@tonic-gate 			    "pshot%d: %s wait %d second\n",
3094*7c478bd9Sstevel@tonic-gate 				ddi_get_instance(parent), devname, n);
3095*7c478bd9Sstevel@tonic-gate 		delay(n * drv_usectohz(1000000));
3096*7c478bd9Sstevel@tonic-gate 	} else if (strncmp(caddr, "wait", 4) == 0) {
3097*7c478bd9Sstevel@tonic-gate 		if (pshot_debug)
3098*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
3099*7c478bd9Sstevel@tonic-gate 			    "pshot%d: %s wait 1 second\n",
3100*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(parent), devname);
3101*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
3102*7c478bd9Sstevel@tonic-gate 	}
3103*7c478bd9Sstevel@tonic-gate 
3104*7c478bd9Sstevel@tonic-gate 	return (NDI_SUCCESS);
3105*7c478bd9Sstevel@tonic-gate }
3106*7c478bd9Sstevel@tonic-gate 
3107*7c478bd9Sstevel@tonic-gate /*
3108*7c478bd9Sstevel@tonic-gate  * translate nodetype name to actual value
3109*7c478bd9Sstevel@tonic-gate  */
3110*7c478bd9Sstevel@tonic-gate static char *
3111*7c478bd9Sstevel@tonic-gate pshot_str2nt(char *str)
3112*7c478bd9Sstevel@tonic-gate {
3113*7c478bd9Sstevel@tonic-gate 	int i;
3114*7c478bd9Sstevel@tonic-gate 
3115*7c478bd9Sstevel@tonic-gate 	for (i = 0; pshot_nodetypes[i].name; i++) {
3116*7c478bd9Sstevel@tonic-gate 		if (strcmp(pshot_nodetypes[i].name, str) == 0)
3117*7c478bd9Sstevel@tonic-gate 			return (pshot_nodetypes[i].val);
3118*7c478bd9Sstevel@tonic-gate 	}
3119*7c478bd9Sstevel@tonic-gate 	return (NULL);
3120*7c478bd9Sstevel@tonic-gate }
3121*7c478bd9Sstevel@tonic-gate 
3122*7c478bd9Sstevel@tonic-gate /*
3123*7c478bd9Sstevel@tonic-gate  * grows array pointed to by <dstp>, with <src> data
3124*7c478bd9Sstevel@tonic-gate  * <dstlen> = # elements of the original <*dstp>
3125*7c478bd9Sstevel@tonic-gate  * <srclen> = # elements of <src>
3126*7c478bd9Sstevel@tonic-gate  *
3127*7c478bd9Sstevel@tonic-gate  * on success, returns 0 and a pointer to the new array through <dstp> with
3128*7c478bd9Sstevel@tonic-gate  * <srclen> + <dstlen> number of elements;
3129*7c478bd9Sstevel@tonic-gate  * else returns non-zero
3130*7c478bd9Sstevel@tonic-gate  *
3131*7c478bd9Sstevel@tonic-gate  * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
3132*7c478bd9Sstevel@tonic-gate  */
3133*7c478bd9Sstevel@tonic-gate static int
3134*7c478bd9Sstevel@tonic-gate pshot_devices_grow(pshot_device_t **dstp, size_t dstlen,
3135*7c478bd9Sstevel@tonic-gate     const pshot_device_t *src, size_t srclen)
3136*7c478bd9Sstevel@tonic-gate {
3137*7c478bd9Sstevel@tonic-gate 	size_t i;
3138*7c478bd9Sstevel@tonic-gate 	pshot_device_t *newdst;
3139*7c478bd9Sstevel@tonic-gate 
3140*7c478bd9Sstevel@tonic-gate 	newdst = kmem_alloc((srclen + dstlen) * sizeof (*src),
3141*7c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
3142*7c478bd9Sstevel@tonic-gate 
3143*7c478bd9Sstevel@tonic-gate 	/* keep old pointers and dup new ones */
3144*7c478bd9Sstevel@tonic-gate 	if (*dstp)
3145*7c478bd9Sstevel@tonic-gate 		bcopy(*dstp, newdst, dstlen * sizeof (*src));
3146*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < srclen; i++) {
3147*7c478bd9Sstevel@tonic-gate 		newdst[i + dstlen].name =
3148*7c478bd9Sstevel@tonic-gate 		    i_ddi_strdup(src[i].name, KM_SLEEP);
3149*7c478bd9Sstevel@tonic-gate 
3150*7c478bd9Sstevel@tonic-gate 		newdst[i + dstlen].nodetype =
3151*7c478bd9Sstevel@tonic-gate 		    i_ddi_strdup(src[i].nodetype, KM_SLEEP);
3152*7c478bd9Sstevel@tonic-gate 
3153*7c478bd9Sstevel@tonic-gate 		newdst[i + dstlen].compat =
3154*7c478bd9Sstevel@tonic-gate 		    i_ddi_strdup(src[i].compat, KM_SLEEP);
3155*7c478bd9Sstevel@tonic-gate 	}
3156*7c478bd9Sstevel@tonic-gate 
3157*7c478bd9Sstevel@tonic-gate 	/* do last */
3158*7c478bd9Sstevel@tonic-gate 	if (*dstp)
3159*7c478bd9Sstevel@tonic-gate 		kmem_free(*dstp, dstlen * sizeof (*src));
3160*7c478bd9Sstevel@tonic-gate 	*dstp = newdst;
3161*7c478bd9Sstevel@tonic-gate 	return (0);
3162*7c478bd9Sstevel@tonic-gate }
3163*7c478bd9Sstevel@tonic-gate 
3164*7c478bd9Sstevel@tonic-gate /*
3165*7c478bd9Sstevel@tonic-gate  * free a pshot_device_t array <dp> with <len> elements
3166*7c478bd9Sstevel@tonic-gate  * null pointers within the elements are ok
3167*7c478bd9Sstevel@tonic-gate  */
3168*7c478bd9Sstevel@tonic-gate static void
3169*7c478bd9Sstevel@tonic-gate pshot_devices_free(pshot_device_t *dp, size_t len)
3170*7c478bd9Sstevel@tonic-gate {
3171*7c478bd9Sstevel@tonic-gate 	size_t i;
3172*7c478bd9Sstevel@tonic-gate 
3173*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
3174*7c478bd9Sstevel@tonic-gate 		if (dp[i].name)
3175*7c478bd9Sstevel@tonic-gate 			kmem_free(dp[i].name, strlen(dp[i].name) + 1);
3176*7c478bd9Sstevel@tonic-gate 		if (dp[i].nodetype)
3177*7c478bd9Sstevel@tonic-gate 			kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1);
3178*7c478bd9Sstevel@tonic-gate 		if (dp[i].compat)
3179*7c478bd9Sstevel@tonic-gate 			kmem_free(dp[i].compat, strlen(dp[i].compat) + 1);
3180*7c478bd9Sstevel@tonic-gate 	}
3181*7c478bd9Sstevel@tonic-gate 	kmem_free(dp, len * sizeof (*dp));
3182*7c478bd9Sstevel@tonic-gate }
3183*7c478bd9Sstevel@tonic-gate 
3184*7c478bd9Sstevel@tonic-gate /*
3185*7c478bd9Sstevel@tonic-gate  * returns an array of pshot_device_t parsed from <dip>'s properties
3186*7c478bd9Sstevel@tonic-gate  *
3187*7c478bd9Sstevel@tonic-gate  * property structure (i.e. pshot.conf) for pshot:
3188*7c478bd9Sstevel@tonic-gate  *
3189*7c478bd9Sstevel@tonic-gate  * corresponding         |   pshot_device_t array elements
3190*7c478bd9Sstevel@tonic-gate  * pshot_device_t        |
3191*7c478bd9Sstevel@tonic-gate  * member by prop name   |   [0]            [1]           [2]
3192*7c478bd9Sstevel@tonic-gate  * ----------------------|--------------|-------------|-----------------------
3193*7c478bd9Sstevel@tonic-gate  * <PSHOT_PROP_DEVNAME>  ="disk",        "tape",       "testdev";
3194*7c478bd9Sstevel@tonic-gate  * <PSHOT_PROP_DEVNT>    ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
3195*7c478bd9Sstevel@tonic-gate  * <PSHOT_PROP_DEVCOMPAT>="testdrv",     "testdrv",    "testdrv";
3196*7c478bd9Sstevel@tonic-gate  *
3197*7c478bd9Sstevel@tonic-gate  *
3198*7c478bd9Sstevel@tonic-gate  * if any of these properties are specified, then:
3199*7c478bd9Sstevel@tonic-gate  * - all the members must be specified
3200*7c478bd9Sstevel@tonic-gate  * - the number of elements for each string array property must be the same
3201*7c478bd9Sstevel@tonic-gate  * - no empty strings allowed
3202*7c478bd9Sstevel@tonic-gate  * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
3203*7c478bd9Sstevel@tonic-gate  *   sys/sunddi.h
3204*7c478bd9Sstevel@tonic-gate  *
3205*7c478bd9Sstevel@tonic-gate  * NOTE: the pshot_nodetypes[] table should be kept in sync with the list
3206*7c478bd9Sstevel@tonic-gate  * of ddi nodetypes.  It's not normally critical to always be in sync so
3207*7c478bd9Sstevel@tonic-gate  * keeping this up-to-date can usually be done "on-demand".
3208*7c478bd9Sstevel@tonic-gate  *
3209*7c478bd9Sstevel@tonic-gate  * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
3210*7c478bd9Sstevel@tonic-gate  * these will be duplicated verbatim
3211*7c478bd9Sstevel@tonic-gate  */
3212*7c478bd9Sstevel@tonic-gate static pshot_device_t *
3213*7c478bd9Sstevel@tonic-gate pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags)
3214*7c478bd9Sstevel@tonic-gate {
3215*7c478bd9Sstevel@tonic-gate 	pshot_device_t *devarr = NULL;
3216*7c478bd9Sstevel@tonic-gate 	char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL;
3217*7c478bd9Sstevel@tonic-gate 	uint_t name_arr_len, nt_arr_len, compat_arr_len;
3218*7c478bd9Sstevel@tonic-gate 	uint_t i;
3219*7c478bd9Sstevel@tonic-gate 	char *str;
3220*7c478bd9Sstevel@tonic-gate 
3221*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3222*7c478bd9Sstevel@tonic-gate 	    PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) !=
3223*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
3224*7c478bd9Sstevel@tonic-gate 		name_arr = NULL;
3225*7c478bd9Sstevel@tonic-gate 
3226*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3227*7c478bd9Sstevel@tonic-gate 	    PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) !=
3228*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
3229*7c478bd9Sstevel@tonic-gate 		nt_arr = NULL;
3230*7c478bd9Sstevel@tonic-gate 
3231*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3232*7c478bd9Sstevel@tonic-gate 	    PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) !=
3233*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
3234*7c478bd9Sstevel@tonic-gate 		compat_arr = NULL;
3235*7c478bd9Sstevel@tonic-gate 
3236*7c478bd9Sstevel@tonic-gate 	/*
3237*7c478bd9Sstevel@tonic-gate 	 * warn about any incorrect usage, if specified
3238*7c478bd9Sstevel@tonic-gate 	 */
3239*7c478bd9Sstevel@tonic-gate 	if (!(name_arr || nt_arr || compat_arr))
3240*7c478bd9Sstevel@tonic-gate 		return (NULL);
3241*7c478bd9Sstevel@tonic-gate 
3242*7c478bd9Sstevel@tonic-gate 	if (!(name_arr && nt_arr && compat_arr) ||
3243*7c478bd9Sstevel@tonic-gate 	    (name_arr_len != nt_arr_len) ||
3244*7c478bd9Sstevel@tonic-gate 	    (name_arr_len != compat_arr_len))
3245*7c478bd9Sstevel@tonic-gate 		goto FAIL;
3246*7c478bd9Sstevel@tonic-gate 
3247*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < name_arr_len; i++) {
3248*7c478bd9Sstevel@tonic-gate 		if (*name_arr[i] == '\0' ||
3249*7c478bd9Sstevel@tonic-gate 		    *nt_arr[i] == '\0' ||
3250*7c478bd9Sstevel@tonic-gate 		    *compat_arr[i] == '\0')
3251*7c478bd9Sstevel@tonic-gate 			goto FAIL;
3252*7c478bd9Sstevel@tonic-gate 	}
3253*7c478bd9Sstevel@tonic-gate 
3254*7c478bd9Sstevel@tonic-gate 	devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP);
3255*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < name_arr_len; i++) {
3256*7c478bd9Sstevel@tonic-gate 		devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP);
3257*7c478bd9Sstevel@tonic-gate 		devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP);
3258*7c478bd9Sstevel@tonic-gate 
3259*7c478bd9Sstevel@tonic-gate 		if ((str = pshot_str2nt(nt_arr[i])) == NULL)
3260*7c478bd9Sstevel@tonic-gate 			if (flags & PSHOT_DEV_ANYNT)
3261*7c478bd9Sstevel@tonic-gate 				str = nt_arr[i];
3262*7c478bd9Sstevel@tonic-gate 			else
3263*7c478bd9Sstevel@tonic-gate 				goto FAIL;
3264*7c478bd9Sstevel@tonic-gate 		devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP);
3265*7c478bd9Sstevel@tonic-gate 	}
3266*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(name_arr);
3267*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(nt_arr);
3268*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(compat_arr);
3269*7c478bd9Sstevel@tonic-gate 
3270*7c478bd9Sstevel@tonic-gate 	/* set <*lenp> ONLY on success */
3271*7c478bd9Sstevel@tonic-gate 	*lenp = name_arr_len;
3272*7c478bd9Sstevel@tonic-gate 
3273*7c478bd9Sstevel@tonic-gate 	return (devarr);
3274*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
3275*7c478bd9Sstevel@tonic-gate FAIL:
3276*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "malformed device specification property");
3277*7c478bd9Sstevel@tonic-gate 	if (name_arr)
3278*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(name_arr);
3279*7c478bd9Sstevel@tonic-gate 	if (nt_arr)
3280*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(nt_arr);
3281*7c478bd9Sstevel@tonic-gate 	if (compat_arr)
3282*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(compat_arr);
3283*7c478bd9Sstevel@tonic-gate 	if (devarr)
3284*7c478bd9Sstevel@tonic-gate 		pshot_devices_free(devarr, name_arr_len);
3285*7c478bd9Sstevel@tonic-gate 	return (NULL);
3286*7c478bd9Sstevel@tonic-gate }
3287*7c478bd9Sstevel@tonic-gate 
3288*7c478bd9Sstevel@tonic-gate /*
3289*7c478bd9Sstevel@tonic-gate  * if global <pshot_devices> was not set up already (i.e. is NULL):
3290*7c478bd9Sstevel@tonic-gate  *	sets up global <pshot_devices> and <pshot_devices_len>,
3291*7c478bd9Sstevel@tonic-gate  *	using device properties	from <dip> and global <pshot_stock_devices>.
3292*7c478bd9Sstevel@tonic-gate  *	device properties, if any, overrides pshot_stock_devices.
3293*7c478bd9Sstevel@tonic-gate  *
3294*7c478bd9Sstevel@tonic-gate  * returns 0 on success (or if pshot_devices already set up)
3295*7c478bd9Sstevel@tonic-gate  *
3296*7c478bd9Sstevel@tonic-gate  * INTERNAL LOCKING: <pshot_devices_lock>
3297*7c478bd9Sstevel@tonic-gate  */
3298*7c478bd9Sstevel@tonic-gate static int
3299*7c478bd9Sstevel@tonic-gate pshot_devices_setup(dev_info_t *dip)
3300*7c478bd9Sstevel@tonic-gate {
3301*7c478bd9Sstevel@tonic-gate 	pshot_device_t *newdevs = NULL;
3302*7c478bd9Sstevel@tonic-gate 	size_t newdevs_len = 0;
3303*7c478bd9Sstevel@tonic-gate 	int rv = 0;
3304*7c478bd9Sstevel@tonic-gate 
3305*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pshot_devices_lock);
3306*7c478bd9Sstevel@tonic-gate 	if (pshot_devices != NULL)
3307*7c478bd9Sstevel@tonic-gate 		goto FAIL;
3308*7c478bd9Sstevel@tonic-gate 
3309*7c478bd9Sstevel@tonic-gate 	ASSERT(pshot_devices_len == 0);
3310*7c478bd9Sstevel@tonic-gate 
3311*7c478bd9Sstevel@tonic-gate 	newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT);
3312*7c478bd9Sstevel@tonic-gate 	rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices,
3313*7c478bd9Sstevel@tonic-gate 	    PSHOT_N_STOCK_DEVICES);
3314*7c478bd9Sstevel@tonic-gate 	if (rv != 0) {
3315*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow "
3316*7c478bd9Sstevel@tonic-gate 		    "failed");
3317*7c478bd9Sstevel@tonic-gate 		goto FAIL;
3318*7c478bd9Sstevel@tonic-gate 	}
3319*7c478bd9Sstevel@tonic-gate 	newdevs_len += PSHOT_N_STOCK_DEVICES;
3320*7c478bd9Sstevel@tonic-gate 
3321*7c478bd9Sstevel@tonic-gate 	pshot_devices = newdevs;
3322*7c478bd9Sstevel@tonic-gate 	pshot_devices_len = newdevs_len;
3323*7c478bd9Sstevel@tonic-gate 	rv = 0;
3324*7c478bd9Sstevel@tonic-gate FAIL:
3325*7c478bd9Sstevel@tonic-gate 	if (rv && newdevs)
3326*7c478bd9Sstevel@tonic-gate 		pshot_devices_free(newdevs, newdevs_len);
3327*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pshot_devices_lock);
3328*7c478bd9Sstevel@tonic-gate 	return (rv);
3329*7c478bd9Sstevel@tonic-gate }
3330*7c478bd9Sstevel@tonic-gate 
3331*7c478bd9Sstevel@tonic-gate 
3332*7c478bd9Sstevel@tonic-gate #ifdef NOTNEEDED
3333*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
3334*7c478bd9Sstevel@tonic-gate static int
3335*7c478bd9Sstevel@tonic-gate pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how,
3336*7c478bd9Sstevel@tonic-gate     dev_info_t **return_dip)
3337*7c478bd9Sstevel@tonic-gate {
3338*7c478bd9Sstevel@tonic-gate 	char name[64];
3339*7c478bd9Sstevel@tonic-gate 	uint_t bus_id;
3340*7c478bd9Sstevel@tonic-gate 	dev_info_t *child;
3341*7c478bd9Sstevel@tonic-gate 
3342*7c478bd9Sstevel@tonic-gate 	for (bus_id = 10; bus_id < 20; bus_id++) {
3343*7c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "%d", bus_id);
3344*7c478bd9Sstevel@tonic-gate 		if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID,
3345*7c478bd9Sstevel@tonic-gate 		    &child)) != NDI_SUCCESS) {
3346*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3347*7c478bd9Sstevel@tonic-gate 		}
3348*7c478bd9Sstevel@tonic-gate 
3349*7c478bd9Sstevel@tonic-gate 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
3350*7c478bd9Sstevel@tonic-gate 		    "bus-addr", name) != DDI_PROP_SUCCESS) {
3351*7c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(child);
3352*7c478bd9Sstevel@tonic-gate 			if (return_dip != NULL)
3353*7c478bd9Sstevel@tonic-gate 				*return_dip = (dev_info_t *)NULL;
3354*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3355*7c478bd9Sstevel@tonic-gate 		}
3356*7c478bd9Sstevel@tonic-gate 
3357*7c478bd9Sstevel@tonic-gate 		if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
3358*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3359*7c478bd9Sstevel@tonic-gate 		}
3360*7c478bd9Sstevel@tonic-gate 	}
3361*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3362*7c478bd9Sstevel@tonic-gate }
3363*7c478bd9Sstevel@tonic-gate #endif
3364*7c478bd9Sstevel@tonic-gate 
3365*7c478bd9Sstevel@tonic-gate #ifdef NOTNEEDED
3366*7c478bd9Sstevel@tonic-gate static int
3367*7c478bd9Sstevel@tonic-gate strtoi(char *str)
3368*7c478bd9Sstevel@tonic-gate {
3369*7c478bd9Sstevel@tonic-gate 	int c;
3370*7c478bd9Sstevel@tonic-gate 	int val;
3371*7c478bd9Sstevel@tonic-gate 
3372*7c478bd9Sstevel@tonic-gate 	for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
3373*7c478bd9Sstevel@tonic-gate 		val *= 10;
3374*7c478bd9Sstevel@tonic-gate 		val += c - '0';
3375*7c478bd9Sstevel@tonic-gate 	}
3376*7c478bd9Sstevel@tonic-gate 	return (val);
3377*7c478bd9Sstevel@tonic-gate }
3378*7c478bd9Sstevel@tonic-gate #endif
3379*7c478bd9Sstevel@tonic-gate 
3380*7c478bd9Sstevel@tonic-gate struct m_to_reg {
3381*7c478bd9Sstevel@tonic-gate 	char	*mc;
3382*7c478bd9Sstevel@tonic-gate 	int	n_regs;
3383*7c478bd9Sstevel@tonic-gate 	int	regs[3];
3384*7c478bd9Sstevel@tonic-gate };
3385*7c478bd9Sstevel@tonic-gate 
3386*7c478bd9Sstevel@tonic-gate struct m_to_reg m_regspecs[] = {
3387*7c478bd9Sstevel@tonic-gate 	{"sun4c", 3, {0xf, 0x6000000, 0x20}},
3388*7c478bd9Sstevel@tonic-gate 	{"sun4d", 3, {0xf, 0x6000000, 0x20}},
3389*7c478bd9Sstevel@tonic-gate 	{"sun4m", 3, {0xf, 0x6000000, 0x20}},
3390*7c478bd9Sstevel@tonic-gate 	{"sun4u", 3, {0xf, 0x6000000, 0x20}},
3391*7c478bd9Sstevel@tonic-gate 	{"i86pc", 3, {0xf, 0x6000000, 0x20}},
3392*7c478bd9Sstevel@tonic-gate 	{NULL, 0, {0, 0, 0}},
3393*7c478bd9Sstevel@tonic-gate };
3394*7c478bd9Sstevel@tonic-gate 
3395*7c478bd9Sstevel@tonic-gate 
3396*7c478bd9Sstevel@tonic-gate static void
3397*7c478bd9Sstevel@tonic-gate pshot_setup_autoattach(dev_info_t *devi)
3398*7c478bd9Sstevel@tonic-gate {
3399*7c478bd9Sstevel@tonic-gate 	dev_info_t *l1child, *l2child;
3400*7c478bd9Sstevel@tonic-gate 	int rv;
3401*7c478bd9Sstevel@tonic-gate 
3402*7c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child);
3403*7c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS) {
3404*7c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3405*7c478bd9Sstevel@tonic-gate 		    "bus-addr", "0");
3406*7c478bd9Sstevel@tonic-gate 		rv =  ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID,
3407*7c478bd9Sstevel@tonic-gate 		    &l2child);
3408*7c478bd9Sstevel@tonic-gate 		if (rv == NDI_SUCCESS)
3409*7c478bd9Sstevel@tonic-gate 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
3410*7c478bd9Sstevel@tonic-gate 			    l2child, "bus-addr", "99");
3411*7c478bd9Sstevel@tonic-gate 	}
3412*7c478bd9Sstevel@tonic-gate 
3413*7c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child);
3414*7c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
3415*7c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3416*7c478bd9Sstevel@tonic-gate 		    "bus-addr", "99");
3417*7c478bd9Sstevel@tonic-gate 
3418*7c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child);
3419*7c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
3420*7c478bd9Sstevel@tonic-gate 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3421*7c478bd9Sstevel@tonic-gate 		    "bus-addr", "99");
3422*7c478bd9Sstevel@tonic-gate 
3423*7c478bd9Sstevel@tonic-gate 	rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child);
3424*7c478bd9Sstevel@tonic-gate 	if (rv == NDI_SUCCESS)
3425*7c478bd9Sstevel@tonic-gate 		(void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID,
3426*7c478bd9Sstevel@tonic-gate 		    &l2child);
3427*7c478bd9Sstevel@tonic-gate }
3428*7c478bd9Sstevel@tonic-gate 
3429*7c478bd9Sstevel@tonic-gate #ifdef PRUNE_SNUBS
3430*7c478bd9Sstevel@tonic-gate 
3431*7c478bd9Sstevel@tonic-gate #define	PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \
3432*7c478bd9Sstevel@tonic-gate 	(DEVI_PROM_NODE((d)->devi_nodeid)) && \
3433*7c478bd9Sstevel@tonic-gate 	((d)->devi_addr == NULL))
3434*7c478bd9Sstevel@tonic-gate /*
3435*7c478bd9Sstevel@tonic-gate  * test code to remove OBP nodes that have not attached
3436*7c478bd9Sstevel@tonic-gate  */
3437*7c478bd9Sstevel@tonic-gate static void
3438*7c478bd9Sstevel@tonic-gate prune_snubs(const char *name)
3439*7c478bd9Sstevel@tonic-gate {
3440*7c478bd9Sstevel@tonic-gate 	struct dev_info *nex_dip, *cdip, *cndip;
3441*7c478bd9Sstevel@tonic-gate 	int maj;
3442*7c478bd9Sstevel@tonic-gate 	int rv;
3443*7c478bd9Sstevel@tonic-gate 
3444*7c478bd9Sstevel@tonic-gate 	maj = ddi_name_to_major((char *)name);
3445*7c478bd9Sstevel@tonic-gate 	if (maj != -1) {
3446*7c478bd9Sstevel@tonic-gate 		nex_dip = (struct dev_info *)devnamesp[maj].dn_head;
3447*7c478bd9Sstevel@tonic-gate 		while (nex_dip != NULL) {
3448*7c478bd9Sstevel@tonic-gate 			cndip = ddi_get_child(nex_dip);
3449*7c478bd9Sstevel@tonic-gate 			while ((cdip = cndip) != NULL) {
3450*7c478bd9Sstevel@tonic-gate 				cndip = cdip->devi_sibling;
3451*7c478bd9Sstevel@tonic-gate 				if (PRUNE_THIS_NODE(cdip)) {
3452*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_NOTE,
3453*7c478bd9Sstevel@tonic-gate 					    "parent %s@%s pruning node %s",
3454*7c478bd9Sstevel@tonic-gate 					    nex_dip->devi_node_name,
3455*7c478bd9Sstevel@tonic-gate 					    nex_dip->devi_addr,
3456*7c478bd9Sstevel@tonic-gate 					    cdip->devi_node_name);
3457*7c478bd9Sstevel@tonic-gate 					rv = ndi_devi_offline(cdip,
3458*7c478bd9Sstevel@tonic-gate 					    NDI_DEVI_REMOVE);
3459*7c478bd9Sstevel@tonic-gate 					if (rv != NDI_SUCCESS)
3460*7c478bd9Sstevel@tonic-gate 						cmn_err(CE_NOTE,
3461*7c478bd9Sstevel@tonic-gate 						    "failed to prune node, "
3462*7c478bd9Sstevel@tonic-gate 						    "err %d", rv);
3463*7c478bd9Sstevel@tonic-gate 				}
3464*7c478bd9Sstevel@tonic-gate 			}
3465*7c478bd9Sstevel@tonic-gate 		nex_dip = nex_dip->devi_next;
3466*7c478bd9Sstevel@tonic-gate 		}
3467*7c478bd9Sstevel@tonic-gate 	}
3468*7c478bd9Sstevel@tonic-gate }
3469*7c478bd9Sstevel@tonic-gate 
3470*7c478bd9Sstevel@tonic-gate #endif /* PRUBE_SNUBS */
3471*7c478bd9Sstevel@tonic-gate 
3472*7c478bd9Sstevel@tonic-gate #ifdef KERNEL_DEVICE_TREE_WALKER
3473*7c478bd9Sstevel@tonic-gate static kthread_id_t pwt;
3474*7c478bd9Sstevel@tonic-gate static kmutex_t pwl;
3475*7c478bd9Sstevel@tonic-gate static kcondvar_t pwcv;
3476*7c478bd9Sstevel@tonic-gate 
3477*7c478bd9Sstevel@tonic-gate static void
3478*7c478bd9Sstevel@tonic-gate pshot_walk_tree()
3479*7c478bd9Sstevel@tonic-gate {
3480*7c478bd9Sstevel@tonic-gate 	static int pshot_devnode(dev_info_t *dip, void * arg);
3481*7c478bd9Sstevel@tonic-gate 
3482*7c478bd9Sstevel@tonic-gate 	dev_info_t *root = ddi_root_node();
3483*7c478bd9Sstevel@tonic-gate 	ddi_walk_devs(root, pshot_devnode, NULL);
3484*7c478bd9Sstevel@tonic-gate }
3485*7c478bd9Sstevel@tonic-gate 
3486*7c478bd9Sstevel@tonic-gate static void
3487*7c478bd9Sstevel@tonic-gate pshot_walk_thread()
3488*7c478bd9Sstevel@tonic-gate {
3489*7c478bd9Sstevel@tonic-gate 	static void pshot_timeout(void *arg);
3490*7c478bd9Sstevel@tonic-gate 	static kthread_id_t pwt;
3491*7c478bd9Sstevel@tonic-gate 
3492*7c478bd9Sstevel@tonic-gate 	pwt = curthread;
3493*7c478bd9Sstevel@tonic-gate 	mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL);
3494*7c478bd9Sstevel@tonic-gate 	cv_init(&pwcv, NULL, CV_DRIVER, NULL);
3495*7c478bd9Sstevel@tonic-gate 
3496*7c478bd9Sstevel@tonic-gate 	while (1) {
3497*7c478bd9Sstevel@tonic-gate 		pshot_walk_tree();
3498*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pwl);
3499*7c478bd9Sstevel@tonic-gate 		(void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000));
3500*7c478bd9Sstevel@tonic-gate 		cv_wait(&pwcv, &pwl);
3501*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pwl);
3502*7c478bd9Sstevel@tonic-gate 	}
3503*7c478bd9Sstevel@tonic-gate }
3504*7c478bd9Sstevel@tonic-gate 
3505*7c478bd9Sstevel@tonic-gate static void
3506*7c478bd9Sstevel@tonic-gate pshot_timeout(void *arg)
3507*7c478bd9Sstevel@tonic-gate {
3508*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pwl);
3509*7c478bd9Sstevel@tonic-gate 	cv_signal(&pwcv);
3510*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pwl);
3511*7c478bd9Sstevel@tonic-gate }
3512*7c478bd9Sstevel@tonic-gate 
3513*7c478bd9Sstevel@tonic-gate static int
3514*7c478bd9Sstevel@tonic-gate pshot_devnode(dev_info_t *dip, void *arg)
3515*7c478bd9Sstevel@tonic-gate {
3516*7c478bd9Sstevel@tonic-gate 	dev_info_t *f_dip;
3517*7c478bd9Sstevel@tonic-gate 
3518*7c478bd9Sstevel@tonic-gate 	if (dip != ddi_root_node()) {
3519*7c478bd9Sstevel@tonic-gate 		f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent,
3520*7c478bd9Sstevel@tonic-gate 		    DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr);
3521*7c478bd9Sstevel@tonic-gate 		if (f_dip != dip) {
3522*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!pshot_devnode: failed lookup"
3523*7c478bd9Sstevel@tonic-gate 			"node (%s/%s@%s)\n",
3524*7c478bd9Sstevel@tonic-gate 			DEVI(DEVI(dip)->devi_parent)->devi_node_name,
3525*7c478bd9Sstevel@tonic-gate 			(DEVI(dip)->devi_node_name ?
3526*7c478bd9Sstevel@tonic-gate 				DEVI(dip)->devi_node_name : "NULL"),
3527*7c478bd9Sstevel@tonic-gate 			(DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr : "NULL"));
3528*7c478bd9Sstevel@tonic-gate 		}
3529*7c478bd9Sstevel@tonic-gate 	}
3530*7c478bd9Sstevel@tonic-gate 	return (DDI_WALK_CONTINUE);
3531*7c478bd9Sstevel@tonic-gate }
3532*7c478bd9Sstevel@tonic-gate #endif /* KERNEL_DEVICE_TREE_WALKER */
3533*7c478bd9Sstevel@tonic-gate 
3534*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
3535*7c478bd9Sstevel@tonic-gate static void
3536*7c478bd9Sstevel@tonic-gate pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie,
3537*7c478bd9Sstevel@tonic-gate 	void *arg, void *bus_impldata)
3538*7c478bd9Sstevel@tonic-gate {
3539*7c478bd9Sstevel@tonic-gate 	pshot_t *softstate = (pshot_t *)arg;
3540*7c478bd9Sstevel@tonic-gate 	int event_tag;
3541*7c478bd9Sstevel@tonic-gate 
3542*7c478bd9Sstevel@tonic-gate 	/* look up the event */
3543*7c478bd9Sstevel@tonic-gate 	event_tag = NDI_EVENT_TAG(cookie);
3544*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot_event_cb_test:\n\t"
3545*7c478bd9Sstevel@tonic-gate 	    "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
3546*7c478bd9Sstevel@tonic-gate 	    "arg = 0x%p bus_impl = 0x%p\n",
3547*7c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie),
3548*7c478bd9Sstevel@tonic-gate 	    event_tag, (void *)softstate, (void *)bus_impldata);
3549*7c478bd9Sstevel@tonic-gate 
3550*7c478bd9Sstevel@tonic-gate }
3551*7c478bd9Sstevel@tonic-gate 
3552*7c478bd9Sstevel@tonic-gate static void
3553*7c478bd9Sstevel@tonic-gate pshot_event_test(void *arg)
3554*7c478bd9Sstevel@tonic-gate {
3555*7c478bd9Sstevel@tonic-gate 	pshot_t *pshot = (pshot_t *)arg;
3556*7c478bd9Sstevel@tonic-gate 	ndi_event_hdl_t hdl;
3557*7c478bd9Sstevel@tonic-gate 	ndi_event_set_t	events;
3558*7c478bd9Sstevel@tonic-gate 	int i, rval;
3559*7c478bd9Sstevel@tonic-gate 
3560*7c478bd9Sstevel@tonic-gate 	(void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP);
3561*7c478bd9Sstevel@tonic-gate 
3562*7c478bd9Sstevel@tonic-gate 	events.ndi_events_version = NDI_EVENTS_REV1;
3563*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3564*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3565*7c478bd9Sstevel@tonic-gate 
3566*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3567*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3568*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3569*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3570*7c478bd9Sstevel@tonic-gate 
3571*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3572*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3573*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3574*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3575*7c478bd9Sstevel@tonic-gate 
3576*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
3577*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3578*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3579*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3580*7c478bd9Sstevel@tonic-gate 
3581*7c478bd9Sstevel@tonic-gate 
3582*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3583*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3584*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3585*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
3586*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3587*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3588*7c478bd9Sstevel@tonic-gate 
3589*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3590*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3591*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3592*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3593*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3594*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3595*7c478bd9Sstevel@tonic-gate 
3596*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3597*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3598*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3599*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
3600*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3601*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3602*7c478bd9Sstevel@tonic-gate 
3603*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3604*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3605*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3606*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
3607*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3608*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3609*7c478bd9Sstevel@tonic-gate 
3610*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3611*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3612*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3613*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events_high;
3614*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3615*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3616*7c478bd9Sstevel@tonic-gate 
3617*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3618*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3619*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3620*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3621*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3622*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3623*7c478bd9Sstevel@tonic-gate 
3624*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding first 2 events\n");
3625*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3626*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
3627*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3628*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3629*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3630*7c478bd9Sstevel@tonic-gate 
3631*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n");
3632*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3633*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
3634*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3635*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3636*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3637*7c478bd9Sstevel@tonic-gate 
3638*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  middle 2 events\n");
3639*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3640*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
3641*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
3642*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3643*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3644*7c478bd9Sstevel@tonic-gate 
3645*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding those 2 events back\n");
3646*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3647*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
3648*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
3649*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3650*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3651*7c478bd9Sstevel@tonic-gate 
3652*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  2 events\n");
3653*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3654*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 2;
3655*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[4];
3656*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3657*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3658*7c478bd9Sstevel@tonic-gate 
3659*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
3660*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3661*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3662*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3663*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3664*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3665*7c478bd9Sstevel@tonic-gate 
3666*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3667*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3668*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3669*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[2];
3670*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3671*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3672*7c478bd9Sstevel@tonic-gate 
3673*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3674*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3675*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3676*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[3];
3677*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3678*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3679*7c478bd9Sstevel@tonic-gate 
3680*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3681*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3682*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3683*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[6];
3684*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3685*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3686*7c478bd9Sstevel@tonic-gate 
3687*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3688*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3689*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = 1;
3690*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = &pshot_test_events[7];
3691*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3692*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3693*7c478bd9Sstevel@tonic-gate 
3694*7c478bd9Sstevel@tonic-gate 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3695*7c478bd9Sstevel@tonic-gate 	events.ndi_event_defs = pshot_test_events;
3696*7c478bd9Sstevel@tonic-gate 
3697*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3698*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3699*7c478bd9Sstevel@tonic-gate 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3700*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3701*7c478bd9Sstevel@tonic-gate 
3702*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: adding 8 callbacks\n");
3703*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3704*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
3705*7c478bd9Sstevel@tonic-gate 		rval = ndi_event_add_callback(hdl, pshot->dip,
3706*7c478bd9Sstevel@tonic-gate 			ndi_event_tag_to_cookie(hdl,
3707*7c478bd9Sstevel@tonic-gate 				pshot_test_events[i].ndi_event_tag),
3708*7c478bd9Sstevel@tonic-gate 			pshot_event_cb_test,
3709*7c478bd9Sstevel@tonic-gate 			(void *)(uintptr_t)pshot_test_events[i].ndi_event_tag,
3710*7c478bd9Sstevel@tonic-gate 			NDI_SLEEP, &pshot->test_callback_cache[i]);
3711*7c478bd9Sstevel@tonic-gate 		ASSERT(rval == NDI_SUCCESS);
3712*7c478bd9Sstevel@tonic-gate 	}
3713*7c478bd9Sstevel@tonic-gate 
3714*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: event callbacks\n");
3715*7c478bd9Sstevel@tonic-gate 
3716*7c478bd9Sstevel@tonic-gate 	for (i = 10; i < 18; i++) {
3717*7c478bd9Sstevel@tonic-gate 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3718*7c478bd9Sstevel@tonic-gate 
3719*7c478bd9Sstevel@tonic-gate 		rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie,
3720*7c478bd9Sstevel@tonic-gate 		    (void *)hdl);
3721*7c478bd9Sstevel@tonic-gate 
3722*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3723*7c478bd9Sstevel@tonic-gate 			i, rval);
3724*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
3725*7c478bd9Sstevel@tonic-gate 	}
3726*7c478bd9Sstevel@tonic-gate 
3727*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: redo event callbacks\n");
3728*7c478bd9Sstevel@tonic-gate 
3729*7c478bd9Sstevel@tonic-gate 	for (i = 10; i < 18; i++) {
3730*7c478bd9Sstevel@tonic-gate 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3731*7c478bd9Sstevel@tonic-gate 
3732*7c478bd9Sstevel@tonic-gate 		rval = ndi_event_run_callbacks(hdl,
3733*7c478bd9Sstevel@tonic-gate 			pshot->dip, cookie, (void *)hdl);
3734*7c478bd9Sstevel@tonic-gate 
3735*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3736*7c478bd9Sstevel@tonic-gate 			i, rval);
3737*7c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(1000000));
3738*7c478bd9Sstevel@tonic-gate 	}
3739*7c478bd9Sstevel@tonic-gate 
3740*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: removing 8 callbacks\n");
3741*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3742*7c478bd9Sstevel@tonic-gate 
3743*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
3744*7c478bd9Sstevel@tonic-gate 		(void) ndi_event_remove_callback(hdl,
3745*7c478bd9Sstevel@tonic-gate 		    pshot->test_callback_cache[i]);
3746*7c478bd9Sstevel@tonic-gate 
3747*7c478bd9Sstevel@tonic-gate 		pshot->test_callback_cache[i] = 0;
3748*7c478bd9Sstevel@tonic-gate 	}
3749*7c478bd9Sstevel@tonic-gate 
3750*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot: freeing handle with bound set\n");
3751*7c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(1000000));
3752*7c478bd9Sstevel@tonic-gate 
3753*7c478bd9Sstevel@tonic-gate 	rval =	ndi_event_free_hdl(hdl);
3754*7c478bd9Sstevel@tonic-gate 
3755*7c478bd9Sstevel@tonic-gate 	ASSERT(rval == NDI_SUCCESS);
3756*7c478bd9Sstevel@tonic-gate 
3757*7c478bd9Sstevel@tonic-gate }
3758*7c478bd9Sstevel@tonic-gate 
3759*7c478bd9Sstevel@tonic-gate void
3760*7c478bd9Sstevel@tonic-gate pshot_event_test_post_one(void *arg)
3761*7c478bd9Sstevel@tonic-gate {
3762*7c478bd9Sstevel@tonic-gate 	pshot_t	*pshot = (pshot_t *)arg;
3763*7c478bd9Sstevel@tonic-gate 	int rval;
3764*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
3765*7c478bd9Sstevel@tonic-gate 
3766*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n",
3767*7c478bd9Sstevel@tonic-gate 		pshot->instance);
3768*7c478bd9Sstevel@tonic-gate 
3769*7c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST,
3770*7c478bd9Sstevel@tonic-gate 	    &cookie) != DDI_SUCCESS) {
3771*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found");
3772*7c478bd9Sstevel@tonic-gate 		return;
3773*7c478bd9Sstevel@tonic-gate 	}
3774*7c478bd9Sstevel@tonic-gate 
3775*7c478bd9Sstevel@tonic-gate 	rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL);
3776*7c478bd9Sstevel@tonic-gate 
3777*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n",
3778*7c478bd9Sstevel@tonic-gate 		pshot->instance, rval);
3779*7c478bd9Sstevel@tonic-gate 
3780*7c478bd9Sstevel@tonic-gate 	(void) timeout(pshot_event_test_post_one, (void *)pshot,
3781*7c478bd9Sstevel@tonic-gate 		pshot->instance * drv_usectohz(60000000));
3782*7c478bd9Sstevel@tonic-gate 
3783*7c478bd9Sstevel@tonic-gate }
3784*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
3785