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