xref: /illumos-gate/usr/src/uts/common/io/pm.c (revision 5c0b7edee9bd9fad49038456b16972ff28fa4187)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * pm	This driver now only handles the ioctl interface.  The scanning
30  *	and policy stuff now lives in common/os/sunpm.c.
31  *	Not DDI compliant
32  */
33 
34 #include <sys/types.h>
35 #include <sys/errno.h>
36 #include <sys/modctl.h>
37 #include <sys/conf.h>		/* driver flags and functions */
38 #include <sys/open.h>		/* OTYP_CHR definition */
39 #include <sys/stat.h>		/* S_IFCHR definition */
40 #include <sys/pathname.h>	/* name -> dev_info xlation */
41 #include <sys/kmem.h>		/* memory alloc stuff */
42 #include <sys/debug.h>
43 #include <sys/pm.h>
44 #include <sys/ddi.h>
45 #include <sys/sunddi.h>
46 #include <sys/epm.h>
47 #include <sys/vfs.h>
48 #include <sys/mode.h>
49 #include <sys/mkdev.h>
50 #include <sys/promif.h>
51 #include <sys/consdev.h>
52 #include <sys/ddi_impldefs.h>
53 #include <sys/poll.h>
54 #include <sys/note.h>
55 #include <sys/taskq.h>
56 #include <sys/policy.h>
57 
58 /*
59  * Minor number is instance<<8 + clone minor from range 1-255; (0 reserved
60  * for "original"
61  */
62 #define	PM_MINOR_TO_CLONE(minor) ((minor) & (PM_MAX_CLONE - 1))
63 
64 #define	PM_NUMCMPTS(dip) (DEVI(dip)->devi_pm_num_components)
65 #define	PM_IS_CFB(dip) (DEVI(dip)->devi_pm_flags & PMC_CONSOLE_FB)
66 #define	PM_MAJOR(dip) ddi_driver_major(dip)
67 #define	PM_RELE(dip) ddi_release_devi(dip)
68 
69 #define	PM_IDLEDOWN_TIME	10
70 
71 extern kmutex_t	pm_scan_lock;	/* protects autopm_enable, pm_scans_disabled */
72 extern kmutex_t	pm_clone_lock;	/* protects pm_clones array */
73 extern int	autopm_enabled;
74 extern pm_cpupm_t cpupm;
75 extern int	pm_default_idle_threshold;
76 extern int	pm_system_idle_threshold;
77 extern int	pm_cpu_idle_threshold;
78 extern kcondvar_t pm_clones_cv[PM_MAX_CLONE];
79 extern uint_t	pm_poll_cnt[PM_MAX_CLONE];
80 
81 /*
82  * The soft state of the power manager.  Since there will only
83  * one of these, just reference it through a static pointer.
84  */
85 static struct pmstate {
86 	dev_info_t	*pm_dip;		/* ptr to our dev_info node */
87 	int		pm_instance;		/* for ddi_get_instance() */
88 	timeout_id_t	pm_idledown_id;		/* pm idledown timeout id */
89 	uchar_t		pm_clones[PM_MAX_CLONE]; /* uniqueify multiple opens */
90 	struct cred	*pm_cred[PM_MAX_CLONE];	/* cred for each unique open */
91 } pm_state = { NULL, -1, (timeout_id_t)0 };
92 typedef struct pmstate *pm_state_t;
93 static pm_state_t pmstp = &pm_state;
94 
95 static int	pm_open(dev_t *, int, int, cred_t *);
96 static int	pm_close(dev_t, int, int, cred_t *);
97 static int	pm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
98 static int	pm_chpoll(dev_t, short, int, short *, struct pollhead **);
99 
100 static struct cb_ops pm_cb_ops = {
101 	pm_open,	/* open */
102 	pm_close,	/* close */
103 	nodev,		/* strategy */
104 	nodev,		/* print */
105 	nodev,		/* dump */
106 	nodev,		/* read */
107 	nodev,		/* write */
108 	pm_ioctl,	/* ioctl */
109 	nodev,		/* devmap */
110 	nodev,		/* mmap */
111 	nodev,		/* segmap */
112 	pm_chpoll,	/* poll */
113 	ddi_prop_op,	/* prop_op */
114 	NULL,		/* streamtab */
115 	D_NEW | D_MP	/* driver compatibility flag */
116 };
117 
118 static int pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
119     void **result);
120 static int pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
121 static int pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
122 
123 static struct dev_ops pm_ops = {
124 	DEVO_REV,		/* devo_rev */
125 	0,			/* refcnt */
126 	pm_getinfo,		/* info */
127 	nulldev,		/* identify */
128 	nulldev,		/* probe */
129 	pm_attach,		/* attach */
130 	pm_detach,		/* detach */
131 	nodev,			/* reset */
132 	&pm_cb_ops,		/* driver operations */
133 	NULL,			/* bus operations */
134 	NULL			/* power */
135 };
136 
137 static struct modldrv modldrv = {
138 	&mod_driverops,
139 	"power management driver v%I%",
140 	&pm_ops
141 };
142 
143 static struct modlinkage modlinkage = {
144 	MODREV_1, &modldrv, 0
145 };
146 
147 /* Local functions */
148 #ifdef DEBUG
149 static int	print_info(dev_info_t *, void *);
150 
151 #endif
152 
153 int
154 _init(void)
155 {
156 	return (mod_install(&modlinkage));
157 }
158 
159 int
160 _fini(void)
161 {
162 	return (mod_remove(&modlinkage));
163 }
164 
165 int
166 _info(struct modinfo *modinfop)
167 {
168 	return (mod_info(&modlinkage, modinfop));
169 }
170 
171 static int
172 pm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
173 {
174 	int		i;
175 
176 	switch (cmd) {
177 
178 	case DDI_ATTACH:
179 		if (pmstp->pm_instance != -1)	/* Only allow one instance */
180 			return (DDI_FAILURE);
181 		pmstp->pm_instance = ddi_get_instance(dip);
182 		if (ddi_create_minor_node(dip, "pm", S_IFCHR,
183 		    (pmstp->pm_instance << 8) + 0,
184 			DDI_PSEUDO, 0) != DDI_SUCCESS) {
185 			return (DDI_FAILURE);
186 		}
187 		pmstp->pm_dip = dip;	/* pm_init and getinfo depend on it */
188 
189 		for (i = 0; i < PM_MAX_CLONE; i++)
190 			cv_init(&pm_clones_cv[i], NULL, CV_DEFAULT, NULL);
191 
192 		ddi_report_dev(dip);
193 		return (DDI_SUCCESS);
194 
195 	default:
196 		return (DDI_FAILURE);
197 	}
198 }
199 
200 /* ARGSUSED */
201 static int
202 pm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
203 {
204 	int i;
205 
206 	switch (cmd) {
207 	case DDI_DETACH:
208 		/*
209 		 * Don't detach while idledown timeout is pending.  Note that
210 		 * we already know we're not in pm_ioctl() due to framework
211 		 * synchronization, so this is a sufficient test
212 		 */
213 		if (pmstp->pm_idledown_id)
214 			return (DDI_FAILURE);
215 
216 		for (i = 0; i < PM_MAX_CLONE; i++)
217 			cv_destroy(&pm_clones_cv[i]);
218 
219 		ddi_remove_minor_node(dip, NULL);
220 		pmstp->pm_instance = -1;
221 		return (DDI_SUCCESS);
222 
223 	default:
224 		return (DDI_FAILURE);
225 	}
226 }
227 
228 static int
229 pm_close_direct_pm_device(dev_info_t *dip, void *arg)
230 {
231 	int clone;
232 	char *pathbuf;
233 	pm_info_t *info = PM_GET_PM_INFO(dip);
234 
235 	clone = *((int *)arg);
236 
237 	if (!info)
238 		return (DDI_WALK_CONTINUE);
239 
240 	pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
241 	PM_LOCK_DIP(dip);
242 	if (clone == info->pmi_clone) {
243 		PMD(PMD_CLOSE, ("pm_close: found %s@%s(%s#%d)\n",
244 		    PM_DEVICE(dip)))
245 		ASSERT(PM_ISDIRECT(dip));
246 		info->pmi_dev_pm_state &= ~PM_DIRECT;
247 		PM_UNLOCK_DIP(dip);
248 		pm_proceed(dip, PMP_RELEASE, -1, -1);
249 		/* Bring ourselves up if there is a keeper that is up */
250 		(void) ddi_pathname(dip, pathbuf);
251 		pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF, NULL,
252 		    pathbuf, PM_DEP_NOWAIT, NULL, 0);
253 		PM_LOCK_DIP(dip);
254 		info->pmi_clone = 0;
255 		PM_UNLOCK_DIP(dip);
256 	} else {
257 		PM_UNLOCK_DIP(dip);
258 	}
259 	kmem_free(pathbuf, MAXPATHLEN);
260 
261 	/* restart autopm on device released from direct pm */
262 	pm_rescan(dip);
263 
264 	return (DDI_WALK_CONTINUE);
265 }
266 
267 #define	PM_REQ		1
268 #define	NOSTRUCT	2
269 #define	DIP		3
270 #define	NODIP		4
271 #define	NODEP		5
272 #define	DEP		6
273 #define	PM_PSC		7
274 
275 #define	CHECKPERMS	0x001
276 #define	SU		0x002
277 #define	SG		0x004
278 #define	OWNER		0x008
279 
280 #define	INWHO		0x001
281 #define	INDATAINT	0x002
282 #define	INDATASTRING	0x004
283 #define	INDEP		0x008
284 #define	INDATAOUT	0x010
285 #define	INDATA	(INDATAOUT | INDATAINT | INDATASTRING | INDEP)
286 
287 struct pm_cmd_info {
288 	int cmd;		/* command code */
289 	char *name;		/* printable string */
290 	int supported;		/* true if still supported */
291 	int str_type;		/* PM_REQ or NOSTRUCT */
292 	int inargs;		/* INWHO, INDATAINT, INDATASTRING, INDEP, */
293 				/* INDATAOUT */
294 	int diptype;		/* DIP or NODIP */
295 	int deptype;		/* DEP or NODEP */
296 	int permission;		/* SU, GU, or CHECKPERMS */
297 };
298 
299 #ifdef DEBUG
300 char *pm_cmd_string;
301 int pm_cmd;
302 #endif
303 
304 /*
305  * Returns true if permission granted by credentials
306  */
307 static int
308 pm_perms(int perm, cred_t *cr)
309 {
310 	if (perm == 0)			/* no restrictions */
311 		return (1);
312 	if (perm == CHECKPERMS)		/* ok for now (is checked later) */
313 		return (1);
314 	if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */
315 		return (1);
316 	if ((perm & SG) && (crgetgid(cr) == 0))	/* group 0 is ok */
317 		return (1);
318 	return (0);
319 }
320 
321 #ifdef DEBUG
322 static int
323 print_info(dev_info_t *dip, void *arg)
324 {
325 	_NOTE(ARGUNUSED(arg))
326 	pm_info_t	*info;
327 	int		i, j;
328 	struct pm_component *cp;
329 	extern int pm_cur_power(pm_component_t *cp);
330 
331 	info = PM_GET_PM_INFO(dip);
332 	if (!info)
333 		return (DDI_WALK_CONTINUE);
334 	cmn_err(CE_CONT, "pm_info for %s\n", ddi_node_name(dip));
335 	for (i = 0; i < PM_NUMCMPTS(dip); i++) {
336 		cp = PM_CP(dip, i);
337 		cmn_err(CE_CONT, "\tThresholds[%d] =",  i);
338 		for (j = 0; j < cp->pmc_comp.pmc_numlevels; j++)
339 			cmn_err(CE_CONT, " %d", cp->pmc_comp.pmc_thresh[i]);
340 		cmn_err(CE_CONT, "\n");
341 		cmn_err(CE_CONT, "\tCurrent power[%d] = %d\n", i,
342 		    pm_cur_power(cp));
343 	}
344 	if (PM_ISDIRECT(dip))
345 		cmn_err(CE_CONT, "\tDirect power management\n");
346 	return (DDI_WALK_CONTINUE);
347 }
348 #endif
349 
350 /*
351  * command, name, supported, str_type, inargs, diptype, deptype, permission
352  */
353 static struct pm_cmd_info pmci[] = {
354 	{PM_SCHEDULE, "PM_SCHEDULE", 0},
355 	{PM_GET_IDLE_TIME, "PM_GET_IDLE_TIME", 0},
356 	{PM_GET_NUM_CMPTS, "PM_GET_NUM_CMPTS", 0},
357 	{PM_GET_THRESHOLD, "PM_GET_THRESHOLD", 0},
358 	{PM_SET_THRESHOLD, "PM_SET_THRESHOLD", 0},
359 	{PM_GET_NORM_PWR, "PM_GET_NORM_PWR", 0},
360 	{PM_SET_CUR_PWR, "PM_SET_CUR_PWR", 0},
361 	{PM_GET_CUR_PWR, "PM_GET_CUR_PWR", 0},
362 	{PM_GET_NUM_DEPS, "PM_GET_NUM_DEPS", 0},
363 	{PM_GET_DEP, "PM_GET_DEP", 0},
364 	{PM_ADD_DEP, "PM_ADD_DEP", 0},
365 	{PM_REM_DEP, "PM_REM_DEP", 0},
366 	{PM_REM_DEVICE, "PM_REM_DEVICE", 0},
367 	{PM_REM_DEVICES, "PM_REM_DEVICES", 0},
368 	{PM_REPARSE_PM_PROPS, "PM_REPARSE_PM_PROPS", 1, PM_REQ, INWHO, DIP,
369 	    NODEP},
370 	{PM_DISABLE_AUTOPM, "PM_DISABLE_AUTOPM", 0},
371 	{PM_REENABLE_AUTOPM, "PM_REENABLE_AUTOPM", 0},
372 	{PM_SET_NORM_PWR, "PM_SET_NORM_PWR", 0 },
373 	{PM_SET_DEVICE_THRESHOLD, "PM_SET_DEVICE_THRESHOLD", 1, PM_REQ,
374 	    INWHO, NODIP, NODEP, SU},
375 	{PM_GET_SYSTEM_THRESHOLD, "PM_GET_SYSTEM_THRESHOLD", 1, NOSTRUCT},
376 	{PM_GET_DEFAULT_SYSTEM_THRESHOLD, "PM_GET_DEFAULT_SYSTEM_THRESHOLD",
377 	    1, NOSTRUCT},
378 	{PM_SET_SYSTEM_THRESHOLD, "PM_SET_SYSTEM_THRESHOLD", 1, NOSTRUCT,
379 	    0, 0, 0, SU},
380 	{PM_START_PM, "PM_START_PM", 1, NOSTRUCT, 0, 0, 0, SU},
381 	{PM_STOP_PM, "PM_STOP_PM", 1, NOSTRUCT, 0, 0, 0, SU},
382 	{PM_RESET_PM, "PM_RESET_PM", 1, NOSTRUCT, 0, 0, 0, SU},
383 	{PM_GET_STATS, "PM_GET_STATS", 1, PM_REQ, INWHO | INDATAOUT,
384 	    DIP, NODEP},
385 	{PM_GET_DEVICE_THRESHOLD, "PM_GET_DEVICE_THRESHOLD", 1, PM_REQ, INWHO,
386 	    DIP, NODEP},
387 	{PM_GET_POWER_NAME, "PM_GET_POWER_NAME", 1, PM_REQ, INWHO | INDATAOUT,
388 	    DIP, NODEP},
389 	{PM_GET_POWER_LEVELS, "PM_GET_POWER_LEVELS", 1, PM_REQ,
390 	    INWHO | INDATAOUT, DIP, NODEP},
391 	{PM_GET_NUM_COMPONENTS, "PM_GET_NUM_COMPONENTS", 1, PM_REQ, INWHO,
392 	    DIP, NODEP},
393 	{PM_GET_COMPONENT_NAME, "PM_GET_COMPONENT_NAME", 1, PM_REQ,
394 	    INWHO | INDATAOUT, DIP, NODEP},
395 	{PM_GET_NUM_POWER_LEVELS, "PM_GET_NUM_POWER_LEVELS", 1, PM_REQ, INWHO,
396 	    DIP, NODEP},
397 	{PM_GET_STATE_CHANGE, "PM_GET_STATE_CHANGE", 1, PM_PSC},
398 	{PM_GET_STATE_CHANGE_WAIT, "PM_GET_STATE_CHANGE_WAIT", 1, PM_PSC},
399 	{PM_DIRECT_PM, "PM_DIRECT_PM", 1, PM_REQ, INWHO, DIP, NODEP,
400 	    (SU | SG)},
401 	{PM_RELEASE_DIRECT_PM, "PM_RELEASE_DIRECT_PM", 1, PM_REQ, INWHO,
402 	    DIP, NODEP},
403 	{PM_DIRECT_NOTIFY, "PM_DIRECT_NOTIFY", 1, PM_PSC},
404 	{PM_DIRECT_NOTIFY_WAIT, "PM_DIRECT_NOTIFY_WAIT", 1, PM_PSC},
405 	{PM_RESET_DEVICE_THRESHOLD, "PM_RESET_DEVICE_THRESHOLD", 1, PM_REQ,
406 	    INWHO, DIP, NODEP, SU},
407 	{PM_GET_PM_STATE, "PM_GET_PM_STATE", 1, NOSTRUCT},
408 	{PM_GET_DEVICE_TYPE, "PM_GET_DEVICE_TYPE", 1, PM_REQ, INWHO,
409 	    DIP, NODEP},
410 	{PM_SET_COMPONENT_THRESHOLDS, "PM_SET_COMPONENT_THRESHOLDS", 1, PM_REQ,
411 	    INWHO | INDATAINT, NODIP, NODEP, SU},
412 	{PM_GET_COMPONENT_THRESHOLDS, "PM_GET_COMPONENT_THRESHOLDS", 1, PM_REQ,
413 	    INWHO | INDATAOUT, DIP, NODEP},
414 	{PM_IDLE_DOWN, "PM_IDLE_DOWN", 1, NOSTRUCT, 0, 0, 0, SU},
415 	{PM_GET_DEVICE_THRESHOLD_BASIS, "PM_GET_DEVICE_THRESHOLD_BASIS", 1,
416 	    PM_REQ, INWHO, DIP, NODEP},
417 	{PM_SET_CURRENT_POWER, "PM_SET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP,
418 	    NODEP},
419 	{PM_GET_CURRENT_POWER, "PM_GET_CURRENT_POWER", 1, PM_REQ, INWHO, DIP,
420 	    NODEP},
421 	{PM_GET_FULL_POWER, "PM_GET_FULL_POWER", 1, PM_REQ, INWHO, DIP,
422 	    NODEP},
423 	{PM_ADD_DEPENDENT, "PM_ADD_DEPENDENT", 1, PM_REQ, INWHO | INDATASTRING,
424 	    DIP, DEP, SU},
425 	{PM_GET_TIME_IDLE, "PM_GET_TIME_IDLE", 1, PM_REQ, INWHO, DIP, NODEP},
426 	{PM_ADD_DEPENDENT_PROPERTY, "PM_ADD_DEPENDENT_PROPERTY", 1, PM_REQ,
427 	    INWHO | INDATASTRING, NODIP, DEP, SU},
428 	{PM_START_CPUPM, "PM_START_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU},
429 	{PM_STOP_CPUPM, "PM_STOP_CPUPM", 1, NOSTRUCT, 0, 0, 0, SU},
430 	{PM_GET_CPU_THRESHOLD, "PM_GET_CPU_THRESHOLD", 1, NOSTRUCT},
431 	{PM_SET_CPU_THRESHOLD, "PM_SET_CPU_THRESHOLD", 1, NOSTRUCT,
432 	    0, 0, 0, SU},
433 	{PM_GET_CPUPM_STATE, "PM_GET_CPUPM_STATE", 1, NOSTRUCT},
434 	{0, NULL}
435 };
436 
437 struct pm_cmd_info *
438 pc_info(int cmd)
439 {
440 	struct pm_cmd_info *pcip;
441 
442 	for (pcip = pmci; pcip->name; pcip++) {
443 		if (cmd == pcip->cmd)
444 			return (pcip);
445 	}
446 	return (NULL);
447 }
448 
449 static char *
450 pm_decode_cmd(int cmd)
451 {
452 	static char invbuf[64];
453 	struct pm_cmd_info *pcip = pc_info(cmd);
454 	if (pcip != NULL)
455 		return (pcip->name);
456 	(void) sprintf(invbuf, "ioctl: invalid command %d\n", cmd);
457 	return (invbuf);
458 }
459 
460 /*
461  * Allocate scan resource, create taskq, then dispatch scan,
462  * called only if autopm is enabled.
463  */
464 int
465 pm_start_pm_walk(dev_info_t *dip, void *arg)
466 {
467 	int cmd = *((int *)arg);
468 #ifdef PMDDEBUG
469 	char *cmdstr = pm_decode_cmd(cmd);
470 #endif
471 
472 	if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip))
473 		return (DDI_WALK_CONTINUE);
474 
475 	switch (cmd) {
476 	case PM_START_CPUPM:
477 		if (!PM_ISCPU(dip))
478 			return (DDI_WALK_CONTINUE);
479 		mutex_enter(&pm_scan_lock);
480 		if (!PM_CPUPM_DISABLED)
481 			pm_scan_init(dip);
482 		mutex_exit(&pm_scan_lock);
483 		break;
484 	case PM_START_PM:
485 		mutex_enter(&pm_scan_lock);
486 		if (PM_ISCPU(dip) && PM_CPUPM_DISABLED) {
487 			mutex_exit(&pm_scan_lock);
488 			return (DDI_WALK_CONTINUE);
489 		}
490 		if (autopm_enabled)
491 			pm_scan_init(dip);
492 		mutex_exit(&pm_scan_lock);
493 		break;
494 	}
495 
496 	/*
497 	 * Start doing pm on device: ensure pm_scan data structure initiated,
498 	 * no need to guarantee a successful scan run.
499 	 */
500 	PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: scan %s@%s(%s#%d)\n", cmdstr,
501 	    PM_DEVICE(dip)))
502 	pm_rescan(dip);
503 
504 	return (DDI_WALK_CONTINUE);
505 }
506 
507 /*
508  * Bring devices to full power level, then stop scan
509  */
510 int
511 pm_stop_pm_walk(dev_info_t *dip, void *arg)
512 {
513 	pm_info_t *info = PM_GET_PM_INFO(dip);
514 	int cmd = *((int *)arg);
515 #ifdef PMDDEBUG
516 	char *cmdstr = pm_decode_cmd(cmd);
517 #endif
518 
519 	if (!info)
520 		return (DDI_WALK_CONTINUE);
521 
522 	switch (cmd) {
523 	case PM_STOP_PM:
524 		/*
525 		 * If CPU devices are being managed independently, then don't
526 		 * stop them as part of PM_STOP_PM. Only stop them as part of
527 		 * PM_STOP_CPUPM and PM_RESET_PM.
528 		 */
529 		if (PM_ISCPU(dip) && PM_CPUPM_ENABLED)
530 			return (DDI_WALK_CONTINUE);
531 		break;
532 	case PM_STOP_CPUPM:
533 		/*
534 		 * If stopping CPU devices and this device is not marked
535 		 * as a CPU device, then skip.
536 		 */
537 		if (!PM_ISCPU(dip))
538 			return (DDI_WALK_CONTINUE);
539 		break;
540 	}
541 
542 	/*
543 	 * Stop the current scan, and then bring it back to normal power.
544 	 */
545 	if (!PM_ISBC(dip)) {
546 		PMD(PMD_SCAN | PMD_IOCTL, ("ioctl: %s: stop scan for "
547 		    "%s@%s(%s#%d)\n", cmdstr, PM_DEVICE(dip)))
548 		pm_scan_stop(dip);
549 	}
550 
551 	if (!PM_ISBC(dip) && !PM_ISDIRECT(dip) &&
552 	    !pm_all_at_normal(dip)) {
553 		PM_LOCK_DIP(dip);
554 		if (info->pmi_dev_pm_state & PM_DETACHING) {
555 			PMD(PMD_ALLNORM, ("ioctl: %s: deferring "
556 			    "all_to_normal because %s@%s(%s#%d) is detaching\n",
557 			    cmdstr, PM_DEVICE(dip)))
558 			info->pmi_dev_pm_state |= PM_ALLNORM_DEFERRED;
559 			PM_UNLOCK_DIP(dip);
560 			return (DDI_WALK_CONTINUE);
561 		}
562 		PM_UNLOCK_DIP(dip);
563 		if (pm_all_to_normal(dip, PM_CANBLOCK_FAIL) != DDI_SUCCESS) {
564 			PMD(PMD_ERROR, ("ioctl: %s: could not bring %s@%s"
565 			    "(%s#%d) to normal\n", cmdstr, PM_DEVICE(dip)))
566 		}
567 	}
568 
569 	return (DDI_WALK_CONTINUE);
570 }
571 
572 static int
573 pm_start_idledown(dev_info_t *dip, void *arg)
574 {
575 	int		flag = (int)(intptr_t)arg;
576 	pm_scan_t	*scanp = PM_GET_PM_SCAN(dip);
577 
578 	if (!scanp)
579 		return (DDI_WALK_CONTINUE);
580 
581 	PM_LOCK_DIP(dip);
582 	scanp->ps_idle_down |= flag;
583 	PM_UNLOCK_DIP(dip);
584 	pm_rescan(dip);
585 
586 	return (DDI_WALK_CONTINUE);
587 }
588 
589 /*ARGSUSED*/
590 static int
591 pm_end_idledown(dev_info_t *dip, void *ignore)
592 {
593 	pm_scan_t	*scanp = PM_GET_PM_SCAN(dip);
594 
595 	if (!scanp)
596 		return (DDI_WALK_CONTINUE);
597 
598 	PM_LOCK_DIP(dip);
599 	/*
600 	 * The PMID_TIMERS bits are place holder till idledown expires.
601 	 * The bits are also the base for regenerating PMID_SCANS bits.
602 	 * While it's up to scan thread to clear up the PMID_SCANS bits
603 	 * after each scan run, PMID_TIMERS ensure aggressive scan down
604 	 * performance throughout the idledown period.
605 	 */
606 	scanp->ps_idle_down &= ~PMID_TIMERS;
607 	PM_UNLOCK_DIP(dip);
608 
609 	return (DDI_WALK_CONTINUE);
610 }
611 
612 /*ARGSUSED*/
613 static void
614 pm_end_idledown_walk(void *ignore)
615 {
616 	PMD(PMD_IDLEDOWN, ("ioctl: end_idledown: idledown_id(%lx) timer is "
617 	    "off\n", (ulong_t)pmstp->pm_idledown_id));
618 
619 	mutex_enter(&pm_scan_lock);
620 	pmstp->pm_idledown_id = 0;
621 	mutex_exit(&pm_scan_lock);
622 
623 	ddi_walk_devs(ddi_root_node(), pm_end_idledown, NULL);
624 }
625 
626 /*
627  * pm_timeout_idledown - keep idledown effect for 10 seconds.
628  *
629  * Return 0 if another competing caller scheduled idledown timeout,
630  * otherwise, return idledown timeout_id.
631  */
632 static timeout_id_t
633 pm_timeout_idledown(void)
634 {
635 	timeout_id_t	to_id;
636 
637 	/*
638 	 * Keep idle-down in effect for either 10 seconds
639 	 * or length of a scan interval, which ever is greater.
640 	 */
641 	mutex_enter(&pm_scan_lock);
642 	if (pmstp->pm_idledown_id != 0) {
643 		to_id = pmstp->pm_idledown_id;
644 		pmstp->pm_idledown_id = 0;
645 		mutex_exit(&pm_scan_lock);
646 		(void) untimeout(to_id);
647 		mutex_enter(&pm_scan_lock);
648 		if (pmstp->pm_idledown_id != 0) {
649 			PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: "
650 			    "another caller got it, idledown_id(%lx)!\n",
651 			    (ulong_t)pmstp->pm_idledown_id))
652 			mutex_exit(&pm_scan_lock);
653 			return (0);
654 		}
655 	}
656 	pmstp->pm_idledown_id = timeout(pm_end_idledown_walk, NULL,
657 	    PM_IDLEDOWN_TIME * hz);
658 	PMD(PMD_IDLEDOWN, ("ioctl: timeout_idledown: idledown_id(%lx)\n",
659 	    (ulong_t)pmstp->pm_idledown_id))
660 	mutex_exit(&pm_scan_lock);
661 
662 	return (pmstp->pm_idledown_id);
663 }
664 
665 static int
666 pm_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
667 	struct pollhead **phpp)
668 {
669 	extern struct pollhead pm_pollhead;	/* common/os/sunpm.c */
670 	int	clone;
671 
672 	clone = PM_MINOR_TO_CLONE(getminor(dev));
673 	PMD(PMD_IOCTL, ("ioctl: pm_chpoll: clone %d\n", clone))
674 	if ((events & (POLLIN | POLLRDNORM)) && pm_poll_cnt[clone]) {
675 		*reventsp |= (POLLIN | POLLRDNORM);
676 		PMD(PMD_IOCTL, ("ioctl: pm_chpoll: reventsp set\n"))
677 	} else {
678 		*reventsp = 0;
679 		if (!anyyet) {
680 			PMD(PMD_IOCTL, ("ioctl: pm_chpoll: not anyyet\n"))
681 			*phpp = &pm_pollhead;
682 		}
683 #ifdef DEBUG
684 		else {
685 			PMD(PMD_IOCTL, ("ioctl: pm_chpoll: anyyet\n"))
686 		}
687 #endif
688 	}
689 	return (0);
690 }
691 
692 /*
693  * called by pm_dicard_entries to free up the memory. It also decrements
694  * pm_poll_cnt, if direct is non zero.
695  */
696 static void
697 pm_free_entries(psce_t *pscep, int clone, int direct)
698 {
699 	pm_state_change_t	*p;
700 
701 	if (pscep) {
702 		p = pscep->psce_out;
703 		while (p->size) {
704 			if (direct) {
705 				PMD(PMD_IOCTL, ("ioctl: discard: "
706 				    "pm_poll_cnt[%d] is %d before "
707 				    "ASSERT\n", clone,
708 				    pm_poll_cnt[clone]))
709 				ASSERT(pm_poll_cnt[clone]);
710 				pm_poll_cnt[clone]--;
711 			}
712 			kmem_free(p->physpath, p->size);
713 			p->size = 0;
714 			if (p == pscep->psce_last)
715 				p = pscep->psce_first;
716 			else
717 				p++;
718 		}
719 		pscep->psce_out = pscep->psce_first;
720 		pscep->psce_in = pscep->psce_first;
721 		mutex_exit(&pscep->psce_lock);
722 	}
723 }
724 
725 /*
726  * Discard entries for this clone. Calls pm_free_entries to free up memory.
727  */
728 static void
729 pm_discard_entries(int clone)
730 {
731 	psce_t	*pscep;
732 	psce_t			*pm_psc_clone_to_direct(int);
733 	psce_t			*pm_psc_clone_to_interest(int);
734 	int			direct = 0;
735 
736 	mutex_enter(&pm_clone_lock);
737 	if ((pscep = pm_psc_clone_to_direct(clone)) != NULL)
738 		direct = 1;
739 	pm_free_entries(pscep, clone, direct);
740 	pscep = pm_psc_clone_to_interest(clone);
741 	pm_free_entries(pscep, clone, 0);
742 	mutex_exit(&pm_clone_lock);
743 }
744 
745 
746 static void
747 pm_set_idle_threshold(dev_info_t *dip, int thresh, int flag)
748 {
749 	if (!PM_ISBC(dip) && !PM_ISDIRECT(dip)) {
750 		switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) {
751 		case PMC_DEF_THRESH:
752 		case PMC_CPU_THRESH:
753 			PMD(PMD_IOCTL, ("ioctl: set_idle_threshold: set "
754 			    "%s@%s(%s#%d) default thresh to 0t%d\n",
755 			    PM_DEVICE(dip), thresh))
756 			pm_set_device_threshold(dip, thresh, flag);
757 			break;
758 		default:
759 			break;
760 		}
761 	}
762 }
763 
764 static int
765 pm_set_idle_thresh_walk(dev_info_t *dip, void *arg)
766 {
767 	int cmd = *((int *)arg);
768 
769 	if (!PM_GET_PM_INFO(dip))
770 		return (DDI_WALK_CONTINUE);
771 
772 	switch (cmd) {
773 	case PM_SET_SYSTEM_THRESHOLD:
774 		if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH)
775 			break;
776 		pm_set_idle_threshold(dip, pm_system_idle_threshold,
777 		    PMC_DEF_THRESH);
778 		pm_rescan(dip);
779 		break;
780 	case PM_SET_CPU_THRESHOLD:
781 		if (!PM_ISCPU(dip))
782 			break;
783 		pm_set_idle_threshold(dip, pm_cpu_idle_threshold,
784 		    PMC_CPU_THRESH);
785 		pm_rescan(dip);
786 		break;
787 	}
788 
789 	return (DDI_WALK_CONTINUE);
790 }
791 
792 /*ARGSUSED*/
793 static int
794 pm_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
795 {
796 	dev_t	dev;
797 	int	instance;
798 
799 	switch (infocmd) {
800 	case DDI_INFO_DEVT2DEVINFO:
801 		if (pmstp->pm_instance == -1)
802 			return (DDI_FAILURE);
803 		*result = pmstp->pm_dip;
804 		return (DDI_SUCCESS);
805 
806 	case DDI_INFO_DEVT2INSTANCE:
807 		dev = (dev_t)arg;
808 		instance = getminor(dev) >> 8;
809 		*result = (void *)(uintptr_t)instance;
810 		return (DDI_SUCCESS);
811 
812 	default:
813 		return (DDI_FAILURE);
814 	}
815 }
816 
817 
818 /*ARGSUSED1*/
819 static int
820 pm_open(dev_t *devp, int flag, int otyp, cred_t *cr)
821 {
822 	int		clone;
823 
824 	if (otyp != OTYP_CHR)
825 		return (EINVAL);
826 
827 	mutex_enter(&pm_clone_lock);
828 	for (clone = 1; clone < PM_MAX_CLONE; clone++)
829 		if (!pmstp->pm_clones[clone])
830 			break;
831 
832 	if (clone == PM_MAX_CLONE) {
833 		mutex_exit(&pm_clone_lock);
834 		return (ENXIO);
835 	}
836 	pmstp->pm_cred[clone] = cr;
837 	crhold(cr);
838 
839 	*devp = makedevice(getmajor(*devp), (pmstp->pm_instance << 8) + clone);
840 	pmstp->pm_clones[clone] = 1;
841 	mutex_exit(&pm_clone_lock);
842 
843 	return (0);
844 }
845 
846 /*ARGSUSED1*/
847 static int
848 pm_close(dev_t dev, int flag, int otyp, cred_t *cr)
849 {
850 	int clone;
851 
852 	if (otyp != OTYP_CHR)
853 		return (EINVAL);
854 
855 	clone = PM_MINOR_TO_CLONE(getminor(dev));
856 	PMD(PMD_CLOSE, ("pm_close: minor %x, clone %x\n", getminor(dev),
857 	    clone))
858 
859 	/*
860 	 * Walk the entire device tree to find the corresponding
861 	 * device and operate on it.
862 	 */
863 	ddi_walk_devs(ddi_root_node(), pm_close_direct_pm_device,
864 	    (void *) &clone);
865 
866 	crfree(pmstp->pm_cred[clone]);
867 	pmstp->pm_cred[clone] = 0;
868 	pmstp->pm_clones[clone] = 0;
869 	pm_discard_entries(clone);
870 	ASSERT(pm_poll_cnt[clone] == 0);
871 	pm_deregister_watcher(clone, NULL);
872 	return (0);
873 }
874 
875 /*ARGSUSED*/
876 static int
877 pm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)
878 {
879 	struct pm_cmd_info *pc_info(int);
880 	struct pm_cmd_info *pcip = pc_info(cmd);
881 	pm_req_t	req;
882 	dev_info_t	*dip = NULL;
883 	pm_info_t	*info = NULL;
884 	int		clone;
885 	char		*cmdstr = pm_decode_cmd(cmd);
886 	/*
887 	 * To keep devinfo nodes from going away while we're holding a
888 	 * pointer to their dip, pm_name_to_dip() optionally holds
889 	 * the devinfo node.  If we've done that, we set dipheld
890 	 * so we know at the end of the ioctl processing to release the
891 	 * node again.
892 	 */
893 	int		dipheld = 0;
894 	int		icount = 0;
895 	int		i;
896 	int		comps;
897 	size_t		lencopied;
898 	int		ret = ENOTTY;
899 	int		curpower;
900 	char		who[MAXNAMELEN];
901 	size_t		wholen;			/* copyinstr length */
902 	size_t		deplen = MAXNAMELEN;
903 	char		*dep, i_dep_buf[MAXNAMELEN];
904 	char		*pathbuf;
905 	struct pm_component *cp;
906 #ifdef	_MULTI_DATAMODEL
907 	pm_state_change32_t		*pscp32;
908 	pm_state_change32_t		psc32;
909 	size_t				copysize32;
910 #endif
911 	pm_state_change_t		*pscp;
912 	pm_state_change_t		psc;
913 	size_t		copysize;
914 	extern void	pm_record_thresh(pm_thresh_rec_t *);
915 	psce_t		*pm_psc_clone_to_direct(int);
916 	psce_t		*pm_psc_clone_to_interest(int);
917 	extern	void	pm_register_watcher(int, dev_info_t *);
918 	extern	int	pm_get_current_power(dev_info_t *, int, int *);
919 	extern	int	pm_interest_registered(int);
920 	extern	void	pm_all_to_default_thresholds(void);
921 	extern	int	pm_current_threshold(dev_info_t *, int, int *);
922 	extern void	pm_deregister_watcher(int, dev_info_t *);
923 	extern void	pm_unrecord_threshold(char *);
924 
925 	PMD(PMD_IOCTL, ("ioctl: %s: begin\n", cmdstr))
926 
927 #ifdef DEBUG
928 	if (cmd == 666) {
929 		ddi_walk_devs(ddi_root_node(), print_info, NULL);
930 		return (0);
931 	}
932 	ret = 0x0badcafe;			/* sanity checking */
933 	pm_cmd = cmd;				/* for ASSERT debugging */
934 	pm_cmd_string = cmdstr;	/* for ASSERT debugging */
935 #endif
936 
937 
938 	if (pcip == NULL) {
939 		PMD(PMD_ERROR, ("ioctl: unknown command %d\n", cmd))
940 		return (ENOTTY);
941 	}
942 	if (pcip == NULL || pcip->supported == 0) {
943 		PMD(PMD_ERROR, ("ioctl: command %s no longer supported\n",
944 		    pcip->name))
945 		return (ENOTTY);
946 	}
947 
948 	wholen = 0;
949 	dep = i_dep_buf;
950 	i_dep_buf[0] = 0;
951 	clone = PM_MINOR_TO_CLONE(getminor(dev));
952 	if (!pm_perms(pcip->permission, pmstp->pm_cred[clone])) {
953 		ret = EPERM;
954 		return (ret);
955 	}
956 	switch (pcip->str_type) {
957 	case PM_REQ:
958 #ifdef	_MULTI_DATAMODEL
959 		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
960 			pm_req32_t	req32;
961 
962 			if (ddi_copyin((caddr_t)arg, &req32,
963 			    sizeof (req32), mode) != 0) {
964 				PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
965 				    "EFAULT\n\n", cmdstr))
966 				ret = EFAULT;
967 				break;
968 			}
969 			req.component = req32.component;
970 			req.value = req32.value;
971 			req.datasize = req32.datasize;
972 			if (pcip->inargs & INWHO) {
973 				ret = copyinstr((char *)(uintptr_t)
974 				    req32.physpath, who, MAXNAMELEN, &wholen);
975 				if (ret) {
976 					PMD(PMD_ERROR, ("ioctl: %s: "
977 					    "copyinstr fails returning %d\n",
978 					    cmdstr, ret))
979 					break;
980 				}
981 				req.physpath = who;
982 			}
983 			PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", cmdstr,
984 			    req.physpath))
985 			if (pcip->inargs & INDATA) {
986 				req.data = (void *)(uintptr_t)req32.data;
987 				req.datasize = req32.datasize;
988 			} else {
989 				req.data = NULL;
990 				req.datasize = 0;
991 			}
992 			switch (pcip->diptype) {
993 			case DIP:
994 				if (!(dip =
995 				    pm_name_to_dip(req.physpath, 1))) {
996 					PMD(PMD_ERROR, ("ioctl: %s: "
997 					    "pm_name_to_dip for %s failed\n",
998 					    cmdstr, req.physpath))
999 					return (ENODEV);
1000 				}
1001 				ASSERT(!dipheld);
1002 				dipheld++;
1003 				break;
1004 			case NODIP:
1005 				break;
1006 			default:
1007 				/*
1008 				 * Internal error, invalid ioctl description
1009 				 * force debug entry even if pm_debug not set
1010 				 */
1011 #ifdef	DEBUG
1012 				pm_log("invalid diptype %d for cmd %d (%s)\n",
1013 				    pcip->diptype, cmd, pcip->name);
1014 #endif
1015 				ASSERT(0);
1016 				return (EIO);
1017 			}
1018 			if (pcip->inargs & INDATAINT) {
1019 				int32_t int32buf;
1020 				int32_t *i32p;
1021 				int *ip;
1022 				icount = req32.datasize / sizeof (int32_t);
1023 				if (icount <= 0) {
1024 					PMD(PMD_ERROR, ("ioctl: %s: datasize"
1025 					    " 0 or neg EFAULT\n\n", cmdstr))
1026 					ret = EFAULT;
1027 					break;
1028 				}
1029 				ASSERT(!(pcip->inargs & INDATASTRING));
1030 				req.datasize = icount * sizeof (int);
1031 				req.data = kmem_alloc(req.datasize, KM_SLEEP);
1032 				ip = req.data;
1033 				ret = 0;
1034 				for (i = 0,
1035 				    i32p = (int32_t *)(uintptr_t)req32.data;
1036 				    i < icount; i++, i32p++) {
1037 					if (ddi_copyin((void *)i32p, &int32buf,
1038 					    sizeof (int32_t), mode)) {
1039 						kmem_free(req.data,
1040 						    req.datasize);
1041 						PMD(PMD_ERROR, ("ioctl: %s: "
1042 						    "entry %d EFAULT\n",
1043 						    cmdstr, i))
1044 						ret = EFAULT;
1045 						break;
1046 					}
1047 					*ip++ = (int)int32buf;
1048 				}
1049 				if (ret)
1050 					break;
1051 			}
1052 			if (pcip->inargs & INDATASTRING) {
1053 				ASSERT(!(pcip->inargs & INDATAINT));
1054 				ASSERT(pcip->deptype == DEP);
1055 				if (req32.data != NULL) {
1056 					size_t dummy;
1057 					if (copyinstr((void *)(uintptr_t)
1058 					    req32.data, dep, deplen, &dummy)) {
1059 						PMD(PMD_ERROR, ("ioctl: %s: "
1060 						    "0x%p dep size %lx, EFAULT"
1061 						    "\n", cmdstr,
1062 						    (void *)req.data, deplen))
1063 						ret = EFAULT;
1064 						break;
1065 					}
1066 #ifdef DEBUG
1067 					else {
1068 						PMD(PMD_DEP, ("ioctl: %s: "
1069 						    "dep %s\n", cmdstr, dep))
1070 					}
1071 #endif
1072 				} else {
1073 					PMD(PMD_ERROR, ("ioctl: %s: no "
1074 					    "dependent\n", cmdstr))
1075 					ret = EINVAL;
1076 					break;
1077 				}
1078 			}
1079 		} else
1080 #endif /* _MULTI_DATAMODEL */
1081 		{
1082 			if (ddi_copyin((caddr_t)arg,
1083 			    &req, sizeof (req), mode) != 0) {
1084 				PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
1085 				    "EFAULT\n\n", cmdstr))
1086 				ret = EFAULT;
1087 				break;
1088 			}
1089 			if (pcip->inargs & INWHO) {
1090 				ret = copyinstr((char *)req.physpath, who,
1091 				    MAXNAMELEN, &wholen);
1092 				if (ret) {
1093 					PMD(PMD_ERROR, ("ioctl: %s copyinstr"
1094 					    " fails returning %d\n", cmdstr,
1095 					    ret))
1096 					break;
1097 				}
1098 				req.physpath = who;
1099 			}
1100 			PMD(PMD_IOCTL, ("ioctl: %s: physpath=%s\n", cmdstr,
1101 			    req.physpath))
1102 			if (!(pcip->inargs & INDATA)) {
1103 				req.data = NULL;
1104 				req.datasize = 0;
1105 			}
1106 			switch (pcip->diptype) {
1107 			case DIP:
1108 				if (!(dip =
1109 				    pm_name_to_dip(req.physpath, 1))) {
1110 					PMD(PMD_ERROR, ("ioctl: %s: "
1111 					    "pm_name_to_dip for %s failed\n",
1112 					    cmdstr, req.physpath))
1113 					return (ENODEV);
1114 				}
1115 				ASSERT(!dipheld);
1116 				dipheld++;
1117 				break;
1118 			case NODIP:
1119 				break;
1120 			default:
1121 				/*
1122 				 * Internal error, invalid ioctl description
1123 				 * force debug entry even if pm_debug not set
1124 				 */
1125 #ifdef	DEBUG
1126 				pm_log("invalid diptype %d for cmd %d (%s)\n",
1127 				    pcip->diptype, cmd, pcip->name);
1128 #endif
1129 				ASSERT(0);
1130 				return (EIO);
1131 			}
1132 			if (pcip->inargs & INDATAINT) {
1133 				int *ip;
1134 
1135 				ASSERT(!(pcip->inargs & INDATASTRING));
1136 				ip = req.data;
1137 				icount = req.datasize / sizeof (int);
1138 				if (icount <= 0) {
1139 					PMD(PMD_ERROR, ("ioctl: %s: datasize"
1140 					    " 0 or neg EFAULT\n\n", cmdstr))
1141 					ret = EFAULT;
1142 					break;
1143 				}
1144 				req.data = kmem_alloc(req.datasize, KM_SLEEP);
1145 				if (ddi_copyin((caddr_t)ip, req.data,
1146 				    req.datasize, mode) != 0) {
1147 					PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
1148 					    "EFAULT\n\n", cmdstr))
1149 					ret = EFAULT;
1150 					break;
1151 				}
1152 			}
1153 			if (pcip->inargs & INDATASTRING) {
1154 				ASSERT(!(pcip->inargs & INDATAINT));
1155 				ASSERT(pcip->deptype == DEP);
1156 				if (req.data != NULL) {
1157 					size_t dummy;
1158 					if (copyinstr((caddr_t)req.data,
1159 					    dep, deplen, &dummy)) {
1160 						PMD(PMD_ERROR, ("ioctl: %s: "
1161 						    "0x%p dep size %lu, "
1162 						    "EFAULT\n", cmdstr,
1163 						    (void *)req.data, deplen))
1164 						ret = EFAULT;
1165 						break;
1166 					}
1167 #ifdef DEBUG
1168 					else {
1169 						PMD(PMD_DEP, ("ioctl: %s: "
1170 						    "dep %s\n", cmdstr, dep))
1171 					}
1172 #endif
1173 				} else {
1174 					PMD(PMD_ERROR, ("ioctl: %s: no "
1175 					    "dependent\n", cmdstr))
1176 					ret = EINVAL;
1177 					break;
1178 				}
1179 			}
1180 		}
1181 		/*
1182 		 * Now we've got all the args in for the commands that
1183 		 * use the new pm_req struct.
1184 		 */
1185 		switch (cmd) {
1186 		case PM_REPARSE_PM_PROPS:
1187 		{
1188 			struct dev_ops	*drv;
1189 			struct cb_ops	*cb;
1190 			void		*propval;
1191 			int length;
1192 			/*
1193 			 * This ioctl is provided only for the ddivs pm test.
1194 			 * We only do it to a driver which explicitly allows
1195 			 * us to do so by exporting a pm-reparse-ok property.
1196 			 * We only care whether the property exists or not.
1197 			 */
1198 			if ((drv = ddi_get_driver(dip)) == NULL) {
1199 				ret = EINVAL;
1200 				break;
1201 			}
1202 			if ((cb = drv->devo_cb_ops) != NULL) {
1203 				if ((*cb->cb_prop_op)(DDI_DEV_T_ANY, dip,
1204 				    PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP |
1205 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1206 				    "pm-reparse-ok", (caddr_t)&propval,
1207 				    &length) != DDI_SUCCESS) {
1208 					ret = EINVAL;
1209 					break;
1210 				}
1211 			} else if (ddi_prop_op(DDI_DEV_T_ANY, dip,
1212 			    PROP_LEN_AND_VAL_ALLOC, (DDI_PROP_CANSLEEP |
1213 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1214 			    "pm-reparse-ok", (caddr_t)&propval,
1215 			    &length) != DDI_SUCCESS) {
1216 				ret = EINVAL;
1217 				break;
1218 			}
1219 			kmem_free(propval, length);
1220 			ret =  e_new_pm_props(dip);
1221 			break;
1222 		}
1223 
1224 		case PM_GET_DEVICE_THRESHOLD:
1225 			PM_LOCK_DIP(dip);
1226 			if (!PM_GET_PM_INFO(dip) || PM_ISBC(dip)) {
1227 				PM_UNLOCK_DIP(dip);
1228 				PMD(PMD_ERROR, ("ioctl: %s: ENODEV\n",
1229 				    cmdstr))
1230 				ret = ENODEV;
1231 				break;
1232 			}
1233 			*rval_p = DEVI(dip)->devi_pm_dev_thresh;
1234 			PM_UNLOCK_DIP(dip);
1235 			ret = 0;
1236 			break;
1237 
1238 		case PM_DIRECT_PM:
1239 		{
1240 			int has_dep;
1241 			if ((info = PM_GET_PM_INFO(dip)) == NULL) {
1242 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1243 				    "ENODEV\n", cmdstr))
1244 				ret = ENODEV;
1245 				break;
1246 			}
1247 			/*
1248 			 * Check to see if we are there is a dependency on
1249 			 * this kept device, if so, return EBUSY.
1250 			 */
1251 			pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1252 			(void) ddi_pathname(dip, pathbuf);
1253 			pm_dispatch_to_dep_thread(PM_DEP_WK_CHECK_KEPT,
1254 			    NULL, pathbuf, PM_DEP_WAIT, &has_dep, 0);
1255 			kmem_free(pathbuf, MAXPATHLEN);
1256 			if (has_dep) {
1257 				PMD(PMD_ERROR | PMD_DPM, ("%s EBUSY\n",
1258 				    cmdstr))
1259 				ret = EBUSY;
1260 				break;
1261 			}
1262 			PM_LOCK_DIP(dip);
1263 			if (PM_ISDIRECT(dip) || (info->pmi_clone != 0)) {
1264 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1265 				    "%s@%s(%s#%d): EBUSY\n", cmdstr,
1266 				    PM_DEVICE(dip)))
1267 				PM_UNLOCK_DIP(dip);
1268 				ret = EBUSY;
1269 				break;
1270 			}
1271 			info->pmi_dev_pm_state |= PM_DIRECT;
1272 			info->pmi_clone = clone;
1273 			PM_UNLOCK_DIP(dip);
1274 			PMD(PMD_DPM, ("ioctl: %s: info %p, pmi_clone %d\n",
1275 			    cmdstr, (void *)info, clone))
1276 			mutex_enter(&pm_clone_lock);
1277 			pm_register_watcher(clone, dip);
1278 			mutex_exit(&pm_clone_lock);
1279 			ret = 0;
1280 			break;
1281 		}
1282 
1283 		case PM_RELEASE_DIRECT_PM:
1284 		{
1285 			if ((info = PM_GET_PM_INFO(dip)) == NULL) {
1286 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1287 				    "ENODEV\n", cmdstr))
1288 				ret = ENODEV;
1289 				break;
1290 			}
1291 			PM_LOCK_DIP(dip);
1292 			if (info->pmi_clone != clone) {
1293 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1294 				    "%s@%s(%s#%d) EINVAL\n", cmdstr,
1295 				    PM_DEVICE(dip)))
1296 				ret = EINVAL;
1297 				PM_UNLOCK_DIP(dip);
1298 				break;
1299 			}
1300 			ASSERT(PM_ISDIRECT(dip));
1301 			info->pmi_dev_pm_state &= ~PM_DIRECT;
1302 			PM_UNLOCK_DIP(dip);
1303 			/* Bring ourselves up if there is a keeper. */
1304 			pathbuf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1305 			(void) ddi_pathname(dip, pathbuf);
1306 			pm_dispatch_to_dep_thread(PM_DEP_WK_BRINGUP_SELF,
1307 			    NULL, pathbuf, PM_DEP_WAIT, NULL, 0);
1308 			kmem_free(pathbuf, MAXPATHLEN);
1309 			pm_discard_entries(clone);
1310 			pm_deregister_watcher(clone, dip);
1311 			/*
1312 			 * Now we could let the other threads that are
1313 			 * trying to do a DIRECT_PM thru
1314 			 */
1315 			PM_LOCK_DIP(dip);
1316 			info->pmi_clone = 0;
1317 			PM_UNLOCK_DIP(dip);
1318 			pm_proceed(dip, PMP_RELEASE, -1, -1);
1319 			PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n",
1320 			    cmdstr))
1321 			pm_rescan(dip);
1322 			ret = 0;
1323 			break;
1324 		}
1325 
1326 		case PM_SET_CURRENT_POWER:
1327 		{
1328 			int comp = req.component;
1329 			int  value = req.value;
1330 			PMD(PMD_DPM, ("ioctl: %s: %s component %d to value "
1331 			    "%d\n", cmdstr, req.physpath, comp, value))
1332 			if (!e_pm_valid_comp(dip, comp, NULL) ||
1333 			    !e_pm_valid_power(dip, comp, value)) {
1334 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1335 				    "physpath=%s, comp=%d, level=%d, fails\n",
1336 				    cmdstr, req.physpath, comp, value))
1337 				ret = EINVAL;
1338 				break;
1339 			}
1340 
1341 			if ((info = PM_GET_PM_INFO(dip)) == NULL) {
1342 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1343 				    "ENODEV\n", cmdstr))
1344 				ret = ENODEV;
1345 				break;
1346 			}
1347 			if (info->pmi_clone != clone) {
1348 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1349 				    "(not owner) %s fails; clone %d, owner %d"
1350 				    "\n", cmdstr, req.physpath, clone,
1351 				    info->pmi_clone))
1352 				ret = EINVAL;
1353 				break;
1354 			}
1355 			ASSERT(PM_ISDIRECT(dip));
1356 
1357 			if (pm_set_power(dip, comp, value, PM_LEVEL_EXACT,
1358 			    PM_CANBLOCK_BLOCK, 0, &ret) != DDI_SUCCESS) {
1359 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s: "
1360 				    "pm_set_power for %s fails, errno=%d\n",
1361 				    cmdstr, req.physpath, ret))
1362 				break;
1363 			}
1364 
1365 			pm_proceed(dip, PMP_SETPOWER, comp, value);
1366 
1367 			/*
1368 			 * Power down all idle components if console framebuffer
1369 			 * is powered off.
1370 			 */
1371 			if (PM_IS_CFB(dip) && (pm_system_idle_threshold ==
1372 			    pm_default_idle_threshold)) {
1373 				dev_info_t	*root = ddi_root_node();
1374 				if (PM_ISBC(dip)) {
1375 					if (comp == 0 && value == 0 &&
1376 					    (pm_timeout_idledown() != 0)) {
1377 						ddi_walk_devs(root,
1378 						    pm_start_idledown,
1379 						    (void *)PMID_CFB);
1380 					}
1381 				} else {
1382 					int count = 0;
1383 					for (i = 0; i < PM_NUMCMPTS(dip); i++) {
1384 						ret = pm_get_current_power(dip,
1385 						    i, &curpower);
1386 						if (ret == DDI_SUCCESS &&
1387 						    curpower == 0)
1388 							count++;
1389 					}
1390 					if ((count == PM_NUMCMPTS(dip)) &&
1391 					    (pm_timeout_idledown() != 0)) {
1392 						ddi_walk_devs(root,
1393 						    pm_start_idledown,
1394 						    (void *)PMID_CFB);
1395 					}
1396 				}
1397 			}
1398 
1399 			PMD(PMD_RESCAN | PMD_DPM, ("ioctl: %s: rescan\n",
1400 			    cmdstr))
1401 			pm_rescan(dip);
1402 			*rval_p = 0;
1403 			ret = 0;
1404 			break;
1405 		}
1406 
1407 		case PM_GET_FULL_POWER:
1408 		{
1409 			int normal;
1410 			ASSERT(dip);
1411 			PMD(PMD_NORM, ("ioctl: %s: %s component %d\n",
1412 			    cmdstr, req.physpath, req.component))
1413 			normal =  pm_get_normal_power(dip, req.component);
1414 
1415 			if (normal == DDI_FAILURE) {
1416 				PMD(PMD_ERROR | PMD_NORM, ("ioctl: %s: "
1417 				    "returns EINVAL\n", cmdstr))
1418 				ret = EINVAL;
1419 				break;
1420 			}
1421 			*rval_p = normal;
1422 			PMD(PMD_NORM, ("ioctl: %s: returns %d\n",
1423 			    cmdstr, normal))
1424 			ret = 0;
1425 			break;
1426 		}
1427 
1428 		case PM_GET_CURRENT_POWER:
1429 			if (pm_get_current_power(dip, req.component,
1430 			    rval_p) != DDI_SUCCESS) {
1431 				PMD(PMD_ERROR | PMD_DPM, ("ioctl: %s "
1432 				    "EINVAL\n", cmdstr))
1433 				ret = EINVAL;
1434 				break;
1435 			}
1436 			PMD(PMD_DPM, ("ioctl: %s: %s comp %d returns %d\n",
1437 			    cmdstr, req.physpath, req.component, *rval_p))
1438 			if (*rval_p == PM_LEVEL_UNKNOWN)
1439 				ret = EAGAIN;
1440 			else
1441 				ret = 0;
1442 			break;
1443 
1444 		case PM_GET_TIME_IDLE:
1445 		{
1446 			time_t timestamp;
1447 			int comp = req.component;
1448 			pm_component_t *cp;
1449 			if (!e_pm_valid_comp(dip, comp, &cp)) {
1450 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
1451 				    "component %d > numcmpts - 1 %d--EINVAL\n",
1452 				    cmdstr, PM_DEVICE(dip), comp,
1453 				    PM_NUMCMPTS(dip) - 1))
1454 				ret = EINVAL;
1455 				break;
1456 			}
1457 			timestamp = cp->pmc_timestamp;
1458 			if (timestamp) {
1459 				time_t now;
1460 				(void) drv_getparm(TIME, &now);
1461 				*rval_p = (now - timestamp);
1462 			} else {
1463 				*rval_p = 0;
1464 			}
1465 			ret = 0;
1466 			break;
1467 		}
1468 
1469 		case PM_ADD_DEPENDENT:
1470 		{
1471 			dev_info_t	*kept_dip;
1472 
1473 			PMD(PMD_KEEPS, ("%s, kept %s, keeper %s\n", cmdstr,
1474 			    dep, req.physpath))
1475 
1476 			/*
1477 			 * hold and install kept while processing dependency
1478 			 * keeper (in .physpath) has already been held.
1479 			 */
1480 			if (dep[0] == '\0') {
1481 				PMD(PMD_ERROR, ("kept NULL or null\n"))
1482 				ret = EINVAL;
1483 				break;
1484 			} else if ((kept_dip =
1485 			    pm_name_to_dip(dep, 1)) == NULL) {
1486 				PMD(PMD_ERROR, ("no dip for kept %s\n", dep))
1487 				ret = ENODEV;
1488 				break;
1489 			} else if (kept_dip == dip) {
1490 				PMD(PMD_ERROR, ("keeper(%s, %p) - kept(%s, %p) "
1491 				    "self-dependency not allowed.\n",
1492 				    dep, (void *)kept_dip, req.physpath,
1493 				    (void *) dip))
1494 				PM_RELE(dip);	/* release "double" hold */
1495 				ret = EINVAL;
1496 				break;
1497 			}
1498 			ASSERT(!(strcmp(req.physpath, (char *)dep) == 0));
1499 
1500 			/*
1501 			 * record dependency, then walk through device tree
1502 			 * independently on behalf of kept and keeper to
1503 			 * establish newly created dependency.
1504 			 */
1505 			pm_dispatch_to_dep_thread(PM_DEP_WK_RECORD_KEEPER,
1506 			    req.physpath, dep, PM_DEP_WAIT, NULL, 0);
1507 
1508 			/*
1509 			 * release kept after establishing dependency, keeper
1510 			 * is released as part of ioctl exit processing.
1511 			 */
1512 			PM_RELE(kept_dip);
1513 			*rval_p = 0;
1514 			ret = 0;
1515 			break;
1516 		}
1517 
1518 		case PM_ADD_DEPENDENT_PROPERTY:
1519 		{
1520 			char *keeper, *kept;
1521 
1522 			if (dep[0] == '\0') {
1523 				PMD(PMD_ERROR, ("ioctl: %s: dep NULL or "
1524 				    "null\n", cmdstr))
1525 				ret = EINVAL;
1526 				break;
1527 			}
1528 			kept = dep;
1529 			keeper = req.physpath;
1530 			/*
1531 			 * record keeper - kept dependency, then walk through
1532 			 * device tree to find out all attached keeper, walk
1533 			 * through again to apply dependency to all the
1534 			 * potential kept.
1535 			 */
1536 			pm_dispatch_to_dep_thread(
1537 			    PM_DEP_WK_RECORD_KEEPER_PROP, keeper, kept,
1538 			    PM_DEP_WAIT, NULL, 0);
1539 
1540 			*rval_p = 0;
1541 			ret = 0;
1542 			break;
1543 		}
1544 
1545 		case PM_SET_DEVICE_THRESHOLD:
1546 		{
1547 			pm_thresh_rec_t *rp;
1548 			pm_pte_t *ep;	/* threshold header storage */
1549 			int *tp;	/* threshold storage */
1550 			size_t size;
1551 			extern int pm_thresh_specd(dev_info_t *);
1552 
1553 			/*
1554 			 * The header struct plus one entry struct plus one
1555 			 * threshold plus the length of the string
1556 			 */
1557 			size = sizeof (pm_thresh_rec_t) +
1558 			    (sizeof (pm_pte_t) * 1) +
1559 			    (1 * sizeof (int)) +
1560 			    strlen(req.physpath) + 1;
1561 
1562 			rp = kmem_zalloc(size, KM_SLEEP);
1563 			rp->ptr_size = size;
1564 			rp->ptr_numcomps = 0;	/* means device threshold */
1565 			ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp));
1566 			rp->ptr_entries = ep;
1567 			tp = (int *)((intptr_t)ep +
1568 			    (1 * sizeof (pm_pte_t)));
1569 			ep->pte_numthresh = 1;
1570 			ep->pte_thresh = tp;
1571 			*tp++ = req.value;
1572 			(void) strcat((char *)tp, req.physpath);
1573 			rp->ptr_physpath = (char *)tp;
1574 			ASSERT((intptr_t)tp + strlen(req.physpath) + 1 ==
1575 			    (intptr_t)rp + rp->ptr_size);
1576 			PMD(PMD_THRESH, ("ioctl: %s: record thresh %d for "
1577 			    "%s\n", cmdstr, req.value, req.physpath))
1578 			pm_record_thresh(rp);
1579 			/*
1580 			 * Don't free rp, pm_record_thresh() keeps it.
1581 			 * We don't try to apply it ourselves because we'd need
1582 			 * to know too much about locking.  Since we don't
1583 			 * hold a lock the entry could be removed before
1584 			 * we get here
1585 			 */
1586 			ASSERT(dip == NULL);
1587 			ret = 0;		/* can't fail now */
1588 			if (!(dip = pm_name_to_dip(req.physpath, 1))) {
1589 				break;
1590 			}
1591 			(void) pm_thresh_specd(dip);
1592 			PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d)\n",
1593 			    cmdstr, PM_DEVICE(dip)))
1594 			PM_RELE(dip);
1595 			break;
1596 		}
1597 
1598 		case PM_RESET_DEVICE_THRESHOLD:
1599 		{
1600 			/*
1601 			 * This only applies to a currently attached and power
1602 			 * managed node
1603 			 */
1604 			/*
1605 			 * We don't do this to old-style drivers
1606 			 */
1607 			info = PM_GET_PM_INFO(dip);
1608 			if (info == NULL) {
1609 				PMD(PMD_ERROR, ("ioctl: %s: %s not power "
1610 				    "managed\n", cmdstr, req.physpath))
1611 				ret = EINVAL;
1612 				break;
1613 			}
1614 			if (PM_ISBC(dip)) {
1615 				PMD(PMD_ERROR, ("ioctl: %s: %s is BC\n",
1616 				    cmdstr, req.physpath))
1617 				ret = EINVAL;
1618 				break;
1619 			}
1620 			pm_unrecord_threshold(req.physpath);
1621 			if (DEVI(dip)->devi_pm_flags & PMC_CPU_THRESH)
1622 				pm_set_device_threshold(dip,
1623 				    pm_cpu_idle_threshold, PMC_CPU_THRESH);
1624 			else
1625 				pm_set_device_threshold(dip,
1626 				    pm_system_idle_threshold, PMC_DEF_THRESH);
1627 			ret = 0;
1628 			break;
1629 		}
1630 
1631 		case PM_GET_NUM_COMPONENTS:
1632 			ret = 0;
1633 			*rval_p = PM_NUMCMPTS(dip);
1634 			break;
1635 
1636 		case PM_GET_DEVICE_TYPE:
1637 			ret = 0;
1638 			if ((info = PM_GET_PM_INFO(dip)) == NULL) {
1639 				PMD(PMD_ERROR, ("ioctl: %s: "
1640 				    "PM_NO_PM_COMPONENTS\n", cmdstr))
1641 				*rval_p = PM_NO_PM_COMPONENTS;
1642 				break;
1643 			}
1644 			if (PM_ISBC(dip)) {
1645 				*rval_p = PM_CREATE_COMPONENTS;
1646 			} else {
1647 				*rval_p = PM_AUTOPM;
1648 			}
1649 			break;
1650 
1651 		case PM_SET_COMPONENT_THRESHOLDS:
1652 		{
1653 			int comps = 0;
1654 			int *end = (int *)req.data + icount;
1655 			pm_thresh_rec_t *rp;
1656 			pm_pte_t *ep;	/* threshold header storage */
1657 			int *tp;	/* threshold storage */
1658 			int *ip;
1659 			int j;
1660 			size_t size;
1661 			extern int pm_thresh_specd(dev_info_t *);
1662 			extern int pm_valid_thresh(dev_info_t *,
1663 			    pm_thresh_rec_t *);
1664 
1665 			for (ip = req.data; *ip; ip++) {
1666 				if (ip >= end) {
1667 					ret = EFAULT;
1668 					break;
1669 				}
1670 				comps++;
1671 				/* skip over indicated number of entries */
1672 				for (j = *ip; j; j--) {
1673 					if (++ip >= end) {
1674 						ret = EFAULT;
1675 						break;
1676 					}
1677 				}
1678 				if (ret)
1679 					break;
1680 			}
1681 			if (ret)
1682 				break;
1683 			if ((intptr_t)ip != (intptr_t)end - sizeof (int)) {
1684 				/* did not exactly fill buffer */
1685 				ret = EINVAL;
1686 				break;
1687 			}
1688 			if (comps == 0) {
1689 				PMD(PMD_ERROR, ("ioctl: %s: %s 0 components"
1690 				    "--EINVAL\n", cmdstr, req.physpath))
1691 				ret = EINVAL;
1692 				break;
1693 			}
1694 			/*
1695 			 * The header struct plus one entry struct per component
1696 			 * plus the size of the lists minus the counts
1697 			 * plus the length of the string
1698 			 */
1699 			size = sizeof (pm_thresh_rec_t) +
1700 			    (sizeof (pm_pte_t) * comps) + req.datasize -
1701 			    ((comps + 1) * sizeof (int)) +
1702 			    strlen(req.physpath) + 1;
1703 
1704 			rp = kmem_zalloc(size, KM_SLEEP);
1705 			rp->ptr_size = size;
1706 			rp->ptr_numcomps = comps;
1707 			ep = (pm_pte_t *)((intptr_t)rp + sizeof (*rp));
1708 			rp->ptr_entries = ep;
1709 			tp = (int *)((intptr_t)ep +
1710 			    (comps * sizeof (pm_pte_t)));
1711 			for (ip = req.data; *ip; ep++) {
1712 				ep->pte_numthresh = *ip;
1713 				ep->pte_thresh = tp;
1714 				for (j = *ip++; j; j--) {
1715 					*tp++ = *ip++;
1716 				}
1717 			}
1718 			(void) strcat((char *)tp, req.physpath);
1719 			rp->ptr_physpath = (char *)tp;
1720 			ASSERT((intptr_t)end == (intptr_t)ip + sizeof (int));
1721 			ASSERT((intptr_t)tp + strlen(req.physpath) + 1 ==
1722 			    (intptr_t)rp + rp->ptr_size);
1723 
1724 			ASSERT(dip == NULL);
1725 			/*
1726 			 * If this is not a currently power managed node,
1727 			 * then we can't check for validity of the thresholds
1728 			 */
1729 			if (!(dip = pm_name_to_dip(req.physpath, 1))) {
1730 				/* don't free rp, pm_record_thresh uses it */
1731 				pm_record_thresh(rp);
1732 				PMD(PMD_ERROR, ("ioctl: %s: pm_name_to_dip "
1733 				    "for %s failed\n", cmdstr, req.physpath))
1734 				ret = 0;
1735 				break;
1736 			}
1737 			ASSERT(!dipheld);
1738 			dipheld++;
1739 
1740 			if (!pm_valid_thresh(dip, rp)) {
1741 				PMD(PMD_ERROR, ("ioctl: %s: invalid thresh "
1742 				    "for %s@%s(%s#%d)\n", cmdstr,
1743 				    PM_DEVICE(dip)))
1744 				kmem_free(rp, size);
1745 				ret = EINVAL;
1746 				break;
1747 			}
1748 			/*
1749 			 * We don't just apply it ourselves because we'd need
1750 			 * to know too much about locking.  Since we don't
1751 			 * hold a lock the entry could be removed before
1752 			 * we get here
1753 			 */
1754 			pm_record_thresh(rp);
1755 			(void) pm_thresh_specd(dip);
1756 			ret = 0;
1757 			break;
1758 		}
1759 
1760 		case PM_GET_COMPONENT_THRESHOLDS:
1761 		{
1762 			int musthave;
1763 			int numthresholds = 0;
1764 			int wordsize;
1765 			int numcomps;
1766 			caddr_t uaddr = req.data;	/* user address */
1767 			int val;	/* int value to be copied out */
1768 			int32_t val32;	/* int32 value to be copied out */
1769 			caddr_t vaddr;	/* address to copyout from */
1770 			int j;
1771 
1772 #ifdef	_MULTI_DATAMODEL
1773 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
1774 				wordsize = sizeof (int32_t);
1775 			} else
1776 #endif /* _MULTI_DATAMODEL */
1777 			{
1778 				wordsize = sizeof (int);
1779 			}
1780 
1781 			ASSERT(dip);
1782 
1783 			numcomps = PM_NUMCMPTS(dip);
1784 			for (i = 0; i < numcomps; i++) {
1785 				cp = PM_CP(dip, i);
1786 				numthresholds += cp->pmc_comp.pmc_numlevels - 1;
1787 			}
1788 			musthave = (numthresholds + numcomps + 1) *  wordsize;
1789 			if (req.datasize < musthave) {
1790 				PMD(PMD_ERROR, ("ioctl: %s: size %ld, need "
1791 				    "%d--EINVAL\n", cmdstr, req.datasize,
1792 				    musthave))
1793 				ret = EINVAL;
1794 				break;
1795 			}
1796 			PM_LOCK_DIP(dip);
1797 			for (i = 0; i < numcomps; i++) {
1798 				int *thp;
1799 				cp = PM_CP(dip, i);
1800 				thp = cp->pmc_comp.pmc_thresh;
1801 				/* first copyout the count */
1802 				if (wordsize == sizeof (int32_t)) {
1803 					val32 = cp->pmc_comp.pmc_numlevels - 1;
1804 					vaddr = (caddr_t)&val32;
1805 				} else {
1806 					val = cp->pmc_comp.pmc_numlevels - 1;
1807 					vaddr = (caddr_t)&val;
1808 				}
1809 				if (ddi_copyout(vaddr, (void *)uaddr,
1810 				    wordsize, mode) != 0) {
1811 					PM_UNLOCK_DIP(dip);
1812 					PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
1813 					    "(%s#%d) vaddr %p EFAULT\n",
1814 					    cmdstr, PM_DEVICE(dip),
1815 					    (void*)vaddr))
1816 					ret = EFAULT;
1817 					break;
1818 				}
1819 				vaddr = uaddr;
1820 				vaddr += wordsize;
1821 				uaddr = (caddr_t)vaddr;
1822 				/* then copyout each threshold value */
1823 				for (j = 0; j < cp->pmc_comp.pmc_numlevels - 1;
1824 				    j++) {
1825 					if (wordsize == sizeof (int32_t)) {
1826 						val32 = thp[j + 1];
1827 						vaddr = (caddr_t)&val32;
1828 					} else {
1829 						val = thp[i + 1];
1830 						vaddr = (caddr_t)&val;
1831 					}
1832 					if (ddi_copyout(vaddr, (void *) uaddr,
1833 					    wordsize, mode) != 0) {
1834 						PM_UNLOCK_DIP(dip);
1835 						PMD(PMD_ERROR, ("ioctl: %s: "
1836 						    "%s@%s(%s#%d) uaddr %p "
1837 						    "EFAULT\n", cmdstr,
1838 						    PM_DEVICE(dip),
1839 						    (void *)uaddr))
1840 						ret = EFAULT;
1841 						break;
1842 					}
1843 					vaddr = uaddr;
1844 					vaddr += wordsize;
1845 					uaddr = (caddr_t)vaddr;
1846 				}
1847 			}
1848 			if (ret)
1849 				break;
1850 			/* last copyout a terminating 0 count */
1851 			if (wordsize == sizeof (int32_t)) {
1852 				val32 = 0;
1853 				vaddr = (caddr_t)&val32;
1854 			} else {
1855 				ASSERT(wordsize == sizeof (int));
1856 				val = 0;
1857 				vaddr = (caddr_t)&val;
1858 			}
1859 			if (ddi_copyout(vaddr, uaddr, wordsize, mode) != 0) {
1860 				PM_UNLOCK_DIP(dip);
1861 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
1862 				    "vaddr %p (0 count) EFAULT\n", cmdstr,
1863 				    PM_DEVICE(dip), (void *)vaddr))
1864 				ret = EFAULT;
1865 				break;
1866 			}
1867 			/* finished, so don't need to increment addresses */
1868 			PM_UNLOCK_DIP(dip);
1869 			ret = 0;
1870 			break;
1871 		}
1872 
1873 		case PM_GET_STATS:
1874 		{
1875 			time_t now;
1876 			time_t *timestamp;
1877 			extern int pm_cur_power(pm_component_t *cp);
1878 			int musthave;
1879 			int wordsize;
1880 
1881 #ifdef	_MULTI_DATAMODEL
1882 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
1883 				wordsize = sizeof (int32_t);
1884 			} else
1885 #endif /* _MULTI_DATAMODEL */
1886 			{
1887 				wordsize = sizeof (int);
1888 			}
1889 
1890 			comps = PM_NUMCMPTS(dip);
1891 			if (comps == 0 || PM_GET_PM_INFO(dip) == NULL) {
1892 				PMD(PMD_ERROR, ("ioctl: %s: %s no components"
1893 				    " or not power managed--EINVAL\n", cmdstr,
1894 				    req.physpath))
1895 				ret = EINVAL;
1896 				break;
1897 			}
1898 			musthave = comps * 2 * wordsize;
1899 			if (req.datasize < musthave) {
1900 				PMD(PMD_ERROR, ("ioctl: %s: size %lu, need "
1901 				    "%d--EINVAL\n", cmdstr, req.datasize,
1902 				    musthave))
1903 				ret = EINVAL;
1904 				break;
1905 			}
1906 
1907 			PM_LOCK_DIP(dip);
1908 			(void) drv_getparm(TIME, &now);
1909 			timestamp = kmem_zalloc(comps * sizeof (time_t),
1910 			    KM_SLEEP);
1911 			pm_get_timestamps(dip, timestamp);
1912 			/*
1913 			 * First the current power levels
1914 			 */
1915 			for (i = 0; i < comps; i++) {
1916 				int curpwr;
1917 				int32_t curpwr32;
1918 				caddr_t cpaddr;
1919 
1920 				cp = PM_CP(dip, i);
1921 				if (wordsize == sizeof (int)) {
1922 					curpwr = pm_cur_power(cp);
1923 					cpaddr = (caddr_t)&curpwr;
1924 				} else {
1925 					ASSERT(wordsize == sizeof (int32_t));
1926 					curpwr32 = pm_cur_power(cp);
1927 					cpaddr = (caddr_t)&curpwr32;
1928 				}
1929 				if (ddi_copyout(cpaddr, (void *) req.data,
1930 				    wordsize, mode) != 0) {
1931 					PM_UNLOCK_DIP(dip);
1932 					PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
1933 					    "(%s#%d) req.data %p EFAULT\n",
1934 					    cmdstr, PM_DEVICE(dip),
1935 					    (void *)req.data))
1936 					ASSERT(!dipheld);
1937 					return (EFAULT);
1938 				}
1939 				cpaddr = (caddr_t)req.data;
1940 				cpaddr += wordsize;
1941 				req.data = cpaddr;
1942 			}
1943 			/*
1944 			 * Then the times remaining
1945 			 */
1946 			for (i = 0; i < comps; i++) {
1947 				int retval;
1948 				int32_t retval32;
1949 				caddr_t rvaddr;
1950 				int curpwr;
1951 
1952 				cp = PM_CP(dip, i);
1953 				curpwr = cp->pmc_cur_pwr;
1954 				if (curpwr == 0 || timestamp[i] == 0) {
1955 					PMD(PMD_STATS, ("ioctl: %s: "
1956 					    "cur_pwer %x, timestamp %lx\n",
1957 					    cmdstr, curpwr, timestamp[i]))
1958 					retval = INT_MAX;
1959 				} else {
1960 					int thresh;
1961 					(void) pm_current_threshold(dip, i,
1962 					    &thresh);
1963 					retval = thresh - (now - timestamp[i]);
1964 					PMD(PMD_STATS, ("ioctl: %s: current "
1965 					    "thresh %x, now %lx, timestamp %lx,"
1966 					    " retval %x\n", cmdstr, thresh, now,
1967 					    timestamp[i], retval))
1968 				}
1969 				if (wordsize == sizeof (int)) {
1970 					rvaddr = (caddr_t)&retval;
1971 				} else {
1972 					ASSERT(wordsize == sizeof (int32_t));
1973 					retval32 = retval;
1974 					rvaddr = (caddr_t)&retval32;
1975 				}
1976 				if (ddi_copyout(rvaddr, (void *) req.data,
1977 				    wordsize, mode) != 0) {
1978 					PM_UNLOCK_DIP(dip);
1979 					PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
1980 					    "(%s#%d) req.data %p EFAULT\n",
1981 					    cmdstr, PM_DEVICE(dip),
1982 					    (void *)req.data))
1983 					ASSERT(!dipheld);
1984 					return (EFAULT);
1985 				}
1986 				rvaddr = (caddr_t)req.data;
1987 				rvaddr += wordsize;
1988 				req.data = (int *)rvaddr;
1989 			}
1990 			PM_UNLOCK_DIP(dip);
1991 			*rval_p = comps;
1992 			ret = 0;
1993 			kmem_free(timestamp, comps * sizeof (time_t));
1994 			break;
1995 		}
1996 
1997 		case PM_GET_COMPONENT_NAME:
1998 			ASSERT(dip);
1999 			if (!e_pm_valid_comp(dip, req.component, &cp)) {
2000 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2001 				    "component %d > numcmpts - 1 %d--EINVAL\n",
2002 				    cmdstr, PM_DEVICE(dip), req.component,
2003 				    PM_NUMCMPTS(dip) - 1))
2004 				ret = EINVAL;
2005 				break;
2006 			}
2007 			if (ret = copyoutstr(cp->pmc_comp.pmc_name,
2008 			    (char *)req.data, req.datasize, &lencopied)) {
2009 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2010 				    "copyoutstr %p failed--EFAULT\n", cmdstr,
2011 				    PM_DEVICE(dip), (void *)req.data))
2012 				break;
2013 			}
2014 			*rval_p = lencopied;
2015 			ret = 0;
2016 			break;
2017 
2018 		case PM_GET_POWER_NAME:
2019 		{
2020 			int i;
2021 
2022 			ASSERT(dip);
2023 			if (!e_pm_valid_comp(dip, req.component, &cp)) {
2024 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2025 				    "component %d > numcmpts - 1 %d--EINVAL\n",
2026 				    cmdstr, PM_DEVICE(dip), req.component,
2027 				    PM_NUMCMPTS(dip) - 1))
2028 				ret = EINVAL;
2029 				break;
2030 			}
2031 			if ((i = req.value) < 0 ||
2032 			    i > cp->pmc_comp.pmc_numlevels - 1) {
2033 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2034 				    "value %d > num_levels - 1 %d--EINVAL\n",
2035 				    cmdstr, PM_DEVICE(dip), req.value,
2036 				    cp->pmc_comp.pmc_numlevels - 1))
2037 				ret = EINVAL;
2038 				break;
2039 			}
2040 			dep = cp->pmc_comp.pmc_lnames[req.value];
2041 			if (ret = copyoutstr(dep,
2042 			    req.data, req.datasize, &lencopied)) {
2043 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2044 				    "copyoutstr %p failed--EFAULT\n", cmdstr,
2045 				    PM_DEVICE(dip), (void *)req.data))
2046 				break;
2047 			}
2048 			*rval_p = lencopied;
2049 			ret = 0;
2050 			break;
2051 		}
2052 
2053 		case PM_GET_POWER_LEVELS:
2054 		{
2055 			int musthave;
2056 			int numlevels;
2057 			int wordsize;
2058 
2059 #ifdef	_MULTI_DATAMODEL
2060 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2061 				wordsize = sizeof (int32_t);
2062 			} else
2063 #endif /* _MULTI_DATAMODEL */
2064 			{
2065 				wordsize = sizeof (int);
2066 			}
2067 			ASSERT(dip);
2068 
2069 			if (!e_pm_valid_comp(dip, req.component, &cp)) {
2070 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2071 				    "has %d components, component %d requested"
2072 				    "--EINVAL\n", cmdstr, PM_DEVICE(dip),
2073 				    PM_NUMCMPTS(dip), req.component))
2074 				ret = EINVAL;
2075 				break;
2076 			}
2077 			numlevels = cp->pmc_comp.pmc_numlevels;
2078 			musthave = numlevels *  wordsize;
2079 			if (req.datasize < musthave) {
2080 				PMD(PMD_ERROR, ("ioctl: %s: size %lu, need "
2081 				    "%d--EINVAL\n", cmdstr, req.datasize,
2082 				    musthave))
2083 				ret = EINVAL;
2084 				break;
2085 			}
2086 			PM_LOCK_DIP(dip);
2087 			for (i = 0; i < numlevels; i++) {
2088 				int level;
2089 				int32_t level32;
2090 				caddr_t laddr;
2091 
2092 				if (wordsize == sizeof (int)) {
2093 					level = cp->pmc_comp.pmc_lvals[i];
2094 					laddr = (caddr_t)&level;
2095 				} else {
2096 					level32 = cp->pmc_comp.pmc_lvals[i];
2097 					laddr = (caddr_t)&level32;
2098 				}
2099 				if (ddi_copyout(laddr, (void *) req.data,
2100 				    wordsize, mode) != 0) {
2101 					PM_UNLOCK_DIP(dip);
2102 					PMD(PMD_ERROR, ("ioctl: %s: %s@%s"
2103 					    "(%s#%d) laddr %p EFAULT\n",
2104 					    cmdstr, PM_DEVICE(dip),
2105 					    (void *)laddr))
2106 					ASSERT(!dipheld);
2107 					return (EFAULT);
2108 				}
2109 				laddr = (caddr_t)req.data;
2110 				laddr += wordsize;
2111 				req.data = (int *)laddr;
2112 			}
2113 			PM_UNLOCK_DIP(dip);
2114 			*rval_p = numlevels;
2115 			ret = 0;
2116 			break;
2117 		}
2118 
2119 
2120 		case PM_GET_NUM_POWER_LEVELS:
2121 			if (!e_pm_valid_comp(dip, req.component, &cp)) {
2122 				PMD(PMD_ERROR, ("ioctl: %s: %s@%s(%s#%d) "
2123 				    "component %d > numcmpts - 1 %d--EINVAL\n",
2124 				    cmdstr, PM_DEVICE(dip), req.component,
2125 				    PM_NUMCMPTS(dip) - 1))
2126 				ret = EINVAL;
2127 				break;
2128 			}
2129 			*rval_p = cp->pmc_comp.pmc_numlevels;
2130 			ret = 0;
2131 			break;
2132 
2133 		case PM_GET_DEVICE_THRESHOLD_BASIS:
2134 			ret = 0;
2135 			PM_LOCK_DIP(dip);
2136 			if ((info = PM_GET_PM_INFO(dip)) == NULL) {
2137 				PM_UNLOCK_DIP(dip);
2138 				PMD(PMD_ERROR, ("ioctl: %s: "
2139 				    "PM_NO_PM_COMPONENTS\n", cmdstr))
2140 				*rval_p = PM_NO_PM_COMPONENTS;
2141 				break;
2142 			}
2143 			if (PM_ISDIRECT(dip)) {
2144 				PM_UNLOCK_DIP(dip);
2145 				*rval_p = PM_DIRECTLY_MANAGED;
2146 				break;
2147 			}
2148 			switch (DEVI(dip)->devi_pm_flags & PMC_THRESH_ALL) {
2149 			case PMC_DEF_THRESH:
2150 			case PMC_NEXDEF_THRESH:
2151 				*rval_p = PM_DEFAULT_THRESHOLD;
2152 				break;
2153 			case PMC_DEV_THRESH:
2154 				*rval_p = PM_DEVICE_THRESHOLD;
2155 				break;
2156 			case PMC_COMP_THRESH:
2157 				*rval_p = PM_COMPONENT_THRESHOLD;
2158 				break;
2159 			case PMC_CPU_THRESH:
2160 				*rval_p = PM_CPU_THRESHOLD;
2161 				break;
2162 			default:
2163 				if (PM_ISBC(dip)) {
2164 					*rval_p = PM_OLD_THRESHOLD;
2165 					break;
2166 				}
2167 				PMD(PMD_ERROR, ("ioctl: %s: default, not "
2168 				    "BC--EINVAL", cmdstr))
2169 				ret = EINVAL;
2170 				break;
2171 			}
2172 			PM_UNLOCK_DIP(dip);
2173 			break;
2174 		}
2175 		break;
2176 
2177 	case PM_PSC:
2178 		/*
2179 		 * Commands that require pm_state_change_t as arg
2180 		 */
2181 #ifdef	_MULTI_DATAMODEL
2182 		if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2183 			pscp32 = (pm_state_change32_t *)arg;
2184 			if (ddi_copyin((caddr_t)arg, &psc32,
2185 			    sizeof (psc32), mode) != 0) {
2186 				PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
2187 				    "EFAULT\n\n", cmdstr))
2188 				ASSERT(!dipheld);
2189 				return (EFAULT);
2190 			}
2191 			psc.physpath = (caddr_t)(uintptr_t)psc32.physpath;
2192 			psc.size = psc32.size;
2193 		} else
2194 #endif /* _MULTI_DATAMODEL */
2195 		{
2196 			pscp = (pm_state_change_t *)arg;
2197 			if (ddi_copyin((caddr_t)arg, &psc,
2198 			    sizeof (psc), mode) != 0) {
2199 				PMD(PMD_ERROR, ("ioctl: %s: ddi_copyin "
2200 				    "EFAULT\n\n", cmdstr))
2201 				ASSERT(!dipheld);
2202 				return (EFAULT);
2203 			}
2204 		}
2205 		switch (cmd) {
2206 
2207 		case PM_GET_STATE_CHANGE:
2208 		case PM_GET_STATE_CHANGE_WAIT:
2209 		{
2210 			psce_t			*pscep;
2211 			pm_state_change_t	*p;
2212 			caddr_t			physpath;
2213 			size_t			physlen;
2214 
2215 			/*
2216 			 * We want to know if any device has changed state.
2217 			 * We look up by clone.  In case we have another thread
2218 			 * from the same process, we loop.
2219 			 * pm_psc_clone_to_interest() returns a locked entry.
2220 			 * We create an internal copy of the event entry prior
2221 			 * to copyout to user space because we don't want to
2222 			 * hold the psce_lock while doing copyout as we might
2223 			 * hit page fault  which eventually brings us back
2224 			 * here requesting the same lock.
2225 			 */
2226 			mutex_enter(&pm_clone_lock);
2227 			if (!pm_interest_registered(clone))
2228 				pm_register_watcher(clone, NULL);
2229 			while ((pscep =
2230 			    pm_psc_clone_to_interest(clone)) == NULL) {
2231 				if (cmd == PM_GET_STATE_CHANGE) {
2232 					PMD(PMD_IOCTL, ("ioctl: %s: "
2233 					    "EWOULDBLOCK\n", cmdstr))
2234 					mutex_exit(&pm_clone_lock);
2235 					ASSERT(!dipheld);
2236 					return (EWOULDBLOCK);
2237 				} else {
2238 					if (cv_wait_sig(&pm_clones_cv[clone],
2239 					    &pm_clone_lock) == 0) {
2240 						mutex_exit(&pm_clone_lock);
2241 						PMD(PMD_ERROR, ("ioctl: %s "
2242 						    "EINTR\n", cmdstr))
2243 						ASSERT(!dipheld);
2244 						return (EINTR);
2245 					}
2246 				}
2247 			}
2248 			mutex_exit(&pm_clone_lock);
2249 
2250 			physlen = pscep->psce_out->size;
2251 			physpath = NULL;
2252 			/*
2253 			 * If we were unable to store the path while bringing
2254 			 * up the console fb upon entering the prom, we give
2255 			 * a "" name with the overrun event set
2256 			 */
2257 			if (physlen == (size_t)-1) {	/* kmemalloc failed */
2258 				physpath = kmem_zalloc(1, KM_SLEEP);
2259 				physlen = 1;
2260 			}
2261 			if ((psc.physpath == NULL) || (psc.size < physlen)) {
2262 				PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n", cmdstr))
2263 				mutex_exit(&pscep->psce_lock);
2264 				ret = EFAULT;
2265 				break;
2266 			}
2267 			if (physpath == NULL) {
2268 				physpath = kmem_zalloc(physlen, KM_SLEEP);
2269 				bcopy((const void *) pscep->psce_out->physpath,
2270 				    (void *) physpath, physlen);
2271 			}
2272 
2273 			p = pscep->psce_out;
2274 #ifdef	_MULTI_DATAMODEL
2275 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2276 #ifdef DEBUG
2277 				size_t usrcopysize;
2278 #endif
2279 				psc32.flags = (ushort_t)p->flags;
2280 				psc32.event = (ushort_t)p->event;
2281 				psc32.timestamp = (int32_t)p->timestamp;
2282 				psc32.component = (int32_t)p->component;
2283 				psc32.old_level = (int32_t)p->old_level;
2284 				psc32.new_level = (int32_t)p->new_level;
2285 				copysize32 = ((intptr_t)&psc32.size -
2286 				    (intptr_t)&psc32.component);
2287 #ifdef DEBUG
2288 				usrcopysize = ((intptr_t)&pscp32->size -
2289 				    (intptr_t)&pscp32->component);
2290 				ASSERT(usrcopysize == copysize32);
2291 #endif
2292 			} else
2293 #endif /* _MULTI_DATAMODEL */
2294 			{
2295 				psc.flags = p->flags;
2296 				psc.event = p->event;
2297 				psc.timestamp = p->timestamp;
2298 				psc.component = p->component;
2299 				psc.old_level = p->old_level;
2300 				psc.new_level = p->new_level;
2301 				copysize = ((long)&p->size -
2302 				    (long)&p->component);
2303 			}
2304 			if (p->size != (size_t)-1)
2305 				kmem_free(p->physpath, p->size);
2306 			p->size = 0;
2307 			p->physpath = NULL;
2308 			if (pscep->psce_out == pscep->psce_last)
2309 				p = pscep->psce_first;
2310 			else
2311 				p++;
2312 			pscep->psce_out = p;
2313 			mutex_exit(&pscep->psce_lock);
2314 
2315 			ret = copyoutstr(physpath, psc.physpath,
2316 			    physlen, &lencopied);
2317 			kmem_free(physpath, physlen);
2318 			if (ret) {
2319 				PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p "
2320 				    "failed--EFAULT\n", cmdstr,
2321 				    (void *)psc.physpath))
2322 				break;
2323 			}
2324 
2325 #ifdef	_MULTI_DATAMODEL
2326 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2327 				if (ddi_copyout(&psc32.component,
2328 				    &pscp32->component, copysize32, mode)
2329 				    != 0) {
2330 					PMD(PMD_ERROR, ("ioctl: %s: copyout "
2331 					    "failed--EFAULT\n", cmdstr))
2332 					ret = EFAULT;
2333 					break;
2334 				}
2335 			} else
2336 #endif	/* _MULTI_DATAMODEL */
2337 			{
2338 				if (ddi_copyout(&psc.component,
2339 				    &pscp->component, copysize, mode) != 0) {
2340 					PMD(PMD_ERROR, ("ioctl: %s: copyout "
2341 					    "failed--EFAULT\n", cmdstr))
2342 					ret = EFAULT;
2343 					break;
2344 				}
2345 			}
2346 			ret = 0;
2347 			break;
2348 		}
2349 
2350 		case PM_DIRECT_NOTIFY:
2351 		case PM_DIRECT_NOTIFY_WAIT:
2352 		{
2353 			psce_t			*pscep;
2354 			pm_state_change_t	*p;
2355 			caddr_t			physpath;
2356 			size_t			physlen;
2357 			/*
2358 			 * We want to know if any direct device of ours has
2359 			 * something we should know about.  We look up by clone.
2360 			 * In case we have another thread from the same process,
2361 			 * we loop.
2362 			 * pm_psc_clone_to_direct() returns a locked entry.
2363 			 */
2364 			mutex_enter(&pm_clone_lock);
2365 			while (pm_poll_cnt[clone] == 0 ||
2366 			    (pscep = pm_psc_clone_to_direct(clone)) == NULL) {
2367 				if (cmd == PM_DIRECT_NOTIFY) {
2368 					PMD(PMD_IOCTL, ("ioctl: %s: "
2369 					    "EWOULDBLOCK\n", cmdstr))
2370 					mutex_exit(&pm_clone_lock);
2371 					ASSERT(!dipheld);
2372 					return (EWOULDBLOCK);
2373 				} else {
2374 					if (cv_wait_sig(&pm_clones_cv[clone],
2375 					    &pm_clone_lock) == 0) {
2376 						mutex_exit(&pm_clone_lock);
2377 						PMD(PMD_ERROR, ("ioctl: %s: "
2378 						    "EINTR\n", cmdstr))
2379 						ASSERT(!dipheld);
2380 						return (EINTR);
2381 					}
2382 				}
2383 			}
2384 			mutex_exit(&pm_clone_lock);
2385 			physlen = pscep->psce_out->size;
2386 			if ((psc.physpath == NULL) || (psc.size < physlen)) {
2387 				mutex_exit(&pscep->psce_lock);
2388 				PMD(PMD_ERROR, ("ioctl: %s: EFAULT\n",
2389 				    cmdstr))
2390 				ret = EFAULT;
2391 				break;
2392 			}
2393 			physpath = kmem_zalloc(physlen, KM_SLEEP);
2394 			bcopy((const void *) pscep->psce_out->physpath,
2395 			    (void *) physpath, physlen);
2396 
2397 			p = pscep->psce_out;
2398 #ifdef	_MULTI_DATAMODEL
2399 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2400 #ifdef DEBUG
2401 				size_t usrcopysize;
2402 #endif
2403 				psc32.component = (int32_t)p->component;
2404 				psc32.flags = (ushort_t)p->flags;
2405 				psc32.event = (ushort_t)p->event;
2406 				psc32.timestamp = (int32_t)p->timestamp;
2407 				psc32.old_level = (int32_t)p->old_level;
2408 				psc32.new_level = (int32_t)p->new_level;
2409 				copysize32 = (intptr_t)&psc32.size -
2410 				    (intptr_t)&psc32.component;
2411 				PMD(PMD_DPM, ("ioctl: %s: PDN32 %s, comp %d "
2412 				    "%d -> %d\n", cmdstr, physpath,
2413 				    p->component, p->old_level, p->new_level))
2414 #ifdef DEBUG
2415 				usrcopysize = (intptr_t)&pscp32->size -
2416 				    (intptr_t)&pscp32->component;
2417 				ASSERT(usrcopysize == copysize32);
2418 #endif
2419 			} else
2420 #endif
2421 			{
2422 				psc.component = p->component;
2423 				psc.flags = p->flags;
2424 				psc.event = p->event;
2425 				psc.timestamp = p->timestamp;
2426 				psc.old_level = p->old_level;
2427 				psc.new_level = p->new_level;
2428 				copysize = (intptr_t)&p->size -
2429 				    (intptr_t)&p->component;
2430 				PMD(PMD_DPM, ("ioctl: %s: PDN %s, comp %d "
2431 				    "%d -> %d\n", cmdstr, physpath,
2432 				    p->component, p->old_level, p->new_level))
2433 			}
2434 			mutex_enter(&pm_clone_lock);
2435 			PMD(PMD_IOCTL, ("ioctl: %s: pm_poll_cnt[%d] is %d "
2436 			    "before decrement\n", cmdstr, clone,
2437 			    pm_poll_cnt[clone]))
2438 			pm_poll_cnt[clone]--;
2439 			mutex_exit(&pm_clone_lock);
2440 			kmem_free(p->physpath, p->size);
2441 			p->size = 0;
2442 			p->physpath = NULL;
2443 			if (pscep->psce_out == pscep->psce_last)
2444 				p = pscep->psce_first;
2445 			else
2446 				p++;
2447 			pscep->psce_out = p;
2448 			mutex_exit(&pscep->psce_lock);
2449 
2450 			ret = copyoutstr(physpath, psc.physpath,
2451 			    physlen, &lencopied);
2452 			kmem_free(physpath, physlen);
2453 			if (ret) {
2454 				PMD(PMD_ERROR, ("ioctl: %s: copyoutstr %p "
2455 				    "failed--EFAULT\n", cmdstr,
2456 				    (void *)psc.physpath))
2457 				break;
2458 			}
2459 
2460 #ifdef	_MULTI_DATAMODEL
2461 			if ((mode & DATAMODEL_MASK) == DATAMODEL_ILP32) {
2462 				if (ddi_copyout(&psc32.component,
2463 				    &pscp32->component, copysize32, mode)
2464 					!= 0) {
2465 					PMD(PMD_ERROR, ("ioctl: %s: copyout "
2466 					    "failed--EFAULT\n", cmdstr))
2467 					ret = EFAULT;
2468 					break;
2469 				}
2470 			} else
2471 #endif	/* _MULTI_DATAMODEL */
2472 			{
2473 				if (ddi_copyout(&psc.component,
2474 				    &pscp->component, copysize, mode) != 0) {
2475 					PMD(PMD_ERROR, ("ioctl: %s: copyout "
2476 					    "failed--EFAULT\n", cmdstr))
2477 					ret = EFAULT;
2478 					break;
2479 				}
2480 			}
2481 			ret = 0;
2482 			break;
2483 		}
2484 		default:
2485 			ASSERT(0);
2486 		}
2487 		break;
2488 
2489 	case NOSTRUCT:
2490 		switch (cmd) {
2491 		case PM_START_PM:
2492 		case PM_START_CPUPM:
2493 			mutex_enter(&pm_scan_lock);
2494 			if ((cmd == PM_START_PM && autopm_enabled) ||
2495 			    (cmd == PM_START_CPUPM && PM_CPUPM_ENABLED)) {
2496 				mutex_exit(&pm_scan_lock);
2497 				PMD(PMD_ERROR, ("ioctl: %s: EBUSY\n",
2498 				    cmdstr))
2499 				ret = EBUSY;
2500 				break;
2501 			}
2502 			if (cmd == PM_START_PM)
2503 			    autopm_enabled = 1;
2504 			else
2505 			    cpupm = PM_CPUPM_ENABLE;
2506 			mutex_exit(&pm_scan_lock);
2507 			ddi_walk_devs(ddi_root_node(), pm_start_pm_walk, &cmd);
2508 			ret = 0;
2509 			break;
2510 
2511 		case PM_RESET_PM:
2512 		case PM_STOP_PM:
2513 		case PM_STOP_CPUPM:
2514 		{
2515 			extern void pm_discard_thresholds(void);
2516 
2517 			mutex_enter(&pm_scan_lock);
2518 			if ((cmd == PM_STOP_PM && !autopm_enabled) ||
2519 			    (cmd == PM_STOP_CPUPM && PM_CPUPM_DISABLED)) {
2520 				mutex_exit(&pm_scan_lock);
2521 				PMD(PMD_ERROR, ("ioctl: %s: EINVAL\n",
2522 				    cmdstr))
2523 				ret = EINVAL;
2524 				break;
2525 			}
2526 			if (cmd == PM_STOP_PM)
2527 			    autopm_enabled = 0;
2528 			else if (cmd == PM_STOP_CPUPM)
2529 			    cpupm = PM_CPUPM_DISABLE;
2530 			else {
2531 			    autopm_enabled = 0;
2532 			    cpupm = PM_CPUPM_NOTSET;
2533 			}
2534 			mutex_exit(&pm_scan_lock);
2535 
2536 			/*
2537 			 * bring devices to full power level, stop scan
2538 			 */
2539 			ddi_walk_devs(ddi_root_node(), pm_stop_pm_walk, &cmd);
2540 			ret = 0;
2541 			if (cmd == PM_STOP_PM || cmd == PM_STOP_CPUPM)
2542 				break;
2543 			/*
2544 			 * Now do only PM_RESET_PM stuff.
2545 			 */
2546 			pm_system_idle_threshold = pm_default_idle_threshold;
2547 			pm_cpu_idle_threshold = 0;
2548 			pm_discard_thresholds();
2549 			pm_all_to_default_thresholds();
2550 			pm_dispatch_to_dep_thread(PM_DEP_WK_REMOVE_DEP,
2551 			    NULL, NULL, PM_DEP_WAIT, NULL, 0);
2552 			break;
2553 		}
2554 
2555 		case PM_GET_SYSTEM_THRESHOLD:
2556 			*rval_p = pm_system_idle_threshold;
2557 			ret = 0;
2558 			break;
2559 
2560 		case PM_GET_DEFAULT_SYSTEM_THRESHOLD:
2561 			*rval_p = pm_default_idle_threshold;
2562 			ret = 0;
2563 			break;
2564 
2565 		case PM_GET_CPU_THRESHOLD:
2566 			*rval_p = pm_cpu_idle_threshold;
2567 			ret = 0;
2568 			break;
2569 
2570 		case PM_SET_SYSTEM_THRESHOLD:
2571 		case PM_SET_CPU_THRESHOLD:
2572 			if ((int)arg < 0) {
2573 				PMD(PMD_ERROR, ("ioctl: %s: arg 0x%x < 0"
2574 				    "--EINVAL\n", cmdstr, (int)arg))
2575 				ret = EINVAL;
2576 				break;
2577 			}
2578 			PMD(PMD_IOCTL, ("ioctl: %s: 0x%x 0t%d\n", cmdstr,
2579 			    (int)arg, (int)arg))
2580 			if (cmd == PM_SET_SYSTEM_THRESHOLD)
2581 				pm_system_idle_threshold = (int)arg;
2582 			else {
2583 				pm_cpu_idle_threshold = (int)arg;
2584 			}
2585 			ddi_walk_devs(ddi_root_node(), pm_set_idle_thresh_walk,
2586 				    (void *) &cmd);
2587 
2588 			ret = 0;
2589 			break;
2590 
2591 		case PM_IDLE_DOWN:
2592 			if (pm_timeout_idledown() != 0) {
2593 				ddi_walk_devs(ddi_root_node(),
2594 				    pm_start_idledown, (void *)PMID_IOC);
2595 			}
2596 			ret = 0;
2597 			break;
2598 
2599 		case PM_GET_PM_STATE:
2600 			if (autopm_enabled) {
2601 				*rval_p = PM_SYSTEM_PM_ENABLED;
2602 			} else {
2603 				*rval_p = PM_SYSTEM_PM_DISABLED;
2604 			}
2605 			ret = 0;
2606 			break;
2607 
2608 		case PM_GET_CPUPM_STATE:
2609 			if (PM_CPUPM_ENABLED)
2610 				*rval_p = PM_CPU_PM_ENABLED;
2611 			else if (PM_CPUPM_DISABLED)
2612 				*rval_p = PM_CPU_PM_DISABLED;
2613 			else
2614 				*rval_p = PM_CPU_PM_NOTSET;
2615 			ret = 0;
2616 			break;
2617 		}
2618 		break;
2619 
2620 	default:
2621 		/*
2622 		 * Internal error, invalid ioctl description
2623 		 * force debug entry even if pm_debug not set
2624 		 */
2625 #ifdef	DEBUG
2626 		pm_log("ioctl: invalid str_type %d for cmd %d (%s)\n",
2627 		    pcip->str_type, cmd, pcip->name);
2628 #endif
2629 		ASSERT(0);
2630 		return (EIO);
2631 	}
2632 	ASSERT(ret != 0x0badcafe);	/* some cmd in wrong case! */
2633 	if (dipheld) {
2634 		ASSERT(dip);
2635 		PMD(PMD_DHR, ("ioctl: %s: releasing %s@%s(%s#%d) for "
2636 		    "exiting pm_ioctl\n", cmdstr, PM_DEVICE(dip)))
2637 		PM_RELE(dip);
2638 	}
2639 	PMD(PMD_IOCTL, ("ioctl: %s: end, ret=%d\n", cmdstr, ret))
2640 	return (ret);
2641 }
2642