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