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