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