xref: /illumos-gate/usr/src/uts/common/io/pshot.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
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_SIDDEV:
1106 	case DDI_CTLOPS_SLAVEONLY:
1107 	case DDI_CTLOPS_AFFINITY:
1108 	case DDI_CTLOPS_POKE:
1109 	case DDI_CTLOPS_PEEK:
1110 		/*
1111 		 * These ops correspond to functions that "shouldn't" be called
1112 		 * by a pseudo driver.  So we whine when we're called.
1113 		 */
1114 		cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
1115 			ddi_get_name(dip), ddi_get_instance(dip),
1116 			ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
1117 		return (DDI_FAILURE);
1118 
1119 	case DDI_CTLOPS_ATTACH:
1120 	{
1121 		dev_info_t *child = (dev_info_t *)rdip;
1122 		childname = ddi_node_name(child);
1123 		childinstance = ddi_get_instance(child);
1124 		as = (struct attachspec *)arg;
1125 
1126 		no_pm_components_child = 0;
1127 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1128 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1129 		    "no-pm-components") == 1) {
1130 			no_pm_components_child = 1;
1131 		}
1132 		if (pshot_debug) {
1133 			cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n",
1134 			    name, instance, childname, childinstance,
1135 			    no_pm_components_child);
1136 		}
1137 
1138 		ndi_devi_enter(dip, &circ);
1139 
1140 		switch (as->when) {
1141 		case DDI_PRE:
1142 			/*
1143 			 * Mark nexus busy before a child attaches.
1144 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1145 			 * - pshot@XXX,nopm_strict)
1146 			 */
1147 			if (!(pshot->state & PM_SUPPORTED))
1148 				break;
1149 			mutex_enter(&pshot->lock);
1150 			++(pshot->busy);
1151 			if (pshot_debug_busy) {
1152 				cmn_err(CE_CONT, "%s%d:"
1153 				    " ctl_attach_pre: busy for %s%d:"
1154 				    " busy = %d\n", name, instance,
1155 				    childname, childinstance,
1156 				    pshot->busy);
1157 			}
1158 			mutex_exit(&pshot->lock);
1159 			rval = pm_busy_component(dip, 0);
1160 			ASSERT(rval == DDI_SUCCESS);
1161 			break;
1162 		case DDI_POST:
1163 			/*
1164 			 * Mark nexus idle after a child attaches.
1165 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
1166 			 * - also skip if this is not a stict parent and
1167 			 * - the child is a tape device or a no-pm-components
1168 			 * - nexus node.
1169 			 */
1170 			if (!(pshot->state & PM_SUPPORTED) ||
1171 			    (strcmp(childname, "tape") == 0 &&
1172 			    !(pshot->state & STRICT_PARENT)) ||
1173 			    no_pm_components_child)
1174 				break;
1175 			mutex_enter(&pshot->lock);
1176 			ASSERT(pshot->busy > 0);
1177 			--pshot->busy;
1178 			if (pshot_debug_busy) {
1179 				cmn_err(CE_CONT, "%s%d:"
1180 				    " ctl_attach_post: idle for %s%d:"
1181 				    " busy = %d\n", name, instance,
1182 				    childname, childinstance,
1183 				    pshot->busy);
1184 			}
1185 			mutex_exit(&pshot->lock);
1186 			rval = pm_idle_component(dip, 0);
1187 			ASSERT(rval == DDI_SUCCESS);
1188 			break;
1189 		}
1190 
1191 		ndi_devi_exit(dip, circ);
1192 
1193 		return (rval);
1194 	}
1195 	case DDI_CTLOPS_BTOP:
1196 	case DDI_CTLOPS_BTOPR:
1197 	case DDI_CTLOPS_DETACH:
1198 		{
1199 		dev_info_t *child = (dev_info_t *)rdip;
1200 		childname = ddi_node_name(child);
1201 		childinstance = ddi_get_instance(child);
1202 		ds = (struct detachspec *)arg;
1203 
1204 		no_pm_components_child = 0;
1205 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1206 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1207 		    "no-pm-components") == 1) {
1208 			no_pm_components_child = 1;
1209 		}
1210 		if (pshot_debug) {
1211 			cmn_err(CE_CONT,
1212 			    "%s%d: ctl_detach %s%d [%d]\n",
1213 			    name, instance, childname, childinstance,
1214 			    no_pm_components_child);
1215 		}
1216 
1217 		ndi_devi_enter(dip, &circ);
1218 
1219 		switch (ds->when) {
1220 		case DDI_PRE:
1221 			/*
1222 			 * Mark nexus busy before a child detaches.
1223 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1224 			 * - pshot@XXX,nopm_strict), or if the child is a
1225 			 * - no-pm-components nexus node.
1226 			 */
1227 			if (!(pshot->state & PM_SUPPORTED) ||
1228 			    (strcmp(childname, "tape") == 0 &&
1229 			    !(pshot->state & STRICT_PARENT)) ||
1230 			    no_pm_components_child)
1231 				break;
1232 			mutex_enter(&pshot->lock);
1233 			++(pshot->busy);
1234 			if (pshot_debug_busy) {
1235 				cmn_err(CE_CONT, "%s%d:"
1236 				    " ctl_detach_pre: busy for %s%d:"
1237 				    " busy = %d\n", name, instance,
1238 				    childname, childinstance,
1239 				    pshot->busy);
1240 			}
1241 			mutex_exit(&pshot->lock);
1242 			rval = pm_busy_component(dip, 0);
1243 			ASSERT(rval == DDI_SUCCESS);
1244 
1245 			break;
1246 		case DDI_POST:
1247 			/*
1248 			 * Mark nexus idle after a child detaches.
1249 			 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1250 			 */
1251 			if (!(pshot->state & PM_SUPPORTED))
1252 				break;
1253 			mutex_enter(&pshot->lock);
1254 			ASSERT(pshot->busy > 0);
1255 			--pshot->busy;
1256 			if (pshot_debug_busy) {
1257 				cmn_err(CE_CONT, "%s%d:"
1258 				    " ctl_detach_post: idle for %s%d:"
1259 				    " busy = %d\n", name, instance,
1260 				    childname, childinstance,
1261 				    pshot->busy);
1262 			}
1263 			mutex_exit(&pshot->lock);
1264 			rval = pm_idle_component(dip, 0);
1265 			ASSERT(rval == DDI_SUCCESS);
1266 
1267 			/*
1268 			 * Mark the driver idle if the NO_INVOL_FLAG
1269 			 * is set. This is needed to make sure the
1270 			 * parent is idle after the child detaches
1271 			 * without calling pm_lower_power().
1272 			 * Clear the NO_INVOL_FLAG.
1273 			 * - also mark idle if a tape device has detached
1274 			 */
1275 			if (!(pshot->state & NO_INVOL_FLAG))
1276 				break;
1277 			mutex_enter(&pshot->lock);
1278 			ASSERT(pshot->busy > 0);
1279 			--pshot->busy;
1280 			if (pshot_debug_busy) {
1281 				cmn_err(CE_CONT, "%s%d:"
1282 				    " ctl_detach_post: NO_INVOL:"
1283 				    " idle for %s%d: busy = %d\n",
1284 				    name, instance, childname,
1285 				    childinstance, pshot->busy);
1286 			}
1287 			pshot->state &= ~NO_INVOL_FLAG;
1288 			mutex_exit(&pshot->lock);
1289 			rval = pm_idle_component(dip, 0);
1290 			ASSERT(rval == DDI_SUCCESS);
1291 
1292 			break;
1293 		}
1294 
1295 		ndi_devi_exit(dip, circ);
1296 
1297 		return (rval);
1298 	}
1299 
1300 	case DDI_CTLOPS_DVMAPAGESIZE:
1301 	case DDI_CTLOPS_IOMIN:
1302 	case DDI_CTLOPS_PTOB:
1303 	default:
1304 		/*
1305 		 * The ops that we pass up (default).  We pass up memory
1306 		 * allocation oriented ops that we receive - these may be
1307 		 * associated with pseudo HBA drivers below us with target
1308 		 * drivers below them that use ddi memory allocation
1309 		 * interfaces like scsi_alloc_consistent_buf.
1310 		 */
1311 		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1312 	}
1313 }
1314 
1315 /*ARGSUSED0*/
1316 static int
1317 pshot_power(dev_info_t *dip, int cmpt, int level)
1318 {
1319 	pshot_t *pshot;
1320 	int instance = ddi_get_instance(dip);
1321 	char *name = ddi_node_name(dip);
1322 	int circ;
1323 	int rv;
1324 
1325 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
1326 	if (pshot == NULL) {
1327 
1328 		return (DDI_FAILURE);
1329 	}
1330 
1331 	ndi_devi_enter(dip, &circ);
1332 
1333 	/*
1334 	 * set POWER_FLAG when power() is called.
1335 	 * ioctl(DEVCT_PM_POWER) is a clear on read call.
1336 	 */
1337 	mutex_enter(&pshot->lock);
1338 	pshot->state |= POWER_FLAG;
1339 	/*
1340 	 * refuse to power OFF if the component is busy
1341 	 */
1342 	if (pshot->busy != 0 && pshot->level > level) {
1343 		cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE"
1344 		    " (%d->%d), DEVICE NOT IDLE: busy = %d",
1345 		    name, instance, pshot->level, level, pshot->busy);
1346 		rv = DDI_FAILURE;
1347 	} else {
1348 		if (pshot_debug) {
1349 			cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n",
1350 			    name, instance, cmpt, pshot->level, level);
1351 		}
1352 		pshot->level = level;
1353 		rv = DDI_SUCCESS;
1354 	}
1355 	mutex_exit(&pshot->lock);
1356 
1357 	ndi_devi_exit(dip, circ);
1358 
1359 	return (rv);
1360 }
1361 
1362 /*ARGSUSED0*/
1363 static int
1364 pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1365     void *arg, void *result)
1366 
1367 {
1368 	int 				ret;
1369 	int 				instance = ddi_get_instance(dip);
1370 	char				*name = ddi_node_name(dip);
1371 	pshot_t 			*pshot;
1372 	pm_bp_child_pwrchg_t		*bpc;
1373 	pm_bp_nexus_pwrup_t		bpn;
1374 	pm_bp_has_changed_t		*bphc;
1375 	int				pwrup_res;
1376 	int				ret_failed = 0;
1377 	int				pwrup_res_failed = 0;
1378 
1379 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
1380 	if (pshot == NULL) {
1381 
1382 		return (DDI_FAILURE);
1383 	}
1384 
1385 	switch (op) {
1386 	case BUS_POWER_PRE_NOTIFICATION:
1387 		bpc = (pm_bp_child_pwrchg_t *)arg;
1388 		if (pshot_debug) {
1389 			cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1390 			    " %s%d comp %d (%d->%d)\n",
1391 			    name, instance, ddi_node_name(bpc->bpc_dip),
1392 			    ddi_get_instance(bpc->bpc_dip),
1393 			    bpc->bpc_comp, bpc->bpc_olevel,
1394 			    bpc->bpc_nlevel);
1395 		}
1396 
1397 		/*
1398 		 * mark parent busy if old_level is either -1 or 0,
1399 		 * and new level is == MAXPWR
1400 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1401 		 */
1402 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1403 		    bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) {
1404 			mutex_enter(&pshot->lock);
1405 			++(pshot->busy);
1406 			if (pshot_debug_busy) {
1407 				cmn_err(CE_CONT,
1408 				    "%s%d: pre_bus_power:"
1409 				    " busy parent for %s%d (%d->%d): "
1410 				    " busy = %d\n",
1411 				    name, instance,
1412 				    ddi_node_name(bpc->bpc_dip),
1413 				    ddi_get_instance(bpc->bpc_dip),
1414 				    bpc->bpc_olevel, bpc->bpc_nlevel,
1415 				    pshot->busy);
1416 			}
1417 			mutex_exit(&pshot->lock);
1418 			ret = pm_busy_component(dip, 0);
1419 			ASSERT(ret == DDI_SUCCESS);
1420 		}
1421 
1422 		/*
1423 		 * if new_level > 0, power up parent, if not already at
1424 		 * MAXPWR, via pm_busop_bus_power
1425 		 * - skip for the no-pm nexus (pshot@XXX,nopm)
1426 		 */
1427 		if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 &&
1428 		    pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) {
1429 			/*
1430 			 * stuff the bpn struct
1431 			 */
1432 			bpn.bpn_comp = 0;
1433 			bpn.bpn_level = MAXPWR;
1434 			bpn.bpn_private = bpc->bpc_private;
1435 			bpn.bpn_dip = dip;
1436 
1437 			/*
1438 			 * ask pm to power parent up
1439 			 */
1440 			if (pshot_debug) {
1441 				cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1442 				    " pm_busop_bus_power on parent for %s%d"
1443 				    " (%d->%d): enter", name, instance,
1444 				    ddi_node_name(bpc->bpc_dip),
1445 				    ddi_get_instance(bpc->bpc_dip),
1446 				    bpc->bpc_olevel, bpc->bpc_nlevel);
1447 			}
1448 			ret = pm_busop_bus_power(dip, impl_arg,
1449 			    BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1450 			    (void *)&pwrup_res);
1451 
1452 			/*
1453 			 * check the return status individually,
1454 			 * idle parent and exit if either failed.
1455 			 */
1456 			if (ret != DDI_SUCCESS) {
1457 				cmn_err(CE_WARN,
1458 				    "%s%d: pre_bus_power:"
1459 				    " pm_busop_bus_power FAILED (ret) FOR"
1460 				    " %s%d (%d->%d)",
1461 				    name, instance,
1462 				    ddi_node_name(bpc->bpc_dip),
1463 				    ddi_get_instance(bpc->bpc_dip),
1464 				    bpc->bpc_olevel, bpc->bpc_nlevel);
1465 				ret_failed = 1;
1466 			}
1467 			if (pwrup_res != DDI_SUCCESS) {
1468 				cmn_err(CE_WARN,
1469 				    "%s%d: pre_bus_power:"
1470 				    " pm_busop_bus_power FAILED (pwrup_res)"
1471 				    " FOR %s%d (%d->%d)",
1472 				    name, instance,
1473 				    ddi_node_name(bpc->bpc_dip),
1474 				    ddi_get_instance(bpc->bpc_dip),
1475 				    bpc->bpc_olevel, bpc->bpc_nlevel);
1476 				pwrup_res_failed = 1;
1477 			}
1478 			if (ret_failed || pwrup_res_failed) {
1479 				/*
1480 				 * decrement the busy count if it
1481 				 * had been incremented.
1482 				 */
1483 				if ((bpc->bpc_comp == 0 &&
1484 				    bpc->bpc_nlevel == MAXPWR &&
1485 				    bpc->bpc_olevel <= 0) &&
1486 				    (pshot->state & PM_SUPPORTED)) {
1487 					mutex_enter(&pshot->lock);
1488 					ASSERT(pshot->busy > 0);
1489 					--(pshot->busy);
1490 					if (pshot_debug_busy) {
1491 						cmn_err(CE_CONT, "%s%d:"
1492 						    " pm_busop_bus_power"
1493 						    " failed: idle parent for"
1494 						    " %s%d (%d->%d):"
1495 						    " busy = %d\n",
1496 						    name, instance,
1497 						    ddi_node_name(
1498 						    bpc->bpc_dip),
1499 						    ddi_get_instance(
1500 						    bpc->bpc_dip),
1501 						    bpc->bpc_olevel,
1502 						    bpc->bpc_nlevel,
1503 						    pshot->busy);
1504 					}
1505 					mutex_exit(&pshot->lock);
1506 					ret = pm_idle_component(dip, 0);
1507 					ASSERT(ret == DDI_SUCCESS);
1508 				}
1509 				return (DDI_FAILURE);
1510 
1511 			} else {
1512 				if (pshot_debug) {
1513 					cmn_err(CE_CONT,
1514 					    "%s%d: pre_bus_power:"
1515 					    " pm_busop_bus_power on parent"
1516 					    " for %s%d (%d->%d)\n",
1517 					    name, instance,
1518 					    ddi_node_name(bpc->bpc_dip),
1519 					    ddi_get_instance(bpc->bpc_dip),
1520 					    bpc->bpc_olevel, bpc->bpc_nlevel);
1521 				}
1522 			}
1523 		}
1524 		break;
1525 
1526 	case BUS_POWER_POST_NOTIFICATION:
1527 		bpc = (pm_bp_child_pwrchg_t *)arg;
1528 		if (pshot_debug) {
1529 			cmn_err(CE_CONT, "%s%d: post_bus_power:"
1530 			    " %s%d comp %d (%d->%d) result %d\n",
1531 			    name, instance, ddi_node_name(bpc->bpc_dip),
1532 			    ddi_get_instance(bpc->bpc_dip),
1533 			    bpc->bpc_comp, bpc->bpc_olevel,
1534 			    bpc->bpc_nlevel, *(int *)result);
1535 		}
1536 
1537 		/*
1538 		 * handle pm_busop_bus_power() failure case.
1539 		 * mark parent idle if had been marked busy.
1540 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1541 		 */
1542 		if (*(int *)result != DDI_SUCCESS) {
1543 			cmn_err(CE_WARN,
1544 			    "pshot%d: post_bus_power_failed:"
1545 			    " pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
1546 			    instance, ddi_node_name(bpc->bpc_dip),
1547 			    ddi_get_instance(bpc->bpc_dip),
1548 			    bpc->bpc_olevel, bpc->bpc_nlevel);
1549 
1550 			if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1551 			    bpc->bpc_olevel <= 0) &&
1552 			    (pshot->state & PM_SUPPORTED)) {
1553 				mutex_enter(&pshot->lock);
1554 				ASSERT(pshot->busy > 0);
1555 				--(pshot->busy);
1556 				if (pshot_debug_busy) {
1557 					cmn_err(CE_CONT, "%s%d:"
1558 					    " post_bus_power_failed:"
1559 					    " idle parent for %s%d"
1560 					    " (%d->%d): busy = %d\n",
1561 					    name, instance,
1562 					    ddi_node_name(bpc->bpc_dip),
1563 					    ddi_get_instance(bpc->bpc_dip),
1564 					    bpc->bpc_olevel, bpc->bpc_nlevel,
1565 					    pshot->busy);
1566 				}
1567 				mutex_exit(&pshot->lock);
1568 				ret = pm_idle_component(dip, 0);
1569 				ASSERT(ret == DDI_SUCCESS);
1570 			}
1571 		}
1572 
1573 		/*
1574 		 * Mark nexus idle when a child's comp 0
1575 		 * is set to level 0 from level 1, 2, or 3 only.
1576 		 * And only if result arg == DDI_SUCCESS.
1577 		 * This will leave the parent busy when the child
1578 		 * does not call pm_lower_power() on detach after
1579 		 * unsetting the NO_LOWER_POWER flag.
1580 		 * If so, need to notify the parent to mark itself
1581 		 * idle anyway, else the no-involumtary-power-cycles
1582 		 * test cases will report false passes!
1583 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1584 		 */
1585 		if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 &&
1586 		    !(bpc->bpc_olevel <= 0) &&
1587 		    *(int *)result == DDI_SUCCESS) &&
1588 		    (pshot->state & PM_SUPPORTED)) {
1589 			mutex_enter(&pshot->lock);
1590 			ASSERT(pshot->busy > 0);
1591 			--(pshot->busy);
1592 			if (pshot_debug_busy) {
1593 				cmn_err(CE_CONT,
1594 				    "%s%d: post_bus_power:"
1595 				    " idle parent for %s%d (%d->%d):"
1596 				    " busy = %d\n", name, instance,
1597 				    ddi_node_name(bpc->bpc_dip),
1598 				    ddi_get_instance(bpc->bpc_dip),
1599 				    bpc->bpc_olevel, bpc->bpc_nlevel,
1600 				    pshot->busy);
1601 			}
1602 			mutex_exit(&pshot->lock);
1603 			ret = pm_idle_component(dip, 0);
1604 			ASSERT(ret == DDI_SUCCESS);
1605 		}
1606 		break;
1607 
1608 	case BUS_POWER_HAS_CHANGED:
1609 		bphc = (pm_bp_has_changed_t *)arg;
1610 		if (pshot_debug) {
1611 			cmn_err(CE_CONT, "%s%d: has_changed_bus_power:"
1612 			    " %s%d comp %d (%d->%d) result %d\n",
1613 			    name, instance, ddi_node_name(bphc->bphc_dip),
1614 			    ddi_get_instance(bphc->bphc_dip),
1615 			    bphc->bphc_comp, bphc->bphc_olevel,
1616 			    bphc->bphc_nlevel, *(int *)result);
1617 		}
1618 
1619 		/*
1620 		 * Mark nexus idle when a child's comp 0
1621 		 * is set to level 0 from levels 1, 2, or 3 only.
1622 		 *
1623 		 * If powering up child leaf/nexus nodes via
1624 		 * pm_power_has_changed() calls, first issue
1625 		 * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
1626 		 * before powering the parent up, then power up the
1627 		 * child node.
1628 		 * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1629 		 */
1630 		if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 &&
1631 		    !(bphc->bphc_olevel <= 0)) &&
1632 		    pshot->state & PM_SUPPORTED) {
1633 			mutex_enter(&pshot->lock);
1634 			ASSERT(pshot->busy > 0);
1635 			--(pshot->busy);
1636 			if (pshot_debug_busy) {
1637 				cmn_err(CE_CONT,
1638 				    "%s%d: has_changed_bus_power:"
1639 				    " idle parent for %s%d (%d->%d):"
1640 				    " busy = %d\n", name, instance,
1641 				    ddi_node_name(bphc->bphc_dip),
1642 				    ddi_get_instance(bphc->bphc_dip),
1643 				    bphc->bphc_olevel,
1644 				    bphc->bphc_nlevel, pshot->busy);
1645 			}
1646 			mutex_exit(&pshot->lock);
1647 			ret = pm_idle_component(dip, 0);
1648 			ASSERT(ret == DDI_SUCCESS);
1649 		}
1650 		break;
1651 
1652 	default:
1653 		return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
1654 
1655 	}
1656 
1657 	return (DDI_SUCCESS);
1658 }
1659 
1660 static int
1661 pshot_initchild(dev_info_t *dip, dev_info_t *child)
1662 {
1663 	char	name[64];
1664 	char	*bus_addr;
1665 	char	*c_nodename;
1666 	int	bus_id;
1667 	dev_info_t *enum_child;
1668 	int	enum_base;
1669 	int	enum_extent;
1670 
1671 
1672 	/* check for bus_enum node */
1673 
1674 #ifdef	NOT_USED
1675 	if (impl_ddi_merge_child(child) != DDI_SUCCESS)
1676 		return (DDI_FAILURE);
1677 #endif
1678 
1679 	enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1680 	    "busid_ebase", 0);
1681 
1682 	enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child,
1683 	    DDI_PROP_DONTPASS, "busid_range", 0);
1684 
1685 	/*
1686 	 * bus enumeration node
1687 	 */
1688 	if ((enum_base != 0) && (enum_extent != 0))	{
1689 		c_nodename = ddi_node_name(child);
1690 		bus_id = enum_base;
1691 		for (; bus_id < enum_extent; bus_id++) {
1692 			if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID,
1693 			    &enum_child) != NDI_SUCCESS)
1694 				return (DDI_FAILURE);
1695 
1696 			(void) sprintf(name, "%d", bus_id);
1697 			if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child,
1698 			    "bus-addr", name) != DDI_PROP_SUCCESS) {
1699 				(void) ndi_devi_free(enum_child);
1700 				return (DDI_FAILURE);
1701 			}
1702 
1703 			if (ndi_devi_online(enum_child, 0) !=
1704 			    DDI_SUCCESS) {
1705 				(void) ndi_devi_free(enum_child);
1706 				return (DDI_FAILURE);
1707 			}
1708 		}
1709 		/*
1710 		 * fail the enumeration node itself
1711 		 */
1712 		return (DDI_FAILURE);
1713 	}
1714 
1715 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr",
1716 	    &bus_addr) != DDI_PROP_SUCCESS) {
1717 		cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)",
1718 		    ddi_node_name(child));
1719 		return (DDI_NOT_WELL_FORMED);
1720 	}
1721 
1722 	if (strlen(bus_addr) == 0) {
1723 		cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)",
1724 		    ddi_node_name(child));
1725 		ddi_prop_free(bus_addr);
1726 		return (DDI_FAILURE);
1727 	}
1728 
1729 	if (strncmp(bus_addr, "failinit", 8) == 0) {
1730 		if (pshot_debug)
1731 			cmn_err(CE_CONT,
1732 			    "pshot%d: %s forced INITCHILD failure\n",
1733 				ddi_get_instance(dip), bus_addr);
1734 		ddi_prop_free(bus_addr);
1735 		return (DDI_FAILURE);
1736 	}
1737 
1738 	if (pshot_log) {
1739 		cmn_err(CE_CONT, "initchild %s%d/%s@%s\n",
1740 			ddi_get_name(dip), ddi_get_instance(dip),
1741 			ddi_node_name(child), bus_addr);
1742 	}
1743 
1744 	ddi_set_name_addr(child, bus_addr);
1745 	ddi_prop_free(bus_addr);
1746 	return (DDI_SUCCESS);
1747 }
1748 
1749 /*ARGSUSED*/
1750 static int
1751 pshot_uninitchild(dev_info_t *dip, dev_info_t *child)
1752 {
1753 	ddi_set_name_addr(child, NULL);
1754 	return (DDI_SUCCESS);
1755 }
1756 
1757 
1758 /*
1759  * devctl IOCTL support
1760  */
1761 /* ARGSUSED */
1762 static int
1763 pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1764 {
1765 	int instance;
1766 	pshot_t *pshot;
1767 
1768 	if (otyp != OTYP_CHR)
1769 		return (EINVAL);
1770 
1771 	instance = pshot_minor_decode_inst(getminor(*devp));
1772 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1773 		return (ENXIO);
1774 
1775 	/*
1776 	 * Access is currently determined on a per-instance basis.
1777 	 * If we want per-node, then need to add state and lock members to
1778 	 * pshot_minor_t
1779 	 */
1780 	mutex_enter(&pshot->lock);
1781 	if (((flags & FEXCL) && (pshot->state & IS_OPEN)) ||
1782 	    (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) {
1783 		mutex_exit(&pshot->lock);
1784 		return (EBUSY);
1785 	}
1786 	pshot->state |= IS_OPEN;
1787 	if (flags & FEXCL)
1788 		pshot->state |= IS_OPEN_EXCL;
1789 
1790 	if (pshot_debug)
1791 		cmn_err(CE_CONT, "pshot%d open\n", instance);
1792 
1793 	mutex_exit(&pshot->lock);
1794 	return (0);
1795 }
1796 
1797 /*
1798  * pshot_close
1799  */
1800 /* ARGSUSED */
1801 static int
1802 pshot_close(dev_t dev, int flag, int otyp, cred_t *credp)
1803 {
1804 	int instance;
1805 	pshot_t *pshot;
1806 
1807 	if (otyp != OTYP_CHR)
1808 		return (EINVAL);
1809 
1810 	instance = pshot_minor_decode_inst(getminor(dev));
1811 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1812 		return (ENXIO);
1813 
1814 	mutex_enter(&pshot->lock);
1815 	pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL);
1816 	mutex_exit(&pshot->lock);
1817 	if (pshot_debug)
1818 		cmn_err(CE_CONT, "pshot%d closed\n", instance);
1819 	return (0);
1820 }
1821 
1822 
1823 /*
1824  * pshot_ioctl: redirects to appropriate command handler based on various
1825  * 	criteria
1826  */
1827 /* ARGSUSED */
1828 static int
1829 pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1830     int *rvalp)
1831 {
1832 	pshot_t *pshot;
1833 	int instance;
1834 	minor_t nodenum;
1835 	char *nodename;
1836 
1837 	instance = pshot_minor_decode_inst(getminor(dev));
1838 	if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1839 		return (ENXIO);
1840 
1841 	nodenum = pshot_minor_decode_nodenum(getminor(dev));
1842 	nodename = pshot->nodes[nodenum].name;
1843 
1844 	if (pshot_debug)
1845 		cmn_err(CE_CONT,
1846 		    "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
1847 		    instance, (void *)dev, cmd, (void *)arg, mode);
1848 
1849 	if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0)
1850 		return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp,
1851 		    rvalp));
1852 
1853 	if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0)
1854 		return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp,
1855 		    rvalp));
1856 
1857 	cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u",
1858 	    pshot->nodes[nodenum].minor);
1859 	return (ENXIO);
1860 }
1861 
1862 
1863 /*
1864  * pshot_devctl: handle DEVCTL operations
1865  */
1866 /* ARGSUSED */
1867 static int
1868 pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
1869     cred_t *credp, int *rvalp)
1870 {
1871 	dev_info_t *self;
1872 	dev_info_t *child = NULL;
1873 	struct devctl_iocdata *dcp;
1874 	uint_t state;
1875 	int rv = 0;
1876 	uint_t flags;
1877 	int instance;
1878 	int i;
1879 	int ret;
1880 
1881 	self = pshot->dip;
1882 
1883 	flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0;
1884 	instance = pshot->instance;
1885 
1886 	/*
1887 	 * We can use the generic implementation for these ioctls
1888 	 */
1889 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
1890 		if (pshot_devctls[i].ioctl_int == cmd) {
1891 			if (pshot_debug)
1892 				cmn_err(CE_CONT, "pshot%d devctl: %s",
1893 				    instance, pshot_devctls[i].ioctl_char);
1894 		}
1895 	}
1896 	switch (cmd) {
1897 	case DEVCTL_DEVICE_GETSTATE:
1898 	case DEVCTL_DEVICE_ONLINE:
1899 	case DEVCTL_DEVICE_OFFLINE:
1900 	case DEVCTL_DEVICE_REMOVE:
1901 	case DEVCTL_BUS_GETSTATE:
1902 	case DEVCTL_BUS_DEV_CREATE:
1903 		rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags);
1904 		if (pshot_debug && rv != 0) {
1905 			cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:"
1906 			    " failed, rv = %d", instance, rv);
1907 		}
1908 
1909 		return (rv);
1910 	}
1911 
1912 	/*
1913 	 * read devctl ioctl data
1914 	 */
1915 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1916 		return (EFAULT);
1917 
1918 	switch (cmd) {
1919 
1920 	case DEVCTL_DEVICE_RESET:
1921 		if (pshot_debug)
1922 			cmn_err(CE_CONT, "pshot%d devctl:"
1923 			    " DEVCTL_DEVICE_RESET\n", instance);
1924 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
1925 		    child, (void *)self);
1926 		ASSERT(rv == NDI_SUCCESS);
1927 		break;
1928 
1929 	case DEVCTL_BUS_QUIESCE:
1930 		if (pshot_debug)
1931 			cmn_err(CE_CONT, "pshot%d devctl:"
1932 			    " DEVCTL_BUS_QUIESCE\n", instance);
1933 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1934 			if (state == BUS_QUIESCED) {
1935 				break;
1936 			}
1937 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
1938 		}
1939 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
1940 		    child, (void *)self);
1941 		ASSERT(rv == NDI_SUCCESS);
1942 
1943 		break;
1944 
1945 	case DEVCTL_BUS_UNQUIESCE:
1946 		if (pshot_debug)
1947 			cmn_err(CE_CONT, "pshot%d devctl:"
1948 			    " DEVCTL_BUS_UNQUIESCE\n", instance);
1949 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1950 			if (state == BUS_ACTIVE) {
1951 				break;
1952 			}
1953 		}
1954 
1955 		/*
1956 		 * quiesce the bus through bus-specific means
1957 		 */
1958 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
1959 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
1960 		    child, (void *)self);
1961 		ASSERT(rv == NDI_SUCCESS);
1962 		break;
1963 
1964 	case DEVCTL_BUS_RESET:
1965 	case DEVCTL_BUS_RESETALL:
1966 		/*
1967 		 * no reset support for the pseudo bus
1968 		 * but if there were....
1969 		 */
1970 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
1971 			child, (void *)self);
1972 		ASSERT(rv == NDI_SUCCESS);
1973 		break;
1974 
1975 	/*
1976 	 * PM related ioctls
1977 	 */
1978 	case DEVCTL_PM_BUSY_COMP:
1979 		/*
1980 		 * mark component 0 busy.
1981 		 * Keep track of ioctl updates to the busy count
1982 		 * via pshot->busy_ioctl.
1983 		 */
1984 		if (pshot_debug) {
1985 			cmn_err(CE_CONT, "pshot%d devctl:"
1986 			    " DEVCTL_PM_BUSY_COMP\n", instance);
1987 		}
1988 		mutex_enter(&pshot->lock);
1989 		++(pshot->busy);
1990 		++(pshot->busy_ioctl);
1991 		if (pshot_debug_busy) {
1992 			cmn_err(CE_CONT, "pshot%d:"
1993 			    " DEVCTL_PM_BUSY_COMP comp 0 busy"
1994 			    " %d busy_ioctl %d\n", instance, pshot->busy,
1995 			    pshot->busy_ioctl);
1996 		}
1997 		mutex_exit(&pshot->lock);
1998 		ret = pm_busy_component(pshot->dip, 0);
1999 		ASSERT(ret == DDI_SUCCESS);
2000 
2001 		break;
2002 
2003 	case DEVCTL_PM_BUSY_COMP_TEST:
2004 		/*
2005 		 * test bus's busy state
2006 		 */
2007 		if (pshot_debug) {
2008 			cmn_err(CE_CONT, "pshot%d devctl:"
2009 			    " DEVCTL_PM_BUSY_COMP_TEST\n", instance);
2010 		}
2011 		mutex_enter(&pshot->lock);
2012 		state = pshot->busy;
2013 		if (copyout(&state, dcp->cpyout_buf,
2014 		    sizeof (uint_t)) != 0) {
2015 			cmn_err(CE_WARN, "pshot%d devctl:"
2016 			    " DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
2017 			    instance);
2018 			rv = EINVAL;
2019 		}
2020 		if (pshot_debug_busy) {
2021 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:"
2022 			    " comp 0 busy %d busy_ioctl %d\n", instance,
2023 			    state, pshot->busy_ioctl);
2024 		}
2025 		mutex_exit(&pshot->lock);
2026 		break;
2027 
2028 	case DEVCTL_PM_IDLE_COMP:
2029 		/*
2030 		 * mark component 0 idle.
2031 		 * NOP if pshot->busy_ioctl <= 0.
2032 		 */
2033 		if (pshot_debug) {
2034 			cmn_err(CE_CONT, "pshot%d devctl:"
2035 			    " DEVCTL_PM_IDLE_COMP\n", instance);
2036 		}
2037 		mutex_enter(&pshot->lock);
2038 		if (pshot->busy_ioctl > 0) {
2039 			ASSERT(pshot->busy > 0);
2040 			--(pshot->busy);
2041 			--(pshot->busy_ioctl);
2042 			if (pshot_debug_busy) {
2043 				cmn_err(CE_CONT, "pshot%d:"
2044 				    " DEVCTL_PM_IDLE_COM: comp 0"
2045 				    " busy %d busy_ioctl %d\n", instance,
2046 				    pshot->busy, pshot->busy_ioctl);
2047 			}
2048 			mutex_exit(&pshot->lock);
2049 			ret = pm_idle_component(pshot->dip, 0);
2050 			ASSERT(ret == DDI_SUCCESS);
2051 
2052 		} else {
2053 			mutex_exit(&pshot->lock);
2054 		}
2055 		break;
2056 
2057 	case DEVCTL_PM_RAISE_PWR:
2058 		/*
2059 		 * raise component 0 to full power level MAXPWR via a
2060 		 * pm_raise_power() call
2061 		 */
2062 		if (pshot_debug) {
2063 			cmn_err(CE_CONT, "pshot%d devctl:"
2064 			    " DEVCTL_PM_RAISE_PWR\n", instance);
2065 		}
2066 		if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) {
2067 			rv = EINVAL;
2068 		} else {
2069 			mutex_enter(&pshot->lock);
2070 			if (pshot_debug) {
2071 				cmn_err(CE_CONT, "pshot%d:"
2072 				    " DEVCTL_PM_RAISE_POWER: comp 0"
2073 				    " to level %d\n", instance, pshot->level);
2074 			}
2075 			mutex_exit(&pshot->lock);
2076 		}
2077 		break;
2078 
2079 	case DEVCTL_PM_LOWER_PWR:
2080 		/*
2081 		 * pm_lower_power() call for negative testing
2082 		 * expected to fail.
2083 		 */
2084 		if (pshot_debug) {
2085 			cmn_err(CE_CONT, "pshot%d devctl:"
2086 			    " DEVCTL_PM_LOWER_PWR\n", instance);
2087 		}
2088 		if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
2089 			rv = EINVAL;
2090 		} else {
2091 			mutex_enter(&pshot->lock);
2092 			if (pshot_debug) {
2093 				cmn_err(CE_CONT, "pshot%d:"
2094 				    " DEVCTL_PM_LOWER_POWER comp 0"
2095 				    " to level %d\n", instance, pshot->level);
2096 			}
2097 			mutex_exit(&pshot->lock);
2098 		}
2099 		break;
2100 
2101 	case DEVCTL_PM_CHANGE_PWR_LOW:
2102 		/*
2103 		 * inform the PM framework that component 0 has changed
2104 		 * power level to 0 via a pm_power_has_changed() call
2105 		 */
2106 		if (pshot_debug) {
2107 			cmn_err(CE_CONT, "pshot%d devctl:"
2108 			    " DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
2109 		}
2110 		mutex_enter(&pshot->lock);
2111 		pshot->level = 0;
2112 		if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) {
2113 			rv = EINVAL;
2114 		} else {
2115 			if (pshot_debug) {
2116 				cmn_err(CE_CONT, "pshot%d:"
2117 				    " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
2118 				    " level %d\n", instance, pshot->level);
2119 			}
2120 		}
2121 		mutex_exit(&pshot->lock);
2122 		break;
2123 
2124 	case DEVCTL_PM_CHANGE_PWR_HIGH:
2125 		/*
2126 		 * inform the PM framework that component 0 has changed
2127 		 * power level to MAXPWR via a pm_power_has_changed() call
2128 		 */
2129 		if (pshot_debug) {
2130 			cmn_err(CE_CONT, "pshot%d devctl:"
2131 			    " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
2132 		}
2133 		mutex_enter(&pshot->lock);
2134 		pshot->level = MAXPWR;
2135 		if (pm_power_has_changed(pshot->dip, 0, MAXPWR)
2136 		    != DDI_SUCCESS) {
2137 			rv = EINVAL;
2138 		} else {
2139 			if (pshot_debug) {
2140 				cmn_err(CE_CONT, "pshot%d:"
2141 				    " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
2142 				    " level %d\n", instance, pshot->level);
2143 			}
2144 		}
2145 		mutex_exit(&pshot->lock);
2146 		break;
2147 
2148 	case DEVCTL_PM_POWER:
2149 		/*
2150 		 * test if the pshot_power() routine has been called,
2151 		 * then clear
2152 		 */
2153 		if (pshot_debug) {
2154 			cmn_err(CE_CONT, "pshot%d devctl:"
2155 			    " DEVCTL_PM_POWER\n", instance);
2156 		}
2157 		mutex_enter(&pshot->lock);
2158 		state = (pshot->state & POWER_FLAG) ? 1 : 0;
2159 		if (copyout(&state, dcp->cpyout_buf,
2160 		    sizeof (uint_t)) != 0) {
2161 			cmn_err(CE_WARN, "pshot%d devctl:"
2162 			    " DEVCTL_PM_POWER: copyout failed",
2163 			    instance);
2164 			rv = EINVAL;
2165 		}
2166 		if (pshot_debug) {
2167 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:"
2168 			    " POWER_FLAG = %d\n", instance, state);
2169 		}
2170 		pshot->state &= ~POWER_FLAG;
2171 		mutex_exit(&pshot->lock);
2172 		break;
2173 
2174 	case DEVCTL_PM_FAIL_SUSPEND:
2175 		/*
2176 		 * fail DDI_SUSPEND
2177 		 */
2178 		if (pshot_debug) {
2179 			cmn_err(CE_CONT, "pshot%d devctl:"
2180 			    " DEVCTL_PM_FAIL_SUSPEND\n", instance);
2181 		}
2182 		mutex_enter(&pshot->lock);
2183 		pshot->state |= FAIL_SUSPEND_FLAG;
2184 		mutex_exit(&pshot->lock);
2185 		if (pshot_debug) {
2186 			cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n",
2187 			    instance);
2188 		}
2189 		break;
2190 
2191 	case DEVCTL_PM_BUS_STRICT_TEST:
2192 		/*
2193 		 * test the STRICT_PARENT flag:
2194 		 *	set => STRICT PARENT
2195 		 *	not set => INVOLVED PARENT
2196 		 */
2197 		mutex_enter(&pshot->lock);
2198 		state = (pshot->state & STRICT_PARENT) ? 1 : 0;
2199 		if (copyout(&state, dcp->cpyout_buf,
2200 		    sizeof (uint_t)) != 0) {
2201 			cmn_err(CE_WARN, "pshot%d devctl:"
2202 			    " DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
2203 			    instance);
2204 			rv = EINVAL;
2205 		}
2206 		if (pshot_debug) {
2207 			cmn_err(CE_CONT, "pshot%d devctl:"
2208 			    " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
2209 			    instance, ((state == 0) ? "INVOLVED" : "STRICT"));
2210 		}
2211 		mutex_exit(&pshot->lock);
2212 		break;
2213 
2214 	case DEVCTL_PM_BUS_NO_INVOL:
2215 		/*
2216 		 * Set the NO_INVOL_FLAG flag to
2217 		 * notify the driver that the child will not
2218 		 * call pm_lower_power() on detach.
2219 		 * The driver needs to mark itself idle twice
2220 		 * during DDI_CTLOPS_DETACH (post).
2221 		 */
2222 		if (pshot_debug) {
2223 			cmn_err(CE_CONT, "pshot%d devctl:"
2224 			    " DEVCTL_PM_BUS_NO_INVOL\n", instance);
2225 		}
2226 		mutex_enter(&pshot->lock);
2227 		pshot->state |= NO_INVOL_FLAG;
2228 		mutex_exit(&pshot->lock);
2229 		break;
2230 
2231 	default:
2232 		rv = ENOTTY;
2233 	}
2234 
2235 	ndi_dc_freehdl(dcp);
2236 	return (rv);
2237 }
2238 
2239 
2240 /*
2241  * pshot_testctl: handle other test operations
2242  *	- If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
2243  *	  child to direct the DEVCTL to, if applicable;
2244  *	  furthermore, any cmd here can be sent by layered ioctls (unlike
2245  *	  those to pshot_devctl() which must come from userland)
2246  */
2247 /* ARGSUSED */
2248 static int
2249 pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
2250     cred_t *credp, int *rvalp)
2251 {
2252 	dev_info_t *self;
2253 	dev_info_t *child = NULL;
2254 	uint_t state;
2255 	int rv = 0;
2256 	int instance;
2257 	int i;
2258 
2259 	/* uint_t flags; */
2260 
2261 	/* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
2262 	self = pshot->dip;
2263 	instance = pshot->instance;
2264 
2265 	if (cmd & DEVCTL_IOC) {
2266 		child = e_ddi_hold_devi_by_dev((dev_t)arg, 0);
2267 	}
2268 
2269 	for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
2270 		if (pshot_devctls[i].ioctl_int == cmd) {
2271 			if (pshot_debug)
2272 				cmn_err(CE_CONT, "pshot%d devctl: %s",
2273 				    instance, pshot_devctls[i].ioctl_char);
2274 		}
2275 	}
2276 	switch (cmd) {
2277 	case DEVCTL_DEVICE_RESET:
2278 		if (pshot_debug)
2279 			cmn_err(CE_CONT, "pshot%d testctl:"
2280 			    " DEVCTL_PM_POWER\n", instance);
2281 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
2282 		    child, (void *)self);
2283 		ASSERT(rv == NDI_SUCCESS);
2284 		break;
2285 
2286 	case DEVCTL_BUS_QUIESCE:
2287 		if (pshot_debug)
2288 			cmn_err(CE_CONT, "pshot%d testctl:"
2289 			    " DEVCTL_PM_POWER\n", instance);
2290 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2291 			if (state == BUS_QUIESCED) {
2292 				break;
2293 			}
2294 			(void) ndi_set_bus_state(self, BUS_QUIESCED);
2295 		}
2296 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
2297 		    child, (void *)self);
2298 		ASSERT(rv == NDI_SUCCESS);
2299 
2300 		break;
2301 
2302 	case DEVCTL_BUS_UNQUIESCE:
2303 		if (pshot_debug)
2304 			cmn_err(CE_CONT, "pshot%d testctl:"
2305 			    " DEVCTL_PM_POWER\n", instance);
2306 		if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2307 			if (state == BUS_ACTIVE) {
2308 				break;
2309 			}
2310 		}
2311 
2312 		/*
2313 		 * quiesce the bus through bus-specific means
2314 		 */
2315 		(void) ndi_set_bus_state(self, BUS_ACTIVE);
2316 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
2317 		    child, (void *)self);
2318 		ASSERT(rv == NDI_SUCCESS);
2319 		break;
2320 
2321 	case DEVCTL_BUS_RESET:
2322 	case DEVCTL_BUS_RESETALL:
2323 		/*
2324 		 * no reset support for the pseudo bus
2325 		 * but if there were....
2326 		 */
2327 		rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
2328 			child, (void *)self);
2329 		ASSERT(rv == NDI_SUCCESS);
2330 		break;
2331 
2332 	default:
2333 		rv = ENOTTY;
2334 	}
2335 
2336 	if (child != NULL)
2337 		ddi_release_devi(child);
2338 	return (rv);
2339 }
2340 
2341 
2342 static int
2343 pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
2344 	char *eventname, ddi_eventcookie_t *event_cookiep)
2345 {
2346 	int	instance = ddi_get_instance(dip);
2347 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2348 
2349 	if (pshot_debug)
2350 	    cmn_err(CE_CONT, "pshot%d: "
2351 		"pshot_get_eventcookie:\n\t"
2352 		"dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
2353 		instance, (void *)dip, (void *)rdip,
2354 		ddi_node_name(rdip), ddi_get_instance(rdip),
2355 		eventname);
2356 
2357 
2358 	return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl,
2359 		rdip, eventname, event_cookiep, NDI_EVENT_NOPASS));
2360 }
2361 
2362 static int
2363 pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
2364 	ddi_eventcookie_t cookie,
2365 	void (*callback)(), void *arg, ddi_callback_id_t *cb_id)
2366 {
2367 	int	instance = ddi_get_instance(dip);
2368 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2369 
2370 	if (pshot_debug)
2371 	    cmn_err(CE_CONT, "pshot%d: "
2372 	    "pshot_add_eventcall:\n\t"
2373 	    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
2374 	    "cb = 0x%p, arg = 0x%p\n",
2375 	    instance, (void *)dip, (void *)rdip,
2376 	    ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
2377 	    NDI_EVENT_NAME(cookie), (void *)callback, arg);
2378 
2379 	/* add callback to our event handle */
2380 	return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip,
2381 		cookie, callback, arg, NDI_SLEEP, cb_id));
2382 }
2383 
2384 static int
2385 pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
2386 {
2387 
2388 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
2389 
2390 	int instance = ddi_get_instance(dip);
2391 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2392 
2393 	ASSERT(cb);
2394 
2395 	if (pshot_debug)
2396 	    cmn_err(CE_CONT, "pshot%d: "
2397 	    "pshot_remove_eventcall:\n\t"
2398 	    "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
2399 	    instance, (void *)dip, (void *)cb->ndi_evtcb_dip,
2400 	    ddi_node_name(cb->ndi_evtcb_dip),
2401 	    ddi_get_instance(cb->ndi_evtcb_dip), (void *)cb->ndi_evtcb_cookie,
2402 	    NDI_EVENT_NAME(cb->ndi_evtcb_cookie));
2403 
2404 	return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id));
2405 }
2406 
2407 static int
2408 pshot_post_event(dev_info_t *dip, dev_info_t *rdip,
2409 	ddi_eventcookie_t cookie, void *impl_data)
2410 {
2411 	int	instance = ddi_get_instance(dip);
2412 	pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2413 
2414 	if (pshot_debug) {
2415 	    if (rdip) {
2416 		cmn_err(CE_CONT, "pshot%d: "
2417 		    "pshot_post_event:\n\t"
2418 		    "dip = 0x%p rdip = 0x%p (%s%d\n\t"
2419 		    "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
2420 		    instance, (void *)dip, (void *)rdip,
2421 		    ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
2422 		    NDI_EVENT_NAME(cookie), impl_data);
2423 	    } else {
2424 		cmn_err(CE_CONT, "pshot%d: "
2425 		    "pshot_post_event:\n\t"
2426 		    "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
2427 		    instance, (void *)dip, (void *)cookie,
2428 		    NDI_EVENT_NAME(cookie), impl_data);
2429 	    }
2430 	}
2431 
2432 	/*  run callbacks for this event */
2433 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip,
2434 	    cookie, impl_data));
2435 }
2436 
2437 /*
2438  * the nexus driver will generate events
2439  * that need to go to children
2440  */
2441 static int
2442 pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child,
2443 	void *bus_impldata)
2444 {
2445 	ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(
2446 		pshot->ndi_event_hdl, event_tag);
2447 
2448 	if (pshot_debug) {
2449 		if (child) {
2450 		    cmn_err(CE_CONT, "pshot%d: "
2451 			"pshot_event: event_tag = 0x%x (%s)\n\t"
2452 			"child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
2453 			pshot->instance, event_tag,
2454 			ndi_event_tag_to_name(pshot->ndi_event_hdl, event_tag),
2455 			(void *)child, ddi_node_name(child),
2456 			ddi_get_instance(child), bus_impldata,
2457 			ddi_node_name((dev_info_t *)bus_impldata),
2458 			ddi_get_instance((dev_info_t *)bus_impldata));
2459 		} else {
2460 		    cmn_err(CE_CONT, "pshot%d: "
2461 			"pshot_event: event_tag = 0x%x (%s)\n\t"
2462 			"child = NULL,  bus_impl = 0x%p (%s%d)\n",
2463 			pshot->instance, event_tag,
2464 			ndi_event_tag_to_name(pshot->ndi_event_hdl, event_tag),
2465 			bus_impldata,
2466 			ddi_node_name((dev_info_t *)bus_impldata),
2467 			ddi_get_instance((dev_info_t *)bus_impldata));
2468 		}
2469 	}
2470 
2471 	return (ndi_event_run_callbacks(pshot->ndi_event_hdl,
2472 		child, cookie, bus_impldata));
2473 }
2474 
2475 
2476 /*
2477  * the pshot driver event notification callback
2478  */
2479 static void
2480 pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
2481 	void *arg, void *bus_impldata)
2482 {
2483 	pshot_t *pshot = (pshot_t *)arg;
2484 	int event_tag;
2485 
2486 	/* look up the event */
2487 	event_tag = NDI_EVENT_TAG(cookie);
2488 
2489 	if (pshot_debug) {
2490 		cmn_err(CE_CONT, "pshot%d: "
2491 		    "pshot_event_cb:\n\t"
2492 		    "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
2493 		    "arg = 0x%p bus_impl = 0x%p (%s%d)\n",
2494 		    pshot->instance, (void *)dip, (void *)cookie,
2495 		    NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata,
2496 		    ddi_node_name((dev_info_t *)bus_impldata),
2497 		    ddi_get_instance((dev_info_t *)bus_impldata));
2498 	}
2499 
2500 	switch (event_tag) {
2501 	case PSHOT_EVENT_TAG_OFFLINE:
2502 	case PSHOT_EVENT_TAG_BUS_RESET:
2503 	case PSHOT_EVENT_TAG_BUS_QUIESCE:
2504 	case PSHOT_EVENT_TAG_BUS_UNQUIESCE:
2505 		/* notify all subscribers of the this event */
2506 		(void) ndi_event_run_callbacks(pshot->ndi_event_hdl,
2507 			NULL, cookie, bus_impldata);
2508 		if (pshot_debug) {
2509 			cmn_err(CE_CONT, "pshot%d: event=%s\n\t"
2510 			"pshot_event_cb\n", pshot->instance,
2511 			NDI_EVENT_NAME(cookie));
2512 		}
2513 		/*FALLTHRU*/
2514 	case PSHOT_EVENT_TAG_TEST_POST:
2515 	case PSHOT_EVENT_TAG_DEV_RESET:
2516 	default:
2517 		return;
2518 	}
2519 }
2520 
2521 static int
2522 pshot_bus_config(dev_info_t *parent, uint_t flags,
2523     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
2524 {
2525 	int		rval;
2526 	char		*devname;
2527 	char		*devstr, *cname, *caddr;
2528 	int		devstrlen;
2529 	int		circ;
2530 	pshot_t		*pshot;
2531 	int		instance = ddi_get_instance(parent);
2532 
2533 	if (pshot_debug) {
2534 		flags |= NDI_DEVI_DEBUG;
2535 		cmn_err(CE_CONT,
2536 		    "pshot%d: bus_config %s flags=0x%x\n",
2537 		    ddi_get_instance(parent),
2538 		    (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags);
2539 	}
2540 
2541 	pshot = ddi_get_soft_state(pshot_softstatep, instance);
2542 	if (pshot == NULL) {
2543 
2544 		return (NDI_FAILURE);
2545 	}
2546 
2547 	/*
2548 	 * Hold the nexus across the bus_config
2549 	 */
2550 	ndi_devi_enter(parent, &circ);
2551 
2552 	switch (op) {
2553 	case BUS_CONFIG_ONE:
2554 
2555 		/*
2556 		 * lookup and hold child device, create if not found
2557 		 */
2558 		devname = (char *)arg;
2559 		devstrlen = strlen(devname) + 1;
2560 		devstr = i_ddi_strdup(devname, KM_SLEEP);
2561 		i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2562 
2563 		/*
2564 		 * The framework ensures that the node has
2565 		 * a name but each nexus is responsible for
2566 		 * the bus address name space.  This driver
2567 		 * requires that a bus address be specified,
2568 		 * as will most nexus drivers.
2569 		 */
2570 		ASSERT(cname && strlen(cname) > 0);
2571 		if (caddr == NULL || strlen(caddr) == 0) {
2572 			cmn_err(CE_WARN,
2573 			    "pshot%d: malformed name %s (no bus address)",
2574 			    ddi_get_instance(parent), devname);
2575 			kmem_free(devstr, devstrlen);
2576 			ndi_devi_exit(parent, circ);
2577 			return (NDI_FAILURE);
2578 		}
2579 
2580 		/*
2581 		 * Handle a few special cases for testing purposes
2582 		 */
2583 		rval = pshot_bus_config_test_specials(parent,
2584 			devname, cname, caddr);
2585 
2586 		if (rval == NDI_SUCCESS) {
2587 			/*
2588 			 * Set up either a leaf or nexus device
2589 			 */
2590 			if (strcmp(cname, "pshot") == 0) {
2591 				rval = pshot_bus_config_setup_nexus(parent,
2592 				    cname, caddr);
2593 			} else {
2594 				rval = pshot_bus_config_setup_leaf(parent,
2595 				    cname, caddr);
2596 			}
2597 		}
2598 
2599 		kmem_free(devstr, devstrlen);
2600 		break;
2601 
2602 	case BUS_CONFIG_DRIVER:
2603 		rval = NDI_FAILURE;
2604 		break;
2605 
2606 	case BUS_CONFIG_ALL:
2607 		rval = NDI_SUCCESS;
2608 		break;
2609 
2610 	default:
2611 		rval = NDI_FAILURE;
2612 		break;
2613 	}
2614 
2615 	if (rval == NDI_SUCCESS)
2616 		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
2617 
2618 	ndi_devi_exit(parent, circ);
2619 
2620 	if (pshot_debug)
2621 		cmn_err(CE_CONT, "pshot%d: bus_config %s\n",
2622 		    ddi_get_instance(parent),
2623 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
2624 
2625 	return (rval);
2626 }
2627 
2628 static int
2629 pshot_bus_unconfig(dev_info_t *parent, uint_t flags,
2630     ddi_bus_config_op_t op, void *arg)
2631 {
2632 	major_t		major;
2633 	int		rval = NDI_SUCCESS;
2634 	int		circ;
2635 
2636 	if (pshot_debug) {
2637 		flags |= NDI_DEVI_DEBUG;
2638 		cmn_err(CE_CONT,
2639 		    "pshot%d: bus_unconfig %s flags=0x%x\n",
2640 		    ddi_get_instance(parent),
2641 		    (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags);
2642 	}
2643 
2644 	/*
2645 	 * Hold the nexus across the bus_unconfig
2646 	 */
2647 	ndi_devi_enter(parent, &circ);
2648 
2649 	switch (op) {
2650 	case BUS_UNCONFIG_ONE:
2651 		/*
2652 		 * Nothing special required here
2653 		 */
2654 		if (pshot_debug) {
2655 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2656 			    " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent));
2657 		}
2658 		break;
2659 
2660 	case BUS_UNCONFIG_DRIVER:
2661 		if (pshot_debug > 0) {
2662 			major = (major_t)(uintptr_t)arg;
2663 			cmn_err(CE_CONT,
2664 			    "pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
2665 			    ddi_get_instance(parent),
2666 			    ddi_major_to_name(major));
2667 		}
2668 		break;
2669 
2670 	case BUS_UNCONFIG_ALL:
2671 		if (pshot_debug) {
2672 			cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2673 			    " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent));
2674 		}
2675 		break;
2676 
2677 	default:
2678 		if (pshot_debug) {
2679 			cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n",
2680 			    ddi_get_instance(parent));
2681 		}
2682 		rval = NDI_FAILURE;
2683 	}
2684 
2685 	if (rval == NDI_SUCCESS)
2686 		rval = ndi_busop_bus_unconfig(parent, flags, op, arg);
2687 
2688 	ndi_devi_exit(parent, circ);
2689 
2690 	if (pshot_debug)
2691 		cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n",
2692 		    ddi_get_instance(parent),
2693 		    (rval == NDI_SUCCESS) ? "ok" : "failed");
2694 
2695 	return (rval);
2696 }
2697 
2698 static dev_info_t *
2699 pshot_findchild(dev_info_t *pdip, char *cname, char *caddr)
2700 {
2701 	dev_info_t *dip;
2702 	char *addr;
2703 
2704 	ASSERT(cname != NULL && caddr != NULL);
2705 	ASSERT(DEVI_BUSY_OWNED(pdip));
2706 
2707 	for (dip = ddi_get_child(pdip); dip != NULL;
2708 	    dip = ddi_get_next_sibling(dip)) {
2709 		if (strcmp(cname, ddi_node_name(dip)) != 0)
2710 			continue;
2711 
2712 		if ((addr = ddi_get_name_addr(dip)) == NULL) {
2713 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
2714 			    "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2715 				if (strcmp(caddr, addr) == 0) {
2716 					ddi_prop_free(addr);
2717 					return (dip);
2718 				}
2719 				ddi_prop_free(addr);
2720 			}
2721 		} else {
2722 			if (strcmp(caddr, addr) == 0)
2723 				return (dip);
2724 		}
2725 	}
2726 
2727 	return (NULL);
2728 }
2729 
2730 static void
2731 pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2732     char *caddr)
2733 {
2734 	char *extension;
2735 
2736 	/*
2737 	 * extract the address extension
2738 	 */
2739 	extension = strstr(caddr, ",");
2740 	if (extension != NULL) {
2741 		++extension;
2742 	} else {
2743 		extension = "null";
2744 	}
2745 
2746 	/*
2747 	 * Create the "pm-want-child-notification?" property for all
2748 	 * nodes that do not have the "pm_strict" or "nopm_strict"
2749 	 * extension
2750 	 */
2751 	if (strcmp(extension, "pm_strict") != 0 &&
2752 	    strcmp(extension, "nopm_strict") != 0) {
2753 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2754 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2755 		    "pm-want-child-notification?") == 0) {
2756 			if (pshot_debug) {
2757 				cmn_err(CE_CONT, "pshot%d:"
2758 				    " nexus_properties:\n\tcreate the"
2759 				    " \"pm-want-child-notification?\""
2760 				    " property for %s@%s\n",
2761 				    ddi_get_instance(parent), cname, caddr);
2762 			}
2763 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2764 			    "pm-want-child-notification?", NULL, 0)
2765 			    != DDI_PROP_SUCCESS) {
2766 				cmn_err(CE_WARN, "pshot%d:"
2767 				    " nexus_properties:\n\tunable to create"
2768 				    " the \"pm-want-child-notification?\""
2769 				    " property for %s@%s",
2770 				    ddi_get_instance(parent), cname, caddr);
2771 			}
2772 		}
2773 	}
2774 
2775 	/*
2776 	 * Create the "no-pm-components" property for all nodes
2777 	 * with extension "nopm" or "nopm_strict"
2778 	 */
2779 	if (strcmp(extension, "nopm") == 0 ||
2780 	    strcmp(extension, "nopm_strict") == 0) {
2781 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2782 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2783 		    "no-pm-components") == 0) {
2784 			if (pshot_debug) {
2785 				cmn_err(CE_CONT, "pshot%d:"
2786 				    " nexus_properties:\n\tcreate the"
2787 				    " \"no-pm-components\""
2788 				    " property for %s@%s\n",
2789 				    ddi_get_instance(parent), cname, caddr);
2790 			}
2791 			if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2792 			    "no-pm-components", NULL, 0)
2793 			    != DDI_PROP_SUCCESS) {
2794 				cmn_err(CE_WARN, "pshot%d:"
2795 				    " nexus_properties:\n\tunable to create"
2796 				    " the \"no-pm-components\""
2797 				    " property for %s@%s",
2798 				ddi_get_instance(parent), cname, caddr);
2799 			}
2800 		}
2801 	}
2802 }
2803 
2804 static void
2805 pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2806     char *caddr)
2807 {
2808 	char *extension;
2809 
2810 	/*
2811 	 * extract the address extension
2812 	 */
2813 	extension = strstr(caddr, ",");
2814 	if (extension != NULL) {
2815 		++extension;
2816 	} else {
2817 		extension = "null";
2818 	}
2819 
2820 	/*
2821 	 * Create the "no-involuntary-power-cycles" property for
2822 	 * all leaf nodes with extension "no_invol"
2823 	 */
2824 	if (strcmp(extension, "no_invol") == 0) {
2825 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2826 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2827 		    "no-involuntary-power-cycles") == 0) {
2828 			if (pshot_debug) {
2829 				cmn_err(CE_CONT, "pshot%d:"
2830 				    " leaf_properties:\n\tcreate the"
2831 				    " \"no-involuntary-power-cycles\""
2832 				    " property for %s@%s\n",
2833 				    ddi_get_instance(parent), cname, caddr);
2834 			}
2835 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
2836 			    DDI_PROP_CANSLEEP,
2837 			    "no-involuntary-power-cycles", NULL, 0)
2838 			    != DDI_PROP_SUCCESS) {
2839 				cmn_err(CE_WARN, "pshot%d:"
2840 				    " leaf_properties:\n\tunable to create the"
2841 				    " \"no-involuntary-power-cycles\""
2842 				    " property for %s@%s",
2843 				    ddi_get_instance(parent), cname, caddr);
2844 			}
2845 		}
2846 	}
2847 
2848 	/*
2849 	 * Create the "dependency-property" property for all leaf
2850 	 * nodes with extension "dep_prop"
2851 	 * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
2852 	 */
2853 	if (strcmp(extension, "dep_prop") == 0) {
2854 		if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2855 		    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2856 		    "dependency-property") == 0) {
2857 			if (pshot_debug) {
2858 				cmn_err(CE_CONT, "pshot%d:"
2859 				    " leaf_properties:\n\tcreate the"
2860 				    " \"dependency-property\""
2861 				    " property for %s@%s\n",
2862 				    ddi_get_instance(parent), cname, caddr);
2863 			}
2864 			if (ddi_prop_create(DDI_DEV_T_NONE, child,
2865 			    DDI_PROP_CANSLEEP, "dependency-property", NULL, 0)
2866 			    != DDI_PROP_SUCCESS) {
2867 				cmn_err(CE_WARN, "pshot%d:"
2868 				    " leaf_properties:\n\tunable to create the"
2869 				    " \"dependency-property\" property for"
2870 				    " %s@%s", ddi_get_instance(parent),
2871 				    cname, caddr);
2872 			}
2873 		}
2874 	}
2875 }
2876 
2877 /*
2878  * BUS_CONFIG_ONE: setup a child nexus instance.
2879  */
2880 static int
2881 pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr)
2882 {
2883 	dev_info_t *child;
2884 	int rval;
2885 
2886 	ASSERT(parent != 0);
2887 	ASSERT(cname != NULL);
2888 	ASSERT(caddr != NULL);
2889 
2890 	child = pshot_findchild(parent, cname, caddr);
2891 	if (child) {
2892 		if (pshot_debug) {
2893 			cmn_err(CE_CONT,
2894 			    "pshot%d: bus_config one %s@%s found\n",
2895 			    ddi_get_instance(parent), cname, caddr);
2896 		}
2897 		/*
2898 		 * create the "pm-want-child-notification?" property
2899 		 * for this child, if it doesn't already exist
2900 		 */
2901 		(void) pshot_nexus_properties(parent, child, cname, caddr);
2902 
2903 		return (NDI_SUCCESS);
2904 	}
2905 
2906 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2907 	ASSERT(child != NULL);
2908 
2909 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2910 	    "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2911 		cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed",
2912 		    ddi_get_instance(parent), cname, caddr);
2913 		(void) ndi_devi_free(child);
2914 		return (NDI_FAILURE);
2915 	}
2916 
2917 	rval = ndi_devi_bind_driver(child, 0);
2918 	if (rval != NDI_SUCCESS) {
2919 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
2920 		    ddi_get_instance(parent), cname);
2921 		(void) ndi_devi_free(child);
2922 		return (NDI_FAILURE);
2923 	}
2924 
2925 	/*
2926 	 * create the "pm-want-child-notification?" property
2927 	 */
2928 	(void) pshot_nexus_properties(parent, child, cname, caddr);
2929 
2930 	return (NDI_SUCCESS);
2931 }
2932 
2933 /*
2934  * BUS_CONFIG_ONE: setup a child leaf device instance.
2935  * for testing purposes, we will create nodes of a variety of types.
2936  */
2937 static int
2938 pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr)
2939 {
2940 	dev_info_t *child;
2941 	char *compat_name;
2942 	char *nodetype;
2943 	int rval;
2944 	int i;
2945 
2946 	ASSERT(parent != 0);
2947 	ASSERT(cname != NULL);
2948 	ASSERT(caddr != NULL);
2949 
2950 	/*
2951 	 * if we already have a node with this name, return it
2952 	 */
2953 	if ((child = pshot_findchild(parent, cname, caddr)) != NULL) {
2954 		/*
2955 		 * create the "no-involuntary-power-cycles" or
2956 		 * the "dependency-property" property, if they
2957 		 * don't already exit
2958 		 */
2959 		(void) pshot_leaf_properties(parent, child, cname, caddr);
2960 
2961 		return (NDI_SUCCESS);
2962 	}
2963 
2964 	ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2965 	ASSERT(child != NULL);
2966 
2967 	if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr",
2968 	    caddr) != DDI_PROP_SUCCESS) {
2969 		(void) ndi_devi_free(child);
2970 		return (NDI_FAILURE);
2971 	}
2972 
2973 	/*
2974 	 * test compatible naming
2975 	 * if the child nodename is "cdisk", attach the list of compatible
2976 	 * named disks
2977 	 */
2978 	if (strcmp(cname, pshot_compat_diskname) == 0) {
2979 		if ((ndi_prop_update_string_array(DDI_DEV_T_NONE,
2980 		    child, "compatible", (char **)pshot_compat_psramdisks,
2981 		    5)) != DDI_PROP_SUCCESS) {
2982 			(void) ndi_devi_free(child);
2983 			return (NDI_FAILURE);
2984 		}
2985 	} else {
2986 		for (i = 0; i < pshot_devices_len && pshot_devices[i].name;
2987 		    i++) {
2988 			if (strcmp(cname, pshot_devices[i].name) == 0) {
2989 				compat_name = pshot_devices[i].compat;
2990 				nodetype = pshot_devices[i].nodetype;
2991 				if (pshot_debug) {
2992 					cmn_err(CE_CONT, "pshot%d: %s %s %s\n",
2993 					    ddi_get_instance(parent), cname,
2994 					    compat_name, nodetype);
2995 				}
2996 				if ((ndi_prop_update_string_array(
2997 				    DDI_DEV_T_NONE, child, "compatible",
2998 				    &compat_name, 1)) != DDI_PROP_SUCCESS) {
2999 					(void) ndi_devi_free(child);
3000 					return (NDI_FAILURE);
3001 				}
3002 				if ((ndi_prop_update_string(
3003 				    DDI_DEV_T_NONE, child, "node-type",
3004 				    nodetype)) != DDI_PROP_SUCCESS) {
3005 					(void) ndi_devi_free(child);
3006 					return (NDI_FAILURE);
3007 				}
3008 			}
3009 		}
3010 	}
3011 
3012 	rval = ndi_devi_bind_driver(child, 0);
3013 	if (rval != NDI_SUCCESS) {
3014 		cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
3015 		    ddi_get_instance(parent), cname);
3016 		(void) ndi_devi_free(child);
3017 		return (NDI_FAILURE);
3018 	}
3019 
3020 	/*
3021 	 * create the "no-involuntary-power-cycles" or
3022 	 * the "dependency-property" property
3023 	 */
3024 	(void) pshot_leaf_properties(parent, child, cname, caddr);
3025 
3026 	return (NDI_SUCCESS);
3027 }
3028 
3029 /*
3030  * Handle some special cases for testing bus_config via pshot
3031  *
3032  * Match these special address formats to behavior:
3033  *
3034  *	err.*		- induce bus_config error
3035  *	delay		- induce 1 second of bus_config delay time
3036  *	delay,n		- induce n seconds of bus_config delay time
3037  *	wait		- induce 1 second of bus_config wait time
3038  *	wait,n		- induce n seconds of bus_config wait time
3039  *	failinit.*	- induce error at INITCHILD
3040  *	failprobe.*	- induce error at probe
3041  *	failattach.*	- induce error at attach
3042  */
3043 /*ARGSUSED*/
3044 static int
3045 pshot_bus_config_test_specials(dev_info_t *parent, char *devname,
3046 	char *cname, char *caddr)
3047 {
3048 	char	*p;
3049 	int	n;
3050 
3051 	if (strncmp(caddr, "err", 3) == 0) {
3052 		if (pshot_debug)
3053 			cmn_err(CE_CONT,
3054 			    "pshot%d: %s forced failure\n",
3055 				ddi_get_instance(parent), devname);
3056 		return (NDI_FAILURE);
3057 	}
3058 
3059 	/*
3060 	 * The delay and wait strings have the same effect.
3061 	 * The "wait[,]" support should be removed once the
3062 	 * devfs test suites are fixed.
3063 	 * NOTE: delay should not be called from interrupt context
3064 	 */
3065 	ASSERT(!servicing_interrupt());
3066 
3067 	if (strncmp(caddr, "delay,", 6) == 0) {
3068 		p = caddr+6;
3069 		n = stoi(&p);
3070 		if (*p != 0)
3071 			n = 1;
3072 		if (pshot_debug)
3073 			cmn_err(CE_CONT,
3074 			    "pshot%d: %s delay %d second\n",
3075 				ddi_get_instance(parent), devname, n);
3076 		delay(n * drv_usectohz(1000000));
3077 	} else if (strncmp(caddr, "delay", 5) == 0) {
3078 		if (pshot_debug)
3079 			cmn_err(CE_CONT,
3080 			    "pshot%d: %s delay 1 second\n",
3081 				ddi_get_instance(parent), devname);
3082 		delay(drv_usectohz(1000000));
3083 	} else if (strncmp(caddr, "wait,", 5) == 0) {
3084 		p = caddr+5;
3085 		n = stoi(&p);
3086 		if (*p != 0)
3087 			n = 1;
3088 		if (pshot_debug)
3089 			cmn_err(CE_CONT,
3090 			    "pshot%d: %s wait %d second\n",
3091 				ddi_get_instance(parent), devname, n);
3092 		delay(n * drv_usectohz(1000000));
3093 	} else if (strncmp(caddr, "wait", 4) == 0) {
3094 		if (pshot_debug)
3095 			cmn_err(CE_CONT,
3096 			    "pshot%d: %s wait 1 second\n",
3097 			    ddi_get_instance(parent), devname);
3098 		delay(drv_usectohz(1000000));
3099 	}
3100 
3101 	return (NDI_SUCCESS);
3102 }
3103 
3104 /*
3105  * translate nodetype name to actual value
3106  */
3107 static char *
3108 pshot_str2nt(char *str)
3109 {
3110 	int i;
3111 
3112 	for (i = 0; pshot_nodetypes[i].name; i++) {
3113 		if (strcmp(pshot_nodetypes[i].name, str) == 0)
3114 			return (pshot_nodetypes[i].val);
3115 	}
3116 	return (NULL);
3117 }
3118 
3119 /*
3120  * grows array pointed to by <dstp>, with <src> data
3121  * <dstlen> = # elements of the original <*dstp>
3122  * <srclen> = # elements of <src>
3123  *
3124  * on success, returns 0 and a pointer to the new array through <dstp> with
3125  * <srclen> + <dstlen> number of elements;
3126  * else returns non-zero
3127  *
3128  * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
3129  */
3130 static int
3131 pshot_devices_grow(pshot_device_t **dstp, size_t dstlen,
3132     const pshot_device_t *src, size_t srclen)
3133 {
3134 	size_t i;
3135 	pshot_device_t *newdst;
3136 
3137 	newdst = kmem_alloc((srclen + dstlen) * sizeof (*src),
3138 	    KM_SLEEP);
3139 
3140 	/* keep old pointers and dup new ones */
3141 	if (*dstp)
3142 		bcopy(*dstp, newdst, dstlen * sizeof (*src));
3143 	for (i = 0; i < srclen; i++) {
3144 		newdst[i + dstlen].name =
3145 		    i_ddi_strdup(src[i].name, KM_SLEEP);
3146 
3147 		newdst[i + dstlen].nodetype =
3148 		    i_ddi_strdup(src[i].nodetype, KM_SLEEP);
3149 
3150 		newdst[i + dstlen].compat =
3151 		    i_ddi_strdup(src[i].compat, KM_SLEEP);
3152 	}
3153 
3154 	/* do last */
3155 	if (*dstp)
3156 		kmem_free(*dstp, dstlen * sizeof (*src));
3157 	*dstp = newdst;
3158 	return (0);
3159 }
3160 
3161 /*
3162  * free a pshot_device_t array <dp> with <len> elements
3163  * null pointers within the elements are ok
3164  */
3165 static void
3166 pshot_devices_free(pshot_device_t *dp, size_t len)
3167 {
3168 	size_t i;
3169 
3170 	for (i = 0; i < len; i++) {
3171 		if (dp[i].name)
3172 			kmem_free(dp[i].name, strlen(dp[i].name) + 1);
3173 		if (dp[i].nodetype)
3174 			kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1);
3175 		if (dp[i].compat)
3176 			kmem_free(dp[i].compat, strlen(dp[i].compat) + 1);
3177 	}
3178 	kmem_free(dp, len * sizeof (*dp));
3179 }
3180 
3181 /*
3182  * returns an array of pshot_device_t parsed from <dip>'s properties
3183  *
3184  * property structure (i.e. pshot.conf) for pshot:
3185  *
3186  * corresponding         |   pshot_device_t array elements
3187  * pshot_device_t        |
3188  * member by prop name   |   [0]            [1]           [2]
3189  * ----------------------|--------------|-------------|-----------------------
3190  * <PSHOT_PROP_DEVNAME>  ="disk",        "tape",       "testdev";
3191  * <PSHOT_PROP_DEVNT>    ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
3192  * <PSHOT_PROP_DEVCOMPAT>="testdrv",     "testdrv",    "testdrv";
3193  *
3194  *
3195  * if any of these properties are specified, then:
3196  * - all the members must be specified
3197  * - the number of elements for each string array property must be the same
3198  * - no empty strings allowed
3199  * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
3200  *   sys/sunddi.h
3201  *
3202  * NOTE: the pshot_nodetypes[] table should be kept in sync with the list
3203  * of ddi nodetypes.  It's not normally critical to always be in sync so
3204  * keeping this up-to-date can usually be done "on-demand".
3205  *
3206  * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
3207  * these will be duplicated verbatim
3208  */
3209 static pshot_device_t *
3210 pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags)
3211 {
3212 	pshot_device_t *devarr = NULL;
3213 	char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL;
3214 	uint_t name_arr_len, nt_arr_len, compat_arr_len;
3215 	uint_t i;
3216 	char *str;
3217 
3218 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3219 	    PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) !=
3220 	    DDI_PROP_SUCCESS)
3221 		name_arr = NULL;
3222 
3223 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3224 	    PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) !=
3225 	    DDI_PROP_SUCCESS)
3226 		nt_arr = NULL;
3227 
3228 	if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3229 	    PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) !=
3230 	    DDI_PROP_SUCCESS)
3231 		compat_arr = NULL;
3232 
3233 	/*
3234 	 * warn about any incorrect usage, if specified
3235 	 */
3236 	if (!(name_arr || nt_arr || compat_arr))
3237 		return (NULL);
3238 
3239 	if (!(name_arr && nt_arr && compat_arr) ||
3240 	    (name_arr_len != nt_arr_len) ||
3241 	    (name_arr_len != compat_arr_len))
3242 		goto FAIL;
3243 
3244 	for (i = 0; i < name_arr_len; i++) {
3245 		if (*name_arr[i] == '\0' ||
3246 		    *nt_arr[i] == '\0' ||
3247 		    *compat_arr[i] == '\0')
3248 			goto FAIL;
3249 	}
3250 
3251 	devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP);
3252 	for (i = 0; i < name_arr_len; i++) {
3253 		devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP);
3254 		devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP);
3255 
3256 		if ((str = pshot_str2nt(nt_arr[i])) == NULL)
3257 			if (flags & PSHOT_DEV_ANYNT)
3258 				str = nt_arr[i];
3259 			else
3260 				goto FAIL;
3261 		devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP);
3262 	}
3263 	ddi_prop_free(name_arr);
3264 	ddi_prop_free(nt_arr);
3265 	ddi_prop_free(compat_arr);
3266 
3267 	/* set <*lenp> ONLY on success */
3268 	*lenp = name_arr_len;
3269 
3270 	return (devarr);
3271 	/*NOTREACHED*/
3272 FAIL:
3273 	cmn_err(CE_WARN, "malformed device specification property");
3274 	if (name_arr)
3275 		ddi_prop_free(name_arr);
3276 	if (nt_arr)
3277 		ddi_prop_free(nt_arr);
3278 	if (compat_arr)
3279 		ddi_prop_free(compat_arr);
3280 	if (devarr)
3281 		pshot_devices_free(devarr, name_arr_len);
3282 	return (NULL);
3283 }
3284 
3285 /*
3286  * if global <pshot_devices> was not set up already (i.e. is NULL):
3287  *	sets up global <pshot_devices> and <pshot_devices_len>,
3288  *	using device properties	from <dip> and global <pshot_stock_devices>.
3289  *	device properties, if any, overrides pshot_stock_devices.
3290  *
3291  * returns 0 on success (or if pshot_devices already set up)
3292  *
3293  * INTERNAL LOCKING: <pshot_devices_lock>
3294  */
3295 static int
3296 pshot_devices_setup(dev_info_t *dip)
3297 {
3298 	pshot_device_t *newdevs = NULL;
3299 	size_t newdevs_len = 0;
3300 	int rv = 0;
3301 
3302 	mutex_enter(&pshot_devices_lock);
3303 	if (pshot_devices != NULL)
3304 		goto FAIL;
3305 
3306 	ASSERT(pshot_devices_len == 0);
3307 
3308 	newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT);
3309 	rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices,
3310 	    PSHOT_N_STOCK_DEVICES);
3311 	if (rv != 0) {
3312 		cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow "
3313 		    "failed");
3314 		goto FAIL;
3315 	}
3316 	newdevs_len += PSHOT_N_STOCK_DEVICES;
3317 
3318 	pshot_devices = newdevs;
3319 	pshot_devices_len = newdevs_len;
3320 	rv = 0;
3321 FAIL:
3322 	if (rv && newdevs)
3323 		pshot_devices_free(newdevs, newdevs_len);
3324 	mutex_exit(&pshot_devices_lock);
3325 	return (rv);
3326 }
3327 
3328 
3329 #ifdef NOTNEEDED
3330 /* ARGSUSED */
3331 static int
3332 pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how,
3333     dev_info_t **return_dip)
3334 {
3335 	char name[64];
3336 	uint_t bus_id;
3337 	dev_info_t *child;
3338 
3339 	for (bus_id = 10; bus_id < 20; bus_id++) {
3340 		(void) sprintf(name, "%d", bus_id);
3341 		if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID,
3342 		    &child)) != NDI_SUCCESS) {
3343 			return (DDI_FAILURE);
3344 		}
3345 
3346 		if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
3347 		    "bus-addr", name) != DDI_PROP_SUCCESS) {
3348 			(void) ndi_devi_free(child);
3349 			if (return_dip != NULL)
3350 				*return_dip = (dev_info_t *)NULL;
3351 			return (DDI_FAILURE);
3352 		}
3353 
3354 		if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
3355 			return (DDI_FAILURE);
3356 		}
3357 	}
3358 	return (DDI_SUCCESS);
3359 }
3360 
3361 static int
3362 strtoi(char *str)
3363 {
3364 	int c;
3365 	int val;
3366 
3367 	for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
3368 		val *= 10;
3369 		val += c - '0';
3370 	}
3371 	return (val);
3372 }
3373 
3374 struct m_to_reg {
3375 	char	*mc;
3376 	int	n_regs;
3377 	int	regs[3];
3378 };
3379 
3380 struct m_to_reg m_regspecs[] = {
3381 	{"sun4c", 3, {0xf, 0x6000000, 0x20}},
3382 	{"sun4d", 3, {0xf, 0x6000000, 0x20}},
3383 	{"sun4m", 3, {0xf, 0x6000000, 0x20}},
3384 	{"sun4u", 3, {0xf, 0x6000000, 0x20}},
3385 	{"i86pc", 3, {0xf, 0x6000000, 0x20}},
3386 	{NULL, 0, {0, 0, 0}},
3387 };
3388 #endif
3389 
3390 static void
3391 pshot_setup_autoattach(dev_info_t *devi)
3392 {
3393 	dev_info_t *l1child, *l2child;
3394 	int rv;
3395 
3396 	rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child);
3397 	if (rv == NDI_SUCCESS) {
3398 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3399 		    "bus-addr", "0");
3400 		rv =  ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID,
3401 		    &l2child);
3402 		if (rv == NDI_SUCCESS)
3403 			(void) ndi_prop_update_string(DDI_DEV_T_NONE,
3404 			    l2child, "bus-addr", "99");
3405 	}
3406 
3407 	rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child);
3408 	if (rv == NDI_SUCCESS)
3409 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3410 		    "bus-addr", "99");
3411 
3412 	rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child);
3413 	if (rv == NDI_SUCCESS)
3414 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3415 		    "bus-addr", "99");
3416 
3417 	rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child);
3418 	if (rv == NDI_SUCCESS)
3419 		(void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID,
3420 		    &l2child);
3421 }
3422 
3423 #ifdef PRUNE_SNUBS
3424 
3425 #define	PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \
3426 	(DEVI_PROM_NODE((d)->devi_nodeid)) && \
3427 	((d)->devi_addr == NULL))
3428 /*
3429  * test code to remove OBP nodes that have not attached
3430  */
3431 static void
3432 prune_snubs(const char *name)
3433 {
3434 	struct dev_info *nex_dip, *cdip, *cndip;
3435 	int maj;
3436 	int rv;
3437 
3438 	maj = ddi_name_to_major((char *)name);
3439 	if (maj != -1) {
3440 		nex_dip = (struct dev_info *)devnamesp[maj].dn_head;
3441 		while (nex_dip != NULL) {
3442 			cndip = ddi_get_child(nex_dip);
3443 			while ((cdip = cndip) != NULL) {
3444 				cndip = cdip->devi_sibling;
3445 				if (PRUNE_THIS_NODE(cdip)) {
3446 					cmn_err(CE_NOTE,
3447 					    "parent %s@%s pruning node %s",
3448 					    nex_dip->devi_node_name,
3449 					    nex_dip->devi_addr,
3450 					    cdip->devi_node_name);
3451 					rv = ndi_devi_offline(cdip,
3452 					    NDI_DEVI_REMOVE);
3453 					if (rv != NDI_SUCCESS)
3454 						cmn_err(CE_NOTE,
3455 						    "failed to prune node, "
3456 						    "err %d", rv);
3457 				}
3458 			}
3459 		nex_dip = nex_dip->devi_next;
3460 		}
3461 	}
3462 }
3463 
3464 #endif /* PRUBE_SNUBS */
3465 
3466 #ifdef KERNEL_DEVICE_TREE_WALKER
3467 static kthread_id_t pwt;
3468 static kmutex_t pwl;
3469 static kcondvar_t pwcv;
3470 
3471 static void
3472 pshot_walk_tree()
3473 {
3474 	static int pshot_devnode(dev_info_t *dip, void * arg);
3475 
3476 	dev_info_t *root = ddi_root_node();
3477 	ddi_walk_devs(root, pshot_devnode, NULL);
3478 }
3479 
3480 static void
3481 pshot_walk_thread()
3482 {
3483 	static void pshot_timeout(void *arg);
3484 	static kthread_id_t pwt;
3485 
3486 	pwt = curthread;
3487 	mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL);
3488 	cv_init(&pwcv, NULL, CV_DRIVER, NULL);
3489 
3490 	while (1) {
3491 		pshot_walk_tree();
3492 		mutex_enter(&pwl);
3493 		(void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000));
3494 		cv_wait(&pwcv, &pwl);
3495 		mutex_exit(&pwl);
3496 	}
3497 }
3498 
3499 static void
3500 pshot_timeout(void *arg)
3501 {
3502 	mutex_enter(&pwl);
3503 	cv_signal(&pwcv);
3504 	mutex_exit(&pwl);
3505 }
3506 
3507 static int
3508 pshot_devnode(dev_info_t *dip, void *arg)
3509 {
3510 	dev_info_t *f_dip;
3511 
3512 	if (dip != ddi_root_node()) {
3513 		f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent,
3514 		    DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr);
3515 		if (f_dip != dip) {
3516 			cmn_err(CE_NOTE, "!pshot_devnode: failed lookup"
3517 			"node (%s/%s@%s)\n",
3518 			DEVI(DEVI(dip)->devi_parent)->devi_node_name,
3519 			(DEVI(dip)->devi_node_name ?
3520 				DEVI(dip)->devi_node_name : "NULL"),
3521 			(DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr : "NULL"));
3522 		}
3523 	}
3524 	return (DDI_WALK_CONTINUE);
3525 }
3526 #endif /* KERNEL_DEVICE_TREE_WALKER */
3527 
3528 #ifdef DEBUG
3529 static void
3530 pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie,
3531 	void *arg, void *bus_impldata)
3532 {
3533 	pshot_t *softstate = (pshot_t *)arg;
3534 	int event_tag;
3535 
3536 	/* look up the event */
3537 	event_tag = NDI_EVENT_TAG(cookie);
3538 	cmn_err(CE_CONT, "pshot_event_cb_test:\n\t"
3539 	    "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
3540 	    "arg = 0x%p bus_impl = 0x%p\n",
3541 	    (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie),
3542 	    event_tag, (void *)softstate, (void *)bus_impldata);
3543 
3544 }
3545 
3546 static void
3547 pshot_event_test(void *arg)
3548 {
3549 	pshot_t *pshot = (pshot_t *)arg;
3550 	ndi_event_hdl_t hdl;
3551 	ndi_event_set_t	events;
3552 	int i, rval;
3553 
3554 	(void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP);
3555 
3556 	events.ndi_events_version = NDI_EVENTS_REV1;
3557 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3558 	events.ndi_event_defs = pshot_test_events;
3559 
3560 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3561 	delay(drv_usectohz(1000000));
3562 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3563 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3564 
3565 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3566 	delay(drv_usectohz(1000000));
3567 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3568 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3569 
3570 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
3571 	delay(drv_usectohz(1000000));
3572 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3573 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3574 
3575 
3576 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3577 	delay(drv_usectohz(1000000));
3578 	events.ndi_n_events = 1;
3579 	events.ndi_event_defs = pshot_test_events_high;
3580 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3581 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3582 
3583 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3584 	delay(drv_usectohz(1000000));
3585 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3586 	events.ndi_event_defs = pshot_test_events;
3587 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3588 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3589 
3590 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3591 	delay(drv_usectohz(1000000));
3592 	events.ndi_n_events = 1;
3593 	events.ndi_event_defs = pshot_test_events_high;
3594 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3595 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3596 
3597 	cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3598 	delay(drv_usectohz(1000000));
3599 	events.ndi_n_events = 1;
3600 	events.ndi_event_defs = pshot_test_events_high;
3601 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3602 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3603 
3604 	cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3605 	delay(drv_usectohz(1000000));
3606 	events.ndi_n_events = 1;
3607 	events.ndi_event_defs = pshot_test_events_high;
3608 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3609 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3610 
3611 	cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3612 	delay(drv_usectohz(1000000));
3613 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3614 	events.ndi_event_defs = pshot_test_events;
3615 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3616 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3617 
3618 	cmn_err(CE_CONT, "pshot: unbinding first 2 events\n");
3619 	delay(drv_usectohz(1000000));
3620 	events.ndi_n_events = 2;
3621 	events.ndi_event_defs = pshot_test_events;
3622 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3623 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3624 
3625 	cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n");
3626 	delay(drv_usectohz(1000000));
3627 	events.ndi_n_events = 2;
3628 	events.ndi_event_defs = pshot_test_events;
3629 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3630 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3631 
3632 	cmn_err(CE_CONT, "pshot: unbinding  middle 2 events\n");
3633 	delay(drv_usectohz(1000000));
3634 	events.ndi_n_events = 2;
3635 	events.ndi_event_defs = &pshot_test_events[4];
3636 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3637 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3638 
3639 	cmn_err(CE_CONT, "pshot: binding those 2 events back\n");
3640 	delay(drv_usectohz(1000000));
3641 	events.ndi_n_events = 2;
3642 	events.ndi_event_defs = &pshot_test_events[4];
3643 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3644 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3645 
3646 	cmn_err(CE_CONT, "pshot: unbinding  2 events\n");
3647 	delay(drv_usectohz(1000000));
3648 	events.ndi_n_events = 2;
3649 	events.ndi_event_defs = &pshot_test_events[4];
3650 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3651 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3652 
3653 	cmn_err(CE_CONT, "pshot: unbinding  all events\n");
3654 	delay(drv_usectohz(1000000));
3655 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3656 	events.ndi_event_defs = pshot_test_events;
3657 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3658 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3659 
3660 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3661 	delay(drv_usectohz(1000000));
3662 	events.ndi_n_events = 1;
3663 	events.ndi_event_defs = &pshot_test_events[2];
3664 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3665 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3666 
3667 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3668 	delay(drv_usectohz(1000000));
3669 	events.ndi_n_events = 1;
3670 	events.ndi_event_defs = &pshot_test_events[3];
3671 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3672 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3673 
3674 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3675 	delay(drv_usectohz(1000000));
3676 	events.ndi_n_events = 1;
3677 	events.ndi_event_defs = &pshot_test_events[6];
3678 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3679 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3680 
3681 	cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3682 	delay(drv_usectohz(1000000));
3683 	events.ndi_n_events = 1;
3684 	events.ndi_event_defs = &pshot_test_events[7];
3685 	rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3686 	cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3687 
3688 	events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3689 	events.ndi_event_defs = pshot_test_events;
3690 
3691 	cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3692 	delay(drv_usectohz(1000000));
3693 	rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3694 	cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3695 
3696 	cmn_err(CE_CONT, "pshot: adding 8 callbacks\n");
3697 	delay(drv_usectohz(1000000));
3698 	for (i = 0; i < 8; i++) {
3699 		rval = ndi_event_add_callback(hdl, pshot->dip,
3700 			ndi_event_tag_to_cookie(hdl,
3701 				pshot_test_events[i].ndi_event_tag),
3702 			pshot_event_cb_test,
3703 			(void *)(uintptr_t)pshot_test_events[i].ndi_event_tag,
3704 			NDI_SLEEP, &pshot->test_callback_cache[i]);
3705 		ASSERT(rval == NDI_SUCCESS);
3706 	}
3707 
3708 	cmn_err(CE_CONT, "pshot: event callbacks\n");
3709 
3710 	for (i = 10; i < 18; i++) {
3711 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3712 
3713 		rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie,
3714 		    (void *)hdl);
3715 
3716 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3717 			i, rval);
3718 		delay(drv_usectohz(1000000));
3719 	}
3720 
3721 	cmn_err(CE_CONT, "pshot: redo event callbacks\n");
3722 
3723 	for (i = 10; i < 18; i++) {
3724 		ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3725 
3726 		rval = ndi_event_run_callbacks(hdl,
3727 			pshot->dip, cookie, (void *)hdl);
3728 
3729 		cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3730 			i, rval);
3731 		delay(drv_usectohz(1000000));
3732 	}
3733 
3734 	cmn_err(CE_CONT, "pshot: removing 8 callbacks\n");
3735 	delay(drv_usectohz(1000000));
3736 
3737 	for (i = 0; i < 8; i++) {
3738 		(void) ndi_event_remove_callback(hdl,
3739 		    pshot->test_callback_cache[i]);
3740 
3741 		pshot->test_callback_cache[i] = 0;
3742 	}
3743 
3744 	cmn_err(CE_CONT, "pshot: freeing handle with bound set\n");
3745 	delay(drv_usectohz(1000000));
3746 
3747 	rval =	ndi_event_free_hdl(hdl);
3748 
3749 	ASSERT(rval == NDI_SUCCESS);
3750 
3751 }
3752 
3753 void
3754 pshot_event_test_post_one(void *arg)
3755 {
3756 	pshot_t	*pshot = (pshot_t *)arg;
3757 	int rval;
3758 	ddi_eventcookie_t cookie;
3759 
3760 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n",
3761 		pshot->instance);
3762 
3763 	if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST,
3764 	    &cookie) != DDI_SUCCESS) {
3765 		cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found");
3766 		return;
3767 	}
3768 
3769 	rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL);
3770 
3771 	cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n",
3772 		pshot->instance, rval);
3773 
3774 	(void) timeout(pshot_event_test_post_one, (void *)pshot,
3775 		pshot->instance * drv_usectohz(60000000));
3776 
3777 }
3778 #endif /* DEBUG */
3779