xref: /onnv-gate/usr/src/uts/common/io/srn.c (revision 7656:2621e50fdf4a)
15295Srandyf /*
25295Srandyf  * CDDL HEADER START
35295Srandyf  *
45295Srandyf  * The contents of this file are subject to the terms of the
55295Srandyf  * Common Development and Distribution License (the "License").
65295Srandyf  * You may not use this file except in compliance with the License.
75295Srandyf  *
85295Srandyf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95295Srandyf  * or http://www.opensolaris.org/os/licensing.
105295Srandyf  * See the License for the specific language governing permissions
115295Srandyf  * and limitations under the License.
125295Srandyf  *
135295Srandyf  * When distributing Covered Code, include this CDDL HEADER in each
145295Srandyf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155295Srandyf  * If applicable, add the following below this CDDL HEADER, with the
165295Srandyf  * fields enclosed by brackets "[]" replaced with your own identifying
175295Srandyf  * information: Portions Copyright [yyyy] [name of copyright owner]
185295Srandyf  *
195295Srandyf  * CDDL HEADER END
205295Srandyf  */
215295Srandyf 
225295Srandyf /*
23*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245295Srandyf  * Use is subject to license terms.
255295Srandyf  */
265295Srandyf 
275295Srandyf 
285295Srandyf /*
295295Srandyf  * srn	Provide apm-like interfaces to Xorg
305295Srandyf  */
315295Srandyf 
325295Srandyf #include <sys/types.h>
335295Srandyf #include <sys/errno.h>
345295Srandyf #include <sys/modctl.h>
355295Srandyf #include <sys/conf.h>		/* driver flags and functions */
365295Srandyf #include <sys/open.h>		/* OTYP_CHR definition */
375295Srandyf #include <sys/stat.h>		/* S_IFCHR definition */
385295Srandyf #include <sys/pathname.h>	/* name -> dev_info xlation */
395295Srandyf #include <sys/kmem.h>		/* memory alloc stuff */
405295Srandyf #include <sys/debug.h>
415295Srandyf #include <sys/pm.h>
425295Srandyf #include <sys/ddi.h>
435295Srandyf #include <sys/sunddi.h>
445295Srandyf #include <sys/epm.h>
455295Srandyf #include <sys/vfs.h>
465295Srandyf #include <sys/mode.h>
475295Srandyf #include <sys/mkdev.h>
485295Srandyf #include <sys/promif.h>
495295Srandyf #include <sys/consdev.h>
505295Srandyf #include <sys/ddi_impldefs.h>
515295Srandyf #include <sys/poll.h>
525295Srandyf #include <sys/note.h>
535295Srandyf #include <sys/taskq.h>
545295Srandyf #include <sys/policy.h>
555295Srandyf #include <sys/srn.h>
565295Srandyf 
575295Srandyf /*
585295Srandyf  * Minor number is instance<<8 + clone minor from range 1-255;
595295Srandyf  * But only one will be allocated
605295Srandyf  */
615295Srandyf #define	SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1))
625295Srandyf #define	SU		0x002
635295Srandyf #define	SG		0x004
645295Srandyf 
655295Srandyf extern kmutex_t	srn_clone_lock;	/* protects srn_clones array */
665295Srandyf extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE];
675295Srandyf extern uint_t	srn_poll_cnt[SRN_MAX_CLONE];
685295Srandyf 
695295Srandyf /*
705295Srandyf  * The soft state of the srn driver.  Since there will only be
715295Srandyf  * one of these, just reference it through a static struct.
725295Srandyf  */
735295Srandyf static struct srnstate {
745295Srandyf 	dev_info_t	*srn_dip;		/* ptr to our dev_info node */
755295Srandyf 	int		srn_instance;		/* for ddi_get_instance() */
765295Srandyf 	uchar_t		srn_clones[SRN_MAX_CLONE]; /* unique opens	*/
775295Srandyf 	struct cred	*srn_cred[SRN_MAX_CLONE]; /* cred for each open	*/
785295Srandyf 	int		srn_type[SRN_MAX_CLONE]; /* type of handshake */
795295Srandyf 	int		srn_delivered[SRN_MAX_CLONE];
805295Srandyf 	srn_event_info_t srn_pending[SRN_MAX_CLONE];
815295Srandyf } srn = { NULL, -1};
825295Srandyf typedef struct srnstate *srn_state_t;
835295Srandyf 
845295Srandyf kcondvar_t	srn_clones_cv[SRN_MAX_CLONE];
855295Srandyf uint_t		srn_poll_cnt[SRN_MAX_CLONE];	/* count of events for poll */
865295Srandyf int		srn_apm_count;
875295Srandyf int		srn_autosx_count;
885295Srandyf struct pollhead	srn_pollhead[SRN_MAX_CLONE];
895295Srandyf 
905295Srandyf static int	srn_open(dev_t *, int, int, cred_t *);
915295Srandyf static int	srn_close(dev_t, int, int, cred_t *);
925295Srandyf static int	srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
935295Srandyf static int	srn_chpoll(dev_t, short, int, short *, struct pollhead **);
945295Srandyf 
955295Srandyf static struct cb_ops srn_cb_ops = {
965295Srandyf 	srn_open,	/* open */
975295Srandyf 	srn_close,	/* close */
985295Srandyf 	nodev,		/* strategy */
995295Srandyf 	nodev,		/* print */
1005295Srandyf 	nodev,		/* dump */
1015295Srandyf 	nodev,		/* read */
1025295Srandyf 	nodev,		/* write */
1035295Srandyf 	srn_ioctl,	/* ioctl */
1045295Srandyf 	nodev,		/* devmap */
1055295Srandyf 	nodev,		/* mmap */
1065295Srandyf 	nodev,		/* segmap */
1075295Srandyf 	srn_chpoll,	/* poll */
1085295Srandyf 	ddi_prop_op,	/* prop_op */
1095295Srandyf 	NULL,		/* streamtab */
1105295Srandyf 	D_NEW | D_MP	/* driver compatibility flag */
1115295Srandyf };
1125295Srandyf 
1135295Srandyf static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1145295Srandyf     void **result);
1155295Srandyf static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1165295Srandyf static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1175295Srandyf static void srn_notify(int type, int event);
1185295Srandyf 
1195295Srandyf static struct dev_ops srn_ops = {
1205295Srandyf 	DEVO_REV,		/* devo_rev */
1215295Srandyf 	0,			/* refcnt */
1225295Srandyf 	srn_getinfo,		/* info */
1235295Srandyf 	nulldev,		/* identify */
1245295Srandyf 	nulldev,		/* probe */
1255295Srandyf 	srn_attach,		/* attach */
1265295Srandyf 	srn_detach,		/* detach */
1275295Srandyf 	nodev,			/* reset */
1285295Srandyf 	&srn_cb_ops,		/* driver operations */
1295295Srandyf 	NULL,			/* bus operations */
130*7656SSherry.Moore@Sun.COM 	NULL,			/* power */
131*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
1325295Srandyf };
1335295Srandyf 
1345295Srandyf static struct modldrv modldrv = {
1355295Srandyf 	&mod_driverops,
136*7656SSherry.Moore@Sun.COM 	"srn driver",
1375295Srandyf 	&srn_ops
1385295Srandyf };
1395295Srandyf 
1405295Srandyf static struct modlinkage modlinkage = {
1415295Srandyf 	MODREV_1, &modldrv, 0
1425295Srandyf };
1435295Srandyf 
1445295Srandyf /* Local functions */
1455295Srandyf 
1465295Srandyf int
1475295Srandyf _init(void)
1485295Srandyf {
1495295Srandyf 	return (mod_install(&modlinkage));
1505295Srandyf }
1515295Srandyf 
1525295Srandyf int
1535295Srandyf _fini(void)
1545295Srandyf {
1555295Srandyf 	return (mod_remove(&modlinkage));
1565295Srandyf }
1575295Srandyf 
1585295Srandyf int
1595295Srandyf _info(struct modinfo *modinfop)
1605295Srandyf {
1615295Srandyf 	return (mod_info(&modlinkage, modinfop));
1625295Srandyf }
1635295Srandyf 
1645295Srandyf static int
1655295Srandyf srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1665295Srandyf {
1675295Srandyf 	int		i;
1685295Srandyf 	extern void (*srn_signal)(int, int);
1695295Srandyf 
1705295Srandyf 	switch (cmd) {
1715295Srandyf 
1725295Srandyf 	case DDI_ATTACH:
1735295Srandyf 		if (srn.srn_instance != -1)	/* Only allow one instance */
1745295Srandyf 			return (DDI_FAILURE);
1755295Srandyf 		srn.srn_instance = ddi_get_instance(dip);
1765295Srandyf 		if (ddi_create_minor_node(dip, "srn", S_IFCHR,
1775295Srandyf 		    (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0)
1785295Srandyf 		    != DDI_SUCCESS) {
1795295Srandyf 			return (DDI_FAILURE);
1805295Srandyf 		}
1815295Srandyf 		srn.srn_dip = dip;	/* srn_init and getinfo depend on it */
1825295Srandyf 
1835295Srandyf 		for (i = 0; i < SRN_MAX_CLONE; i++)
1845295Srandyf 			cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL);
1855295Srandyf 
1865295Srandyf 		srn.srn_instance = ddi_get_instance(dip);
1875295Srandyf 		mutex_enter(&srn_clone_lock);
1885295Srandyf 		srn_signal = srn_notify;
1895295Srandyf 		mutex_exit(&srn_clone_lock);
1905295Srandyf 		ddi_report_dev(dip);
1915295Srandyf 		return (DDI_SUCCESS);
1925295Srandyf 
1935295Srandyf 	default:
1945295Srandyf 		return (DDI_FAILURE);
1955295Srandyf 	}
1965295Srandyf }
1975295Srandyf 
1985295Srandyf /* ARGSUSED */
1995295Srandyf static int
2005295Srandyf srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2015295Srandyf {
2025295Srandyf 	int i;
2035295Srandyf 	extern int srn_inuse;
2045295Srandyf 	extern void (*srn_signal)(int, int);
2055295Srandyf 
2065295Srandyf 	switch (cmd) {
2075295Srandyf 	case DDI_DETACH:
2085295Srandyf 
2095295Srandyf 		mutex_enter(&srn_clone_lock);
2105295Srandyf 		while (srn_inuse) {
2115295Srandyf 			mutex_exit(&srn_clone_lock);
2125295Srandyf 			delay(1);
2135295Srandyf 			mutex_enter(&srn_clone_lock);
2145295Srandyf 		}
2155295Srandyf 		srn_signal = NULL;
2165295Srandyf 		mutex_exit(&srn_clone_lock);
2175295Srandyf 
2185295Srandyf 		for (i = 0; i < SRN_MAX_CLONE; i++)
2195295Srandyf 			cv_destroy(&srn_clones_cv[i]);
2205295Srandyf 
2215295Srandyf 		ddi_remove_minor_node(dip, NULL);
2225295Srandyf 		srn.srn_instance = -1;
2235295Srandyf 		return (DDI_SUCCESS);
2245295Srandyf 
2255295Srandyf 	default:
2265295Srandyf 		return (DDI_FAILURE);
2275295Srandyf 	}
2285295Srandyf }
2295295Srandyf 
2305295Srandyf 
2315295Srandyf #ifdef DEBUG
2325295Srandyf char *srn_cmd_string;
2335295Srandyf int srn_cmd;
2345295Srandyf #endif
2355295Srandyf 
2365295Srandyf /*
2375295Srandyf  * Returns true if permission granted by credentials
2385295Srandyf  * XXX
2395295Srandyf  */
2405295Srandyf static int
2415295Srandyf srn_perms(int perm, cred_t *cr)
2425295Srandyf {
2435295Srandyf 	if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */
2445295Srandyf 		return (1);
2455295Srandyf 	if ((perm & SG) && (crgetgid(cr) == 0))	/* group 0 is ok */
2465295Srandyf 		return (1);
2475295Srandyf 	return (0);
2485295Srandyf }
2495295Srandyf 
2505295Srandyf static int
2515295Srandyf srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
2525295Srandyf 	struct pollhead **phpp)
2535295Srandyf {
2545295Srandyf 	extern struct pollhead srn_pollhead[];	/* common/os/sunpm.c */
2555295Srandyf 	int	clone;
2565295Srandyf 
2575295Srandyf 	clone = SRN_MINOR_TO_CLONE(getminor(dev));
2585295Srandyf 	if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) {
2595295Srandyf 		*reventsp |= (POLLIN | POLLRDNORM);
2605295Srandyf 	} else {
2615295Srandyf 		*reventsp = 0;
2625295Srandyf 		if (!anyyet) {
2635295Srandyf 			*phpp = &srn_pollhead[clone];
2645295Srandyf 		}
2655295Srandyf 	}
2665295Srandyf 	return (0);
2675295Srandyf }
2685295Srandyf 
2695295Srandyf /*ARGSUSED*/
2705295Srandyf static int
2715295Srandyf srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2725295Srandyf {
2735295Srandyf 	dev_t	dev;
2745295Srandyf 	int	instance;
2755295Srandyf 
2765295Srandyf 	switch (infocmd) {
2775295Srandyf 	case DDI_INFO_DEVT2DEVINFO:
2785295Srandyf 		if (srn.srn_instance == -1)
2795295Srandyf 			return (DDI_FAILURE);
2805295Srandyf 		*result = srn.srn_dip;
2815295Srandyf 		return (DDI_SUCCESS);
2825295Srandyf 
2835295Srandyf 	case DDI_INFO_DEVT2INSTANCE:
2845295Srandyf 		dev = (dev_t)arg;
2855295Srandyf 		instance = getminor(dev) >> 8;
2865295Srandyf 		*result = (void *)(uintptr_t)instance;
2875295Srandyf 		return (DDI_SUCCESS);
2885295Srandyf 
2895295Srandyf 	default:
2905295Srandyf 		return (DDI_FAILURE);
2915295Srandyf 	}
2925295Srandyf }
2935295Srandyf 
2945295Srandyf 
2955295Srandyf /*ARGSUSED1*/
2965295Srandyf static int
2975295Srandyf srn_open(dev_t *devp, int flag, int otyp, cred_t *cr)
2985295Srandyf {
2995295Srandyf 	int		clone;
3005295Srandyf 
3015295Srandyf 	if (otyp != OTYP_CHR)
3025295Srandyf 		return (EINVAL);
3035295Srandyf 
3045295Srandyf 	mutex_enter(&srn_clone_lock);
3055295Srandyf 	for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++)
3065295Srandyf 		if (!srn.srn_clones[clone])
3075295Srandyf 			break;
3085295Srandyf 
3095295Srandyf 	if (clone == SRN_MAX_CLONE) {
3105295Srandyf 		mutex_exit(&srn_clone_lock);
3115295Srandyf 		return (ENXIO);
3125295Srandyf 	}
3135295Srandyf 	srn.srn_cred[clone] = cr;
3145295Srandyf 	ASSERT(srn_apm_count >= 0);
3155295Srandyf 	srn_apm_count++;
3165295Srandyf 	srn.srn_type[clone] = SRN_TYPE_APM;
3175295Srandyf 	crhold(cr);
3185295Srandyf 
3195295Srandyf 	*devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) +
3205295Srandyf 	    clone);
3215295Srandyf 	srn.srn_clones[clone] = 1;
3225295Srandyf 	srn.srn_cred[clone] = cr;
3235295Srandyf 	crhold(cr);
3245295Srandyf 	mutex_exit(&srn_clone_lock);
3255295Srandyf 	PMD(PMD_SX, ("srn open OK\n"))
3265295Srandyf 	return (0);
3275295Srandyf }
3285295Srandyf 
3295295Srandyf /*ARGSUSED1*/
3305295Srandyf static int
3315295Srandyf srn_close(dev_t dev, int flag, int otyp, cred_t *cr)
3325295Srandyf {
3335295Srandyf 	int clone;
3345295Srandyf 
3355295Srandyf 	if (otyp != OTYP_CHR)
3365295Srandyf 		return (EINVAL);
3375295Srandyf 
3385295Srandyf 	clone = SRN_MINOR_TO_CLONE(getminor(dev));
3395295Srandyf 	PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev),
3405295Srandyf 	    clone))
3415295Srandyf 	mutex_enter(&srn_clone_lock);
3425295Srandyf 	crfree(srn.srn_cred[clone]);
3435295Srandyf 	srn.srn_cred[clone] = 0;
3445295Srandyf 	srn_poll_cnt[clone] = 0;
3455295Srandyf 	if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) {
3465295Srandyf 		srn.srn_pending[clone].ae_type = 0;
3475295Srandyf 		srn.srn_delivered[clone] = 0;
3485295Srandyf 		cv_signal(&srn_clones_cv[clone]);
3495295Srandyf 	}
3505295Srandyf 	switch (srn.srn_type[clone]) {
3515295Srandyf 	case SRN_TYPE_AUTOSX:
3525295Srandyf 		ASSERT(srn_autosx_count);
3535295Srandyf 		srn_autosx_count--;
3545295Srandyf 		break;
3555295Srandyf 	case SRN_TYPE_APM:
3565295Srandyf 		ASSERT(srn_apm_count);
3575295Srandyf 		srn_apm_count--;
3585295Srandyf 		break;
3595295Srandyf 	default:
3605295Srandyf 		ASSERT(0);
3615295Srandyf 		return (EINVAL);
3625295Srandyf 	}
3635295Srandyf 	srn.srn_clones[clone] = 0;
3645295Srandyf 	mutex_exit(&srn_clone_lock);
3655295Srandyf 	return (0);
3665295Srandyf }
3675295Srandyf 
3685295Srandyf /*ARGSUSED*/
3695295Srandyf static int
3705295Srandyf srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)
3715295Srandyf {
3725295Srandyf 	int clone = SRN_MINOR_TO_CLONE(getminor(dev));
3735295Srandyf 
3745295Srandyf 	PMD(PMD_SX, ("ioctl: %x: begin\n", cmd))
3755295Srandyf 
3765295Srandyf 	switch (cmd) {
3775295Srandyf 	case SRN_IOC_NEXTEVENT:
3785295Srandyf 	case SRN_IOC_SUSPEND:
3795295Srandyf 	case SRN_IOC_RESUME:
3805295Srandyf 	case SRN_IOC_AUTOSX:
3815295Srandyf 		break;
3825295Srandyf 	default:
3835295Srandyf 		return (ENOTTY);
3845295Srandyf 	}
3855295Srandyf 
3865295Srandyf 	if (!srn_perms(SU | SG, srn.srn_cred[clone])) {
3875295Srandyf 		return (EPERM);
3885295Srandyf 	}
3895295Srandyf 	switch (cmd) {
3905295Srandyf 	case SRN_IOC_AUTOSX:
3915295Srandyf 		PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n"))
3925295Srandyf 		mutex_enter(&srn_clone_lock);
3935295Srandyf 		if (!srn.srn_clones[clone]) {
3945295Srandyf 			PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n"))
3955295Srandyf 			mutex_exit(&srn_clone_lock);
3965295Srandyf 			return (EINVAL);
3975295Srandyf 		}
3985295Srandyf 		if (srn.srn_pending[clone].ae_type) {
3995295Srandyf 			PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n"))
4005295Srandyf 			mutex_exit(&srn_clone_lock);
4015295Srandyf 			return (EBUSY);
4025295Srandyf 		}
4035295Srandyf 		if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) {
4045295Srandyf 			PMD(PMD_SX, ("AUTOSX already--EBUSY\n"))
4055295Srandyf 			mutex_exit(&srn_clone_lock);
4065295Srandyf 			return (EBUSY);
4075295Srandyf 		}
4085295Srandyf 		ASSERT(srn.srn_type[clone] == SRN_TYPE_APM);
4095295Srandyf 		srn.srn_type[clone] = SRN_TYPE_AUTOSX;
4105295Srandyf 		srn_apm_count--;
4115295Srandyf 		ASSERT(srn_apm_count >= 0);
4125295Srandyf 		ASSERT(srn_autosx_count >= 0);
4135295Srandyf 		srn_autosx_count++;
4145295Srandyf 		mutex_exit(&srn_clone_lock);
4155295Srandyf 		PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n"))
4165295Srandyf 		return (0);
4175295Srandyf 
4185295Srandyf 	case SRN_IOC_NEXTEVENT:
4195295Srandyf 		/*
4205295Srandyf 		 * return the next suspend or resume event;  there should
4215295Srandyf 		 * be one, cause we only get called if we've signalled a
4225295Srandyf 		 * poll data completion
4235295Srandyf 		 * then wake up the kernel thread sleeping for the delivery
4245295Srandyf 		 */
4255295Srandyf 		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n"))
4265295Srandyf 		mutex_enter(&srn_clone_lock);
4275295Srandyf 		if (srn_poll_cnt[clone] == 0) {
4285295Srandyf 			mutex_exit(&srn_clone_lock);
4295295Srandyf 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d "
4305295Srandyf 			    "EWOULDBLOCK\n", clone))
4315295Srandyf 			return (EWOULDBLOCK);
4325295Srandyf 		}
4335295Srandyf 		ASSERT(srn.srn_pending[clone].ae_type);
4345295Srandyf 		if (ddi_copyout(&srn.srn_pending[clone], (void *)arg,
4355295Srandyf 		    sizeof (srn_event_info_t), mode) != 0) {
4365295Srandyf 			mutex_exit(&srn_clone_lock);
4375295Srandyf 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n",
4385295Srandyf 			    clone))
4395295Srandyf 			return (EFAULT);
4405295Srandyf 		}
4415295Srandyf 		if (srn.srn_type[clone] == SRN_TYPE_APM)
4425295Srandyf 			srn.srn_delivered[clone] =
4435295Srandyf 			    srn.srn_pending[clone].ae_type;
4445295Srandyf 		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n",
4455295Srandyf 		    clone, srn.srn_pending[clone].ae_type))
4465295Srandyf 		srn_poll_cnt[clone] = 0;
4475295Srandyf 		mutex_exit(&srn_clone_lock);
4485295Srandyf 		return (0);
4495295Srandyf 
4505295Srandyf 	case SRN_IOC_SUSPEND:
4515295Srandyf 		/* ack suspend */
4525295Srandyf 		PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone))
4535295Srandyf 		mutex_enter(&srn_clone_lock);
4545295Srandyf 		if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) {
4555295Srandyf 			mutex_exit(&srn_clone_lock);
4565295Srandyf 			PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n"))
4575295Srandyf 			return (EINVAL);
4585295Srandyf 		}
4595295Srandyf 		srn.srn_delivered[clone] = 0;
4605295Srandyf 		srn.srn_pending[clone].ae_type = 0;
4615295Srandyf 		/* notify the kernel suspend thread  to continue */
4625295Srandyf 		PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone))
4635295Srandyf 		cv_signal(&srn_clones_cv[clone]);
4645295Srandyf 		mutex_exit(&srn_clone_lock);
4655295Srandyf 		return (0);
4665295Srandyf 
4675295Srandyf 	case SRN_IOC_RESUME:
4685295Srandyf 		/* ack resume */
4695295Srandyf 		PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone))
4705295Srandyf 		mutex_enter(&srn_clone_lock);
4715295Srandyf 		if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) {
4725295Srandyf 			mutex_exit(&srn_clone_lock);
4735295Srandyf 			PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n"))
4745295Srandyf 			return (EINVAL);
4755295Srandyf 		}
4765295Srandyf 		srn.srn_delivered[clone] = 0;
4775295Srandyf 		srn.srn_pending[clone].ae_type = 0;
4785295Srandyf 		/* notify the kernel resume thread  to continue */
4795295Srandyf 		PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone))
4805295Srandyf 		cv_signal(&srn_clones_cv[clone]);
4815295Srandyf 		mutex_exit(&srn_clone_lock);
4825295Srandyf 		return (0);
4835295Srandyf 
4845295Srandyf 	default:
4855295Srandyf 		PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n"))
4865295Srandyf 		return (EINVAL);
4875295Srandyf 	}
4885295Srandyf }
4895295Srandyf /*
4905295Srandyf  * A very simple handshake with the srn driver,
4915295Srandyf  * only one outstanding event at a time.
4925295Srandyf  * The OS delivers the event and depending on type,
4935295Srandyf  * either blocks waiting for the ack, or drives on
4945295Srandyf  */
4955295Srandyf void
4965295Srandyf srn_notify(int type, int event)
4975295Srandyf {
4985295Srandyf 	int clone, count;
4995295Srandyf 	PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n",
5005295Srandyf 	    type, event));
5015295Srandyf 	ASSERT(mutex_owned(&srn_clone_lock));
5025295Srandyf 	switch (type) {
5035295Srandyf 	case SRN_TYPE_APM:
5045295Srandyf 		if (srn_apm_count == 0) {
5055295Srandyf 			PMD(PMD_SX, ("no apm types\n"))
5065295Srandyf 			return;
5075295Srandyf 		}
5085295Srandyf 		count = srn_apm_count;
5095295Srandyf 		break;
5105295Srandyf 	case SRN_TYPE_AUTOSX:
5115295Srandyf 		if (srn_autosx_count == 0) {
5125295Srandyf 			PMD(PMD_SX, ("no autosx types\n"))
5135295Srandyf 			return;
5145295Srandyf 		}
5155295Srandyf 		count = srn_autosx_count;
5165295Srandyf 		break;
5175295Srandyf 	default:
5185295Srandyf 		ASSERT(0);
5195295Srandyf 		break;
5205295Srandyf 	}
5215295Srandyf 	ASSERT(count > 0);
5225295Srandyf 	PMD(PMD_SX, ("count %d\n", count))
5235295Srandyf 	for (clone = 0; clone < SRN_MAX_CLONE; clone++) {
5245295Srandyf 		if (srn.srn_type[clone] == type) {
5255295Srandyf 			if (type == SRN_TYPE_APM) {
5265295Srandyf 				ASSERT(srn.srn_pending[clone].ae_type == 0);
5275295Srandyf 				ASSERT(srn_poll_cnt[clone] == 0);
5285295Srandyf 				ASSERT(srn.srn_delivered[clone] == 0);
5295295Srandyf 			}
5305295Srandyf 			srn.srn_pending[clone].ae_type = event;
5315295Srandyf 			srn_poll_cnt[clone] = 1;
5325295Srandyf 			PMD(PMD_SX, ("pollwake %d\n", clone))
5335295Srandyf 			pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN));
5345295Srandyf 			count--;
5355295Srandyf 			if (count == 0)
5365295Srandyf 				break;
5375295Srandyf 		}
5385295Srandyf 	}
5395295Srandyf 	if (type == SRN_TYPE_AUTOSX) {		/* we don't wait */
5405295Srandyf 		PMD(PMD_SX, ("Not waiting for AUTOSX ack\n"))
5415295Srandyf 		return;
5425295Srandyf 	}
5435295Srandyf 	ASSERT(type == SRN_TYPE_APM);
5445295Srandyf 	/* otherwise wait for acks */
5455295Srandyf restart:
5465295Srandyf 	/*
5475295Srandyf 	 * We wait untill all of the pending events are cleared.
5485295Srandyf 	 * We have to start over every time we do a cv_wait because
5495295Srandyf 	 * we give up the mutex and can be re-entered
5505295Srandyf 	 */
5515295Srandyf 	for (clone = 1; clone < SRN_MAX_CLONE; clone++) {
5525295Srandyf 		if (srn.srn_clones[clone] == 0 ||
5535295Srandyf 		    srn.srn_type[clone] != SRN_TYPE_APM)
5545295Srandyf 			continue;
5555295Srandyf 		if (srn.srn_pending[clone].ae_type) {
5565295Srandyf 			PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, "
5575295Srandyf 			    "event %x\n", clone, event))
5585295Srandyf 			cv_wait(&srn_clones_cv[clone], &srn_clone_lock);
5595295Srandyf 			goto restart;
5605295Srandyf 		}
5615295Srandyf 	}
5625295Srandyf 	PMD(PMD_SX, ("srn_notify done with %x\n", event))
5635295Srandyf }
564