xref: /titanic_52/usr/src/uts/common/io/srn.c (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
1*2df1fe9cSrandyf /*
2*2df1fe9cSrandyf  * CDDL HEADER START
3*2df1fe9cSrandyf  *
4*2df1fe9cSrandyf  * The contents of this file are subject to the terms of the
5*2df1fe9cSrandyf  * Common Development and Distribution License (the "License").
6*2df1fe9cSrandyf  * You may not use this file except in compliance with the License.
7*2df1fe9cSrandyf  *
8*2df1fe9cSrandyf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2df1fe9cSrandyf  * or http://www.opensolaris.org/os/licensing.
10*2df1fe9cSrandyf  * See the License for the specific language governing permissions
11*2df1fe9cSrandyf  * and limitations under the License.
12*2df1fe9cSrandyf  *
13*2df1fe9cSrandyf  * When distributing Covered Code, include this CDDL HEADER in each
14*2df1fe9cSrandyf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2df1fe9cSrandyf  * If applicable, add the following below this CDDL HEADER, with the
16*2df1fe9cSrandyf  * fields enclosed by brackets "[]" replaced with your own identifying
17*2df1fe9cSrandyf  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2df1fe9cSrandyf  *
19*2df1fe9cSrandyf  * CDDL HEADER END
20*2df1fe9cSrandyf  */
21*2df1fe9cSrandyf 
22*2df1fe9cSrandyf /*
23*2df1fe9cSrandyf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*2df1fe9cSrandyf  * Use is subject to license terms.
25*2df1fe9cSrandyf  */
26*2df1fe9cSrandyf 
27*2df1fe9cSrandyf #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2df1fe9cSrandyf 
29*2df1fe9cSrandyf /*
30*2df1fe9cSrandyf  * srn	Provide apm-like interfaces to Xorg
31*2df1fe9cSrandyf  */
32*2df1fe9cSrandyf 
33*2df1fe9cSrandyf #include <sys/types.h>
34*2df1fe9cSrandyf #include <sys/errno.h>
35*2df1fe9cSrandyf #include <sys/modctl.h>
36*2df1fe9cSrandyf #include <sys/conf.h>		/* driver flags and functions */
37*2df1fe9cSrandyf #include <sys/open.h>		/* OTYP_CHR definition */
38*2df1fe9cSrandyf #include <sys/stat.h>		/* S_IFCHR definition */
39*2df1fe9cSrandyf #include <sys/pathname.h>	/* name -> dev_info xlation */
40*2df1fe9cSrandyf #include <sys/kmem.h>		/* memory alloc stuff */
41*2df1fe9cSrandyf #include <sys/debug.h>
42*2df1fe9cSrandyf #include <sys/pm.h>
43*2df1fe9cSrandyf #include <sys/ddi.h>
44*2df1fe9cSrandyf #include <sys/sunddi.h>
45*2df1fe9cSrandyf #include <sys/epm.h>
46*2df1fe9cSrandyf #include <sys/vfs.h>
47*2df1fe9cSrandyf #include <sys/mode.h>
48*2df1fe9cSrandyf #include <sys/mkdev.h>
49*2df1fe9cSrandyf #include <sys/promif.h>
50*2df1fe9cSrandyf #include <sys/consdev.h>
51*2df1fe9cSrandyf #include <sys/ddi_impldefs.h>
52*2df1fe9cSrandyf #include <sys/poll.h>
53*2df1fe9cSrandyf #include <sys/note.h>
54*2df1fe9cSrandyf #include <sys/taskq.h>
55*2df1fe9cSrandyf #include <sys/policy.h>
56*2df1fe9cSrandyf #include <sys/srn.h>
57*2df1fe9cSrandyf 
58*2df1fe9cSrandyf /*
59*2df1fe9cSrandyf  * Minor number is instance<<8 + clone minor from range 1-255;
60*2df1fe9cSrandyf  * But only one will be allocated
61*2df1fe9cSrandyf  */
62*2df1fe9cSrandyf #define	SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1))
63*2df1fe9cSrandyf #define	SU		0x002
64*2df1fe9cSrandyf #define	SG		0x004
65*2df1fe9cSrandyf 
66*2df1fe9cSrandyf extern kmutex_t	srn_clone_lock;	/* protects srn_clones array */
67*2df1fe9cSrandyf extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE];
68*2df1fe9cSrandyf extern uint_t	srn_poll_cnt[SRN_MAX_CLONE];
69*2df1fe9cSrandyf 
70*2df1fe9cSrandyf /*
71*2df1fe9cSrandyf  * The soft state of the srn driver.  Since there will only be
72*2df1fe9cSrandyf  * one of these, just reference it through a static struct.
73*2df1fe9cSrandyf  */
74*2df1fe9cSrandyf static struct srnstate {
75*2df1fe9cSrandyf 	dev_info_t	*srn_dip;		/* ptr to our dev_info node */
76*2df1fe9cSrandyf 	int		srn_instance;		/* for ddi_get_instance() */
77*2df1fe9cSrandyf 	uchar_t		srn_clones[SRN_MAX_CLONE]; /* unique opens	*/
78*2df1fe9cSrandyf 	struct cred	*srn_cred[SRN_MAX_CLONE]; /* cred for each open	*/
79*2df1fe9cSrandyf 	int		srn_type[SRN_MAX_CLONE]; /* type of handshake */
80*2df1fe9cSrandyf 	int		srn_delivered[SRN_MAX_CLONE];
81*2df1fe9cSrandyf 	srn_event_info_t srn_pending[SRN_MAX_CLONE];
82*2df1fe9cSrandyf } srn = { NULL, -1};
83*2df1fe9cSrandyf typedef struct srnstate *srn_state_t;
84*2df1fe9cSrandyf 
85*2df1fe9cSrandyf kcondvar_t	srn_clones_cv[SRN_MAX_CLONE];
86*2df1fe9cSrandyf uint_t		srn_poll_cnt[SRN_MAX_CLONE];	/* count of events for poll */
87*2df1fe9cSrandyf int		srn_apm_count;
88*2df1fe9cSrandyf int		srn_autosx_count;
89*2df1fe9cSrandyf struct pollhead	srn_pollhead[SRN_MAX_CLONE];
90*2df1fe9cSrandyf 
91*2df1fe9cSrandyf static int	srn_open(dev_t *, int, int, cred_t *);
92*2df1fe9cSrandyf static int	srn_close(dev_t, int, int, cred_t *);
93*2df1fe9cSrandyf static int	srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
94*2df1fe9cSrandyf static int	srn_chpoll(dev_t, short, int, short *, struct pollhead **);
95*2df1fe9cSrandyf 
96*2df1fe9cSrandyf static struct cb_ops srn_cb_ops = {
97*2df1fe9cSrandyf 	srn_open,	/* open */
98*2df1fe9cSrandyf 	srn_close,	/* close */
99*2df1fe9cSrandyf 	nodev,		/* strategy */
100*2df1fe9cSrandyf 	nodev,		/* print */
101*2df1fe9cSrandyf 	nodev,		/* dump */
102*2df1fe9cSrandyf 	nodev,		/* read */
103*2df1fe9cSrandyf 	nodev,		/* write */
104*2df1fe9cSrandyf 	srn_ioctl,	/* ioctl */
105*2df1fe9cSrandyf 	nodev,		/* devmap */
106*2df1fe9cSrandyf 	nodev,		/* mmap */
107*2df1fe9cSrandyf 	nodev,		/* segmap */
108*2df1fe9cSrandyf 	srn_chpoll,	/* poll */
109*2df1fe9cSrandyf 	ddi_prop_op,	/* prop_op */
110*2df1fe9cSrandyf 	NULL,		/* streamtab */
111*2df1fe9cSrandyf 	D_NEW | D_MP	/* driver compatibility flag */
112*2df1fe9cSrandyf };
113*2df1fe9cSrandyf 
114*2df1fe9cSrandyf static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
115*2df1fe9cSrandyf     void **result);
116*2df1fe9cSrandyf static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
117*2df1fe9cSrandyf static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
118*2df1fe9cSrandyf static void srn_notify(int type, int event);
119*2df1fe9cSrandyf 
120*2df1fe9cSrandyf static struct dev_ops srn_ops = {
121*2df1fe9cSrandyf 	DEVO_REV,		/* devo_rev */
122*2df1fe9cSrandyf 	0,			/* refcnt */
123*2df1fe9cSrandyf 	srn_getinfo,		/* info */
124*2df1fe9cSrandyf 	nulldev,		/* identify */
125*2df1fe9cSrandyf 	nulldev,		/* probe */
126*2df1fe9cSrandyf 	srn_attach,		/* attach */
127*2df1fe9cSrandyf 	srn_detach,		/* detach */
128*2df1fe9cSrandyf 	nodev,			/* reset */
129*2df1fe9cSrandyf 	&srn_cb_ops,		/* driver operations */
130*2df1fe9cSrandyf 	NULL,			/* bus operations */
131*2df1fe9cSrandyf 	NULL			/* power */
132*2df1fe9cSrandyf };
133*2df1fe9cSrandyf 
134*2df1fe9cSrandyf static struct modldrv modldrv = {
135*2df1fe9cSrandyf 	&mod_driverops,
136*2df1fe9cSrandyf 	"srn driver v1.4",
137*2df1fe9cSrandyf 	&srn_ops
138*2df1fe9cSrandyf };
139*2df1fe9cSrandyf 
140*2df1fe9cSrandyf static struct modlinkage modlinkage = {
141*2df1fe9cSrandyf 	MODREV_1, &modldrv, 0
142*2df1fe9cSrandyf };
143*2df1fe9cSrandyf 
144*2df1fe9cSrandyf /* Local functions */
145*2df1fe9cSrandyf 
146*2df1fe9cSrandyf int
147*2df1fe9cSrandyf _init(void)
148*2df1fe9cSrandyf {
149*2df1fe9cSrandyf 	return (mod_install(&modlinkage));
150*2df1fe9cSrandyf }
151*2df1fe9cSrandyf 
152*2df1fe9cSrandyf int
153*2df1fe9cSrandyf _fini(void)
154*2df1fe9cSrandyf {
155*2df1fe9cSrandyf 	return (mod_remove(&modlinkage));
156*2df1fe9cSrandyf }
157*2df1fe9cSrandyf 
158*2df1fe9cSrandyf int
159*2df1fe9cSrandyf _info(struct modinfo *modinfop)
160*2df1fe9cSrandyf {
161*2df1fe9cSrandyf 	return (mod_info(&modlinkage, modinfop));
162*2df1fe9cSrandyf }
163*2df1fe9cSrandyf 
164*2df1fe9cSrandyf static int
165*2df1fe9cSrandyf srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
166*2df1fe9cSrandyf {
167*2df1fe9cSrandyf 	int		i;
168*2df1fe9cSrandyf 	extern void (*srn_signal)(int, int);
169*2df1fe9cSrandyf 
170*2df1fe9cSrandyf 	switch (cmd) {
171*2df1fe9cSrandyf 
172*2df1fe9cSrandyf 	case DDI_ATTACH:
173*2df1fe9cSrandyf 		if (srn.srn_instance != -1)	/* Only allow one instance */
174*2df1fe9cSrandyf 			return (DDI_FAILURE);
175*2df1fe9cSrandyf 		srn.srn_instance = ddi_get_instance(dip);
176*2df1fe9cSrandyf 		if (ddi_create_minor_node(dip, "srn", S_IFCHR,
177*2df1fe9cSrandyf 		    (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0)
178*2df1fe9cSrandyf 		    != DDI_SUCCESS) {
179*2df1fe9cSrandyf 			return (DDI_FAILURE);
180*2df1fe9cSrandyf 		}
181*2df1fe9cSrandyf 		srn.srn_dip = dip;	/* srn_init and getinfo depend on it */
182*2df1fe9cSrandyf 
183*2df1fe9cSrandyf 		for (i = 0; i < SRN_MAX_CLONE; i++)
184*2df1fe9cSrandyf 			cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL);
185*2df1fe9cSrandyf 
186*2df1fe9cSrandyf 		srn.srn_instance = ddi_get_instance(dip);
187*2df1fe9cSrandyf 		mutex_enter(&srn_clone_lock);
188*2df1fe9cSrandyf 		srn_signal = srn_notify;
189*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
190*2df1fe9cSrandyf 		ddi_report_dev(dip);
191*2df1fe9cSrandyf 		return (DDI_SUCCESS);
192*2df1fe9cSrandyf 
193*2df1fe9cSrandyf 	default:
194*2df1fe9cSrandyf 		return (DDI_FAILURE);
195*2df1fe9cSrandyf 	}
196*2df1fe9cSrandyf }
197*2df1fe9cSrandyf 
198*2df1fe9cSrandyf /* ARGSUSED */
199*2df1fe9cSrandyf static int
200*2df1fe9cSrandyf srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
201*2df1fe9cSrandyf {
202*2df1fe9cSrandyf 	int i;
203*2df1fe9cSrandyf 	extern int srn_inuse;
204*2df1fe9cSrandyf 	extern void (*srn_signal)(int, int);
205*2df1fe9cSrandyf 
206*2df1fe9cSrandyf 	switch (cmd) {
207*2df1fe9cSrandyf 	case DDI_DETACH:
208*2df1fe9cSrandyf 
209*2df1fe9cSrandyf 		mutex_enter(&srn_clone_lock);
210*2df1fe9cSrandyf 		while (srn_inuse) {
211*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
212*2df1fe9cSrandyf 			delay(1);
213*2df1fe9cSrandyf 			mutex_enter(&srn_clone_lock);
214*2df1fe9cSrandyf 		}
215*2df1fe9cSrandyf 		srn_signal = NULL;
216*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
217*2df1fe9cSrandyf 
218*2df1fe9cSrandyf 		for (i = 0; i < SRN_MAX_CLONE; i++)
219*2df1fe9cSrandyf 			cv_destroy(&srn_clones_cv[i]);
220*2df1fe9cSrandyf 
221*2df1fe9cSrandyf 		ddi_remove_minor_node(dip, NULL);
222*2df1fe9cSrandyf 		srn.srn_instance = -1;
223*2df1fe9cSrandyf 		return (DDI_SUCCESS);
224*2df1fe9cSrandyf 
225*2df1fe9cSrandyf 	default:
226*2df1fe9cSrandyf 		return (DDI_FAILURE);
227*2df1fe9cSrandyf 	}
228*2df1fe9cSrandyf }
229*2df1fe9cSrandyf 
230*2df1fe9cSrandyf 
231*2df1fe9cSrandyf #ifdef DEBUG
232*2df1fe9cSrandyf char *srn_cmd_string;
233*2df1fe9cSrandyf int srn_cmd;
234*2df1fe9cSrandyf #endif
235*2df1fe9cSrandyf 
236*2df1fe9cSrandyf /*
237*2df1fe9cSrandyf  * Returns true if permission granted by credentials
238*2df1fe9cSrandyf  * XXX
239*2df1fe9cSrandyf  */
240*2df1fe9cSrandyf static int
241*2df1fe9cSrandyf srn_perms(int perm, cred_t *cr)
242*2df1fe9cSrandyf {
243*2df1fe9cSrandyf 	if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */
244*2df1fe9cSrandyf 		return (1);
245*2df1fe9cSrandyf 	if ((perm & SG) && (crgetgid(cr) == 0))	/* group 0 is ok */
246*2df1fe9cSrandyf 		return (1);
247*2df1fe9cSrandyf 	return (0);
248*2df1fe9cSrandyf }
249*2df1fe9cSrandyf 
250*2df1fe9cSrandyf static int
251*2df1fe9cSrandyf srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
252*2df1fe9cSrandyf 	struct pollhead **phpp)
253*2df1fe9cSrandyf {
254*2df1fe9cSrandyf 	extern struct pollhead srn_pollhead[];	/* common/os/sunpm.c */
255*2df1fe9cSrandyf 	int	clone;
256*2df1fe9cSrandyf 
257*2df1fe9cSrandyf 	clone = SRN_MINOR_TO_CLONE(getminor(dev));
258*2df1fe9cSrandyf 	if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) {
259*2df1fe9cSrandyf 		*reventsp |= (POLLIN | POLLRDNORM);
260*2df1fe9cSrandyf 	} else {
261*2df1fe9cSrandyf 		*reventsp = 0;
262*2df1fe9cSrandyf 		if (!anyyet) {
263*2df1fe9cSrandyf 			*phpp = &srn_pollhead[clone];
264*2df1fe9cSrandyf 		}
265*2df1fe9cSrandyf 	}
266*2df1fe9cSrandyf 	return (0);
267*2df1fe9cSrandyf }
268*2df1fe9cSrandyf 
269*2df1fe9cSrandyf /*ARGSUSED*/
270*2df1fe9cSrandyf static int
271*2df1fe9cSrandyf srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
272*2df1fe9cSrandyf {
273*2df1fe9cSrandyf 	dev_t	dev;
274*2df1fe9cSrandyf 	int	instance;
275*2df1fe9cSrandyf 
276*2df1fe9cSrandyf 	switch (infocmd) {
277*2df1fe9cSrandyf 	case DDI_INFO_DEVT2DEVINFO:
278*2df1fe9cSrandyf 		if (srn.srn_instance == -1)
279*2df1fe9cSrandyf 			return (DDI_FAILURE);
280*2df1fe9cSrandyf 		*result = srn.srn_dip;
281*2df1fe9cSrandyf 		return (DDI_SUCCESS);
282*2df1fe9cSrandyf 
283*2df1fe9cSrandyf 	case DDI_INFO_DEVT2INSTANCE:
284*2df1fe9cSrandyf 		dev = (dev_t)arg;
285*2df1fe9cSrandyf 		instance = getminor(dev) >> 8;
286*2df1fe9cSrandyf 		*result = (void *)(uintptr_t)instance;
287*2df1fe9cSrandyf 		return (DDI_SUCCESS);
288*2df1fe9cSrandyf 
289*2df1fe9cSrandyf 	default:
290*2df1fe9cSrandyf 		return (DDI_FAILURE);
291*2df1fe9cSrandyf 	}
292*2df1fe9cSrandyf }
293*2df1fe9cSrandyf 
294*2df1fe9cSrandyf 
295*2df1fe9cSrandyf /*ARGSUSED1*/
296*2df1fe9cSrandyf static int
297*2df1fe9cSrandyf srn_open(dev_t *devp, int flag, int otyp, cred_t *cr)
298*2df1fe9cSrandyf {
299*2df1fe9cSrandyf 	int		clone;
300*2df1fe9cSrandyf 
301*2df1fe9cSrandyf 	if (otyp != OTYP_CHR)
302*2df1fe9cSrandyf 		return (EINVAL);
303*2df1fe9cSrandyf 
304*2df1fe9cSrandyf 	mutex_enter(&srn_clone_lock);
305*2df1fe9cSrandyf 	for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++)
306*2df1fe9cSrandyf 		if (!srn.srn_clones[clone])
307*2df1fe9cSrandyf 			break;
308*2df1fe9cSrandyf 
309*2df1fe9cSrandyf 	if (clone == SRN_MAX_CLONE) {
310*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
311*2df1fe9cSrandyf 		return (ENXIO);
312*2df1fe9cSrandyf 	}
313*2df1fe9cSrandyf 	srn.srn_cred[clone] = cr;
314*2df1fe9cSrandyf 	ASSERT(srn_apm_count >= 0);
315*2df1fe9cSrandyf 	srn_apm_count++;
316*2df1fe9cSrandyf 	srn.srn_type[clone] = SRN_TYPE_APM;
317*2df1fe9cSrandyf 	crhold(cr);
318*2df1fe9cSrandyf 
319*2df1fe9cSrandyf 	*devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) +
320*2df1fe9cSrandyf 	    clone);
321*2df1fe9cSrandyf 	srn.srn_clones[clone] = 1;
322*2df1fe9cSrandyf 	srn.srn_cred[clone] = cr;
323*2df1fe9cSrandyf 	crhold(cr);
324*2df1fe9cSrandyf 	mutex_exit(&srn_clone_lock);
325*2df1fe9cSrandyf 	PMD(PMD_SX, ("srn open OK\n"))
326*2df1fe9cSrandyf 	return (0);
327*2df1fe9cSrandyf }
328*2df1fe9cSrandyf 
329*2df1fe9cSrandyf /*ARGSUSED1*/
330*2df1fe9cSrandyf static int
331*2df1fe9cSrandyf srn_close(dev_t dev, int flag, int otyp, cred_t *cr)
332*2df1fe9cSrandyf {
333*2df1fe9cSrandyf 	int clone;
334*2df1fe9cSrandyf 
335*2df1fe9cSrandyf 	if (otyp != OTYP_CHR)
336*2df1fe9cSrandyf 		return (EINVAL);
337*2df1fe9cSrandyf 
338*2df1fe9cSrandyf 	clone = SRN_MINOR_TO_CLONE(getminor(dev));
339*2df1fe9cSrandyf 	PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev),
340*2df1fe9cSrandyf 	    clone))
341*2df1fe9cSrandyf 	mutex_enter(&srn_clone_lock);
342*2df1fe9cSrandyf 	crfree(srn.srn_cred[clone]);
343*2df1fe9cSrandyf 	srn.srn_cred[clone] = 0;
344*2df1fe9cSrandyf 	srn_poll_cnt[clone] = 0;
345*2df1fe9cSrandyf 	if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) {
346*2df1fe9cSrandyf 		srn.srn_pending[clone].ae_type = 0;
347*2df1fe9cSrandyf 		srn.srn_delivered[clone] = 0;
348*2df1fe9cSrandyf 		cv_signal(&srn_clones_cv[clone]);
349*2df1fe9cSrandyf 	}
350*2df1fe9cSrandyf 	switch (srn.srn_type[clone]) {
351*2df1fe9cSrandyf 	case SRN_TYPE_AUTOSX:
352*2df1fe9cSrandyf 		ASSERT(srn_autosx_count);
353*2df1fe9cSrandyf 		srn_autosx_count--;
354*2df1fe9cSrandyf 		break;
355*2df1fe9cSrandyf 	case SRN_TYPE_APM:
356*2df1fe9cSrandyf 		ASSERT(srn_apm_count);
357*2df1fe9cSrandyf 		srn_apm_count--;
358*2df1fe9cSrandyf 		break;
359*2df1fe9cSrandyf 	default:
360*2df1fe9cSrandyf 		ASSERT(0);
361*2df1fe9cSrandyf 		return (EINVAL);
362*2df1fe9cSrandyf 	}
363*2df1fe9cSrandyf 	srn.srn_clones[clone] = 0;
364*2df1fe9cSrandyf 	mutex_exit(&srn_clone_lock);
365*2df1fe9cSrandyf 	return (0);
366*2df1fe9cSrandyf }
367*2df1fe9cSrandyf 
368*2df1fe9cSrandyf /*ARGSUSED*/
369*2df1fe9cSrandyf static int
370*2df1fe9cSrandyf srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)
371*2df1fe9cSrandyf {
372*2df1fe9cSrandyf 	int clone = SRN_MINOR_TO_CLONE(getminor(dev));
373*2df1fe9cSrandyf 
374*2df1fe9cSrandyf 	PMD(PMD_SX, ("ioctl: %x: begin\n", cmd))
375*2df1fe9cSrandyf 
376*2df1fe9cSrandyf 	switch (cmd) {
377*2df1fe9cSrandyf 	case SRN_IOC_NEXTEVENT:
378*2df1fe9cSrandyf 	case SRN_IOC_SUSPEND:
379*2df1fe9cSrandyf 	case SRN_IOC_RESUME:
380*2df1fe9cSrandyf 	case SRN_IOC_AUTOSX:
381*2df1fe9cSrandyf 		break;
382*2df1fe9cSrandyf 	default:
383*2df1fe9cSrandyf 		return (ENOTTY);
384*2df1fe9cSrandyf 	}
385*2df1fe9cSrandyf 
386*2df1fe9cSrandyf 	if (!srn_perms(SU | SG, srn.srn_cred[clone])) {
387*2df1fe9cSrandyf 		return (EPERM);
388*2df1fe9cSrandyf 	}
389*2df1fe9cSrandyf 	switch (cmd) {
390*2df1fe9cSrandyf 	case SRN_IOC_AUTOSX:
391*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n"))
392*2df1fe9cSrandyf 		mutex_enter(&srn_clone_lock);
393*2df1fe9cSrandyf 		if (!srn.srn_clones[clone]) {
394*2df1fe9cSrandyf 			PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n"))
395*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
396*2df1fe9cSrandyf 			return (EINVAL);
397*2df1fe9cSrandyf 		}
398*2df1fe9cSrandyf 		if (srn.srn_pending[clone].ae_type) {
399*2df1fe9cSrandyf 			PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n"))
400*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
401*2df1fe9cSrandyf 			return (EBUSY);
402*2df1fe9cSrandyf 		}
403*2df1fe9cSrandyf 		if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) {
404*2df1fe9cSrandyf 			PMD(PMD_SX, ("AUTOSX already--EBUSY\n"))
405*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
406*2df1fe9cSrandyf 			return (EBUSY);
407*2df1fe9cSrandyf 		}
408*2df1fe9cSrandyf 		ASSERT(srn.srn_type[clone] == SRN_TYPE_APM);
409*2df1fe9cSrandyf 		srn.srn_type[clone] = SRN_TYPE_AUTOSX;
410*2df1fe9cSrandyf 		srn_apm_count--;
411*2df1fe9cSrandyf 		ASSERT(srn_apm_count >= 0);
412*2df1fe9cSrandyf 		ASSERT(srn_autosx_count >= 0);
413*2df1fe9cSrandyf 		srn_autosx_count++;
414*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
415*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n"))
416*2df1fe9cSrandyf 		return (0);
417*2df1fe9cSrandyf 
418*2df1fe9cSrandyf 	case SRN_IOC_NEXTEVENT:
419*2df1fe9cSrandyf 		/*
420*2df1fe9cSrandyf 		 * return the next suspend or resume event;  there should
421*2df1fe9cSrandyf 		 * be one, cause we only get called if we've signalled a
422*2df1fe9cSrandyf 		 * poll data completion
423*2df1fe9cSrandyf 		 * then wake up the kernel thread sleeping for the delivery
424*2df1fe9cSrandyf 		 */
425*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n"))
426*2df1fe9cSrandyf 		mutex_enter(&srn_clone_lock);
427*2df1fe9cSrandyf 		if (srn_poll_cnt[clone] == 0) {
428*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
429*2df1fe9cSrandyf 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d "
430*2df1fe9cSrandyf 			    "EWOULDBLOCK\n", clone))
431*2df1fe9cSrandyf 			return (EWOULDBLOCK);
432*2df1fe9cSrandyf 		}
433*2df1fe9cSrandyf 		ASSERT(srn.srn_pending[clone].ae_type);
434*2df1fe9cSrandyf 		if (ddi_copyout(&srn.srn_pending[clone], (void *)arg,
435*2df1fe9cSrandyf 		    sizeof (srn_event_info_t), mode) != 0) {
436*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
437*2df1fe9cSrandyf 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n",
438*2df1fe9cSrandyf 			    clone))
439*2df1fe9cSrandyf 			return (EFAULT);
440*2df1fe9cSrandyf 		}
441*2df1fe9cSrandyf 		if (srn.srn_type[clone] == SRN_TYPE_APM)
442*2df1fe9cSrandyf 			srn.srn_delivered[clone] =
443*2df1fe9cSrandyf 			    srn.srn_pending[clone].ae_type;
444*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n",
445*2df1fe9cSrandyf 		    clone, srn.srn_pending[clone].ae_type))
446*2df1fe9cSrandyf 		srn_poll_cnt[clone] = 0;
447*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
448*2df1fe9cSrandyf 		return (0);
449*2df1fe9cSrandyf 
450*2df1fe9cSrandyf 	case SRN_IOC_SUSPEND:
451*2df1fe9cSrandyf 		/* ack suspend */
452*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone))
453*2df1fe9cSrandyf 		mutex_enter(&srn_clone_lock);
454*2df1fe9cSrandyf 		if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) {
455*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
456*2df1fe9cSrandyf 			PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n"))
457*2df1fe9cSrandyf 			return (EINVAL);
458*2df1fe9cSrandyf 		}
459*2df1fe9cSrandyf 		srn.srn_delivered[clone] = 0;
460*2df1fe9cSrandyf 		srn.srn_pending[clone].ae_type = 0;
461*2df1fe9cSrandyf 		/* notify the kernel suspend thread  to continue */
462*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone))
463*2df1fe9cSrandyf 		cv_signal(&srn_clones_cv[clone]);
464*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
465*2df1fe9cSrandyf 		return (0);
466*2df1fe9cSrandyf 
467*2df1fe9cSrandyf 	case SRN_IOC_RESUME:
468*2df1fe9cSrandyf 		/* ack resume */
469*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone))
470*2df1fe9cSrandyf 		mutex_enter(&srn_clone_lock);
471*2df1fe9cSrandyf 		if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) {
472*2df1fe9cSrandyf 			mutex_exit(&srn_clone_lock);
473*2df1fe9cSrandyf 			PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n"))
474*2df1fe9cSrandyf 			return (EINVAL);
475*2df1fe9cSrandyf 		}
476*2df1fe9cSrandyf 		srn.srn_delivered[clone] = 0;
477*2df1fe9cSrandyf 		srn.srn_pending[clone].ae_type = 0;
478*2df1fe9cSrandyf 		/* notify the kernel resume thread  to continue */
479*2df1fe9cSrandyf 		PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone))
480*2df1fe9cSrandyf 		cv_signal(&srn_clones_cv[clone]);
481*2df1fe9cSrandyf 		mutex_exit(&srn_clone_lock);
482*2df1fe9cSrandyf 		return (0);
483*2df1fe9cSrandyf 
484*2df1fe9cSrandyf 	default:
485*2df1fe9cSrandyf 		PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n"))
486*2df1fe9cSrandyf 		return (EINVAL);
487*2df1fe9cSrandyf 	}
488*2df1fe9cSrandyf }
489*2df1fe9cSrandyf /*
490*2df1fe9cSrandyf  * A very simple handshake with the srn driver,
491*2df1fe9cSrandyf  * only one outstanding event at a time.
492*2df1fe9cSrandyf  * The OS delivers the event and depending on type,
493*2df1fe9cSrandyf  * either blocks waiting for the ack, or drives on
494*2df1fe9cSrandyf  */
495*2df1fe9cSrandyf void
496*2df1fe9cSrandyf srn_notify(int type, int event)
497*2df1fe9cSrandyf {
498*2df1fe9cSrandyf 	int clone, count;
499*2df1fe9cSrandyf 	PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n",
500*2df1fe9cSrandyf 	    type, event));
501*2df1fe9cSrandyf 	ASSERT(mutex_owned(&srn_clone_lock));
502*2df1fe9cSrandyf 	switch (type) {
503*2df1fe9cSrandyf 	case SRN_TYPE_APM:
504*2df1fe9cSrandyf 		if (srn_apm_count == 0) {
505*2df1fe9cSrandyf 			PMD(PMD_SX, ("no apm types\n"))
506*2df1fe9cSrandyf 			return;
507*2df1fe9cSrandyf 		}
508*2df1fe9cSrandyf 		count = srn_apm_count;
509*2df1fe9cSrandyf 		break;
510*2df1fe9cSrandyf 	case SRN_TYPE_AUTOSX:
511*2df1fe9cSrandyf 		if (srn_autosx_count == 0) {
512*2df1fe9cSrandyf 			PMD(PMD_SX, ("no autosx types\n"))
513*2df1fe9cSrandyf 			return;
514*2df1fe9cSrandyf 		}
515*2df1fe9cSrandyf 		count = srn_autosx_count;
516*2df1fe9cSrandyf 		break;
517*2df1fe9cSrandyf 	default:
518*2df1fe9cSrandyf 		ASSERT(0);
519*2df1fe9cSrandyf 		break;
520*2df1fe9cSrandyf 	}
521*2df1fe9cSrandyf 	ASSERT(count > 0);
522*2df1fe9cSrandyf 	PMD(PMD_SX, ("count %d\n", count))
523*2df1fe9cSrandyf 	for (clone = 0; clone < SRN_MAX_CLONE; clone++) {
524*2df1fe9cSrandyf 		if (srn.srn_type[clone] == type) {
525*2df1fe9cSrandyf 			if (type == SRN_TYPE_APM) {
526*2df1fe9cSrandyf 				ASSERT(srn.srn_pending[clone].ae_type == 0);
527*2df1fe9cSrandyf 				ASSERT(srn_poll_cnt[clone] == 0);
528*2df1fe9cSrandyf 				ASSERT(srn.srn_delivered[clone] == 0);
529*2df1fe9cSrandyf 			}
530*2df1fe9cSrandyf 			srn.srn_pending[clone].ae_type = event;
531*2df1fe9cSrandyf 			srn_poll_cnt[clone] = 1;
532*2df1fe9cSrandyf 			PMD(PMD_SX, ("pollwake %d\n", clone))
533*2df1fe9cSrandyf 			pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN));
534*2df1fe9cSrandyf 			count--;
535*2df1fe9cSrandyf 			if (count == 0)
536*2df1fe9cSrandyf 				break;
537*2df1fe9cSrandyf 		}
538*2df1fe9cSrandyf 	}
539*2df1fe9cSrandyf 	if (type == SRN_TYPE_AUTOSX) {		/* we don't wait */
540*2df1fe9cSrandyf 		PMD(PMD_SX, ("Not waiting for AUTOSX ack\n"))
541*2df1fe9cSrandyf 		return;
542*2df1fe9cSrandyf 	}
543*2df1fe9cSrandyf 	ASSERT(type == SRN_TYPE_APM);
544*2df1fe9cSrandyf 	/* otherwise wait for acks */
545*2df1fe9cSrandyf restart:
546*2df1fe9cSrandyf 	/*
547*2df1fe9cSrandyf 	 * We wait untill all of the pending events are cleared.
548*2df1fe9cSrandyf 	 * We have to start over every time we do a cv_wait because
549*2df1fe9cSrandyf 	 * we give up the mutex and can be re-entered
550*2df1fe9cSrandyf 	 */
551*2df1fe9cSrandyf 	for (clone = 1; clone < SRN_MAX_CLONE; clone++) {
552*2df1fe9cSrandyf 		if (srn.srn_clones[clone] == 0 ||
553*2df1fe9cSrandyf 		    srn.srn_type[clone] != SRN_TYPE_APM)
554*2df1fe9cSrandyf 			continue;
555*2df1fe9cSrandyf 		if (srn.srn_pending[clone].ae_type) {
556*2df1fe9cSrandyf 			PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, "
557*2df1fe9cSrandyf 			    "event %x\n", clone, event))
558*2df1fe9cSrandyf 			cv_wait(&srn_clones_cv[clone], &srn_clone_lock);
559*2df1fe9cSrandyf 			goto restart;
560*2df1fe9cSrandyf 		}
561*2df1fe9cSrandyf 	}
562*2df1fe9cSrandyf 	PMD(PMD_SX, ("srn_notify done with %x\n", event))
563*2df1fe9cSrandyf }
564