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