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