xref: /onnv-gate/usr/src/uts/common/io/srn.c (revision 10642:3507a45006a0)
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 /*
2310311SRandy.Fishel@Sun.COM  * Copyright 2009 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];
8110311SRandy.Fishel@Sun.COM 	int		srn_fault[SRN_MAX_CLONE];
825295Srandyf } srn = { NULL, -1};
835295Srandyf typedef struct srnstate *srn_state_t;
845295Srandyf 
855295Srandyf kcondvar_t	srn_clones_cv[SRN_MAX_CLONE];
865295Srandyf uint_t		srn_poll_cnt[SRN_MAX_CLONE];	/* count of events for poll */
875295Srandyf int		srn_apm_count;
885295Srandyf int		srn_autosx_count;
8910311SRandy.Fishel@Sun.COM /* Number of seconds to wait for clients to ack a poll */
9010311SRandy.Fishel@Sun.COM int		srn_timeout = 10;
9110311SRandy.Fishel@Sun.COM 
925295Srandyf struct pollhead	srn_pollhead[SRN_MAX_CLONE];
935295Srandyf 
945295Srandyf static int	srn_open(dev_t *, int, int, cred_t *);
955295Srandyf static int	srn_close(dev_t, int, int, cred_t *);
965295Srandyf static int	srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
975295Srandyf static int	srn_chpoll(dev_t, short, int, short *, struct pollhead **);
985295Srandyf 
995295Srandyf static struct cb_ops srn_cb_ops = {
1005295Srandyf 	srn_open,	/* open */
1015295Srandyf 	srn_close,	/* close */
1025295Srandyf 	nodev,		/* strategy */
1035295Srandyf 	nodev,		/* print */
1045295Srandyf 	nodev,		/* dump */
1055295Srandyf 	nodev,		/* read */
1065295Srandyf 	nodev,		/* write */
1075295Srandyf 	srn_ioctl,	/* ioctl */
1085295Srandyf 	nodev,		/* devmap */
1095295Srandyf 	nodev,		/* mmap */
1105295Srandyf 	nodev,		/* segmap */
1115295Srandyf 	srn_chpoll,	/* poll */
1125295Srandyf 	ddi_prop_op,	/* prop_op */
1135295Srandyf 	NULL,		/* streamtab */
1145295Srandyf 	D_NEW | D_MP	/* driver compatibility flag */
1155295Srandyf };
1165295Srandyf 
1175295Srandyf static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
1185295Srandyf     void **result);
1195295Srandyf static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
1205295Srandyf static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
1215295Srandyf static void srn_notify(int type, int event);
1225295Srandyf 
1235295Srandyf static struct dev_ops srn_ops = {
1245295Srandyf 	DEVO_REV,		/* devo_rev */
1255295Srandyf 	0,			/* refcnt */
1265295Srandyf 	srn_getinfo,		/* info */
1275295Srandyf 	nulldev,		/* identify */
1285295Srandyf 	nulldev,		/* probe */
1295295Srandyf 	srn_attach,		/* attach */
1305295Srandyf 	srn_detach,		/* detach */
1315295Srandyf 	nodev,			/* reset */
1325295Srandyf 	&srn_cb_ops,		/* driver operations */
1335295Srandyf 	NULL,			/* bus operations */
1347656SSherry.Moore@Sun.COM 	NULL,			/* power */
1357656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
1365295Srandyf };
1375295Srandyf 
1385295Srandyf static struct modldrv modldrv = {
1395295Srandyf 	&mod_driverops,
1407656SSherry.Moore@Sun.COM 	"srn driver",
1415295Srandyf 	&srn_ops
1425295Srandyf };
1435295Srandyf 
1445295Srandyf static struct modlinkage modlinkage = {
1455295Srandyf 	MODREV_1, &modldrv, 0
1465295Srandyf };
1475295Srandyf 
1485295Srandyf /* Local functions */
1495295Srandyf 
1505295Srandyf int
_init(void)1515295Srandyf _init(void)
1525295Srandyf {
1535295Srandyf 	return (mod_install(&modlinkage));
1545295Srandyf }
1555295Srandyf 
1565295Srandyf int
_fini(void)1575295Srandyf _fini(void)
1585295Srandyf {
1595295Srandyf 	return (mod_remove(&modlinkage));
1605295Srandyf }
1615295Srandyf 
1625295Srandyf int
_info(struct modinfo * modinfop)1635295Srandyf _info(struct modinfo *modinfop)
1645295Srandyf {
1655295Srandyf 	return (mod_info(&modlinkage, modinfop));
1665295Srandyf }
1675295Srandyf 
1685295Srandyf static int
srn_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1695295Srandyf srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1705295Srandyf {
1715295Srandyf 	int		i;
1725295Srandyf 	extern void (*srn_signal)(int, int);
1735295Srandyf 
1745295Srandyf 	switch (cmd) {
1755295Srandyf 
1765295Srandyf 	case DDI_ATTACH:
1775295Srandyf 		if (srn.srn_instance != -1)	/* Only allow one instance */
1785295Srandyf 			return (DDI_FAILURE);
1795295Srandyf 		srn.srn_instance = ddi_get_instance(dip);
1805295Srandyf 		if (ddi_create_minor_node(dip, "srn", S_IFCHR,
1815295Srandyf 		    (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0)
1825295Srandyf 		    != DDI_SUCCESS) {
1835295Srandyf 			return (DDI_FAILURE);
1845295Srandyf 		}
1855295Srandyf 		srn.srn_dip = dip;	/* srn_init and getinfo depend on it */
1865295Srandyf 
1875295Srandyf 		for (i = 0; i < SRN_MAX_CLONE; i++)
1885295Srandyf 			cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL);
1895295Srandyf 
1905295Srandyf 		srn.srn_instance = ddi_get_instance(dip);
1915295Srandyf 		mutex_enter(&srn_clone_lock);
1925295Srandyf 		srn_signal = srn_notify;
1935295Srandyf 		mutex_exit(&srn_clone_lock);
1945295Srandyf 		ddi_report_dev(dip);
1955295Srandyf 		return (DDI_SUCCESS);
1965295Srandyf 
1975295Srandyf 	default:
1985295Srandyf 		return (DDI_FAILURE);
1995295Srandyf 	}
2005295Srandyf }
2015295Srandyf 
2025295Srandyf /* ARGSUSED */
2035295Srandyf static int
srn_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2045295Srandyf srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2055295Srandyf {
2065295Srandyf 	int i;
2075295Srandyf 	extern int srn_inuse;
2085295Srandyf 	extern void (*srn_signal)(int, int);
2095295Srandyf 
2105295Srandyf 	switch (cmd) {
2115295Srandyf 	case DDI_DETACH:
2125295Srandyf 
2135295Srandyf 		mutex_enter(&srn_clone_lock);
2145295Srandyf 		while (srn_inuse) {
2155295Srandyf 			mutex_exit(&srn_clone_lock);
2165295Srandyf 			delay(1);
2175295Srandyf 			mutex_enter(&srn_clone_lock);
2185295Srandyf 		}
2195295Srandyf 		srn_signal = NULL;
2205295Srandyf 		mutex_exit(&srn_clone_lock);
2215295Srandyf 
2225295Srandyf 		for (i = 0; i < SRN_MAX_CLONE; i++)
2235295Srandyf 			cv_destroy(&srn_clones_cv[i]);
2245295Srandyf 
2255295Srandyf 		ddi_remove_minor_node(dip, NULL);
2265295Srandyf 		srn.srn_instance = -1;
2275295Srandyf 		return (DDI_SUCCESS);
2285295Srandyf 
2295295Srandyf 	default:
2305295Srandyf 		return (DDI_FAILURE);
2315295Srandyf 	}
2325295Srandyf }
2335295Srandyf 
2345295Srandyf 
2355295Srandyf #ifdef DEBUG
2365295Srandyf char *srn_cmd_string;
2375295Srandyf int srn_cmd;
2385295Srandyf #endif
2395295Srandyf 
2405295Srandyf /*
2415295Srandyf  * Returns true if permission granted by credentials
2425295Srandyf  * XXX
2435295Srandyf  */
2445295Srandyf static int
srn_perms(int perm,cred_t * cr)2455295Srandyf srn_perms(int perm, cred_t *cr)
2465295Srandyf {
2475295Srandyf 	if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */
2485295Srandyf 		return (1);
2495295Srandyf 	if ((perm & SG) && (crgetgid(cr) == 0))	/* group 0 is ok */
2505295Srandyf 		return (1);
2515295Srandyf 	return (0);
2525295Srandyf }
2535295Srandyf 
2545295Srandyf static int
srn_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)2555295Srandyf srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
2565295Srandyf 	struct pollhead **phpp)
2575295Srandyf {
25810311SRandy.Fishel@Sun.COM 	extern struct pollhead srn_pollhead[];
2595295Srandyf 	int	clone;
2605295Srandyf 
2615295Srandyf 	clone = SRN_MINOR_TO_CLONE(getminor(dev));
2625295Srandyf 	if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) {
2635295Srandyf 		*reventsp |= (POLLIN | POLLRDNORM);
2645295Srandyf 	} else {
2655295Srandyf 		*reventsp = 0;
2665295Srandyf 		if (!anyyet) {
2675295Srandyf 			*phpp = &srn_pollhead[clone];
2685295Srandyf 		}
2695295Srandyf 	}
2705295Srandyf 	return (0);
2715295Srandyf }
2725295Srandyf 
2735295Srandyf /*ARGSUSED*/
2745295Srandyf static int
srn_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)2755295Srandyf srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
2765295Srandyf {
2775295Srandyf 	dev_t	dev;
2785295Srandyf 	int	instance;
2795295Srandyf 
2805295Srandyf 	switch (infocmd) {
2815295Srandyf 	case DDI_INFO_DEVT2DEVINFO:
2825295Srandyf 		if (srn.srn_instance == -1)
2835295Srandyf 			return (DDI_FAILURE);
2845295Srandyf 		*result = srn.srn_dip;
2855295Srandyf 		return (DDI_SUCCESS);
2865295Srandyf 
2875295Srandyf 	case DDI_INFO_DEVT2INSTANCE:
2885295Srandyf 		dev = (dev_t)arg;
2895295Srandyf 		instance = getminor(dev) >> 8;
2905295Srandyf 		*result = (void *)(uintptr_t)instance;
2915295Srandyf 		return (DDI_SUCCESS);
2925295Srandyf 
2935295Srandyf 	default:
2945295Srandyf 		return (DDI_FAILURE);
2955295Srandyf 	}
2965295Srandyf }
2975295Srandyf 
2985295Srandyf 
2995295Srandyf /*ARGSUSED1*/
3005295Srandyf static int
srn_open(dev_t * devp,int flag,int otyp,cred_t * cr)3015295Srandyf srn_open(dev_t *devp, int flag, int otyp, cred_t *cr)
3025295Srandyf {
3035295Srandyf 	int		clone;
3045295Srandyf 
3055295Srandyf 	if (otyp != OTYP_CHR)
3065295Srandyf 		return (EINVAL);
3075295Srandyf 
3085295Srandyf 	mutex_enter(&srn_clone_lock);
3095295Srandyf 	for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++)
3105295Srandyf 		if (!srn.srn_clones[clone])
3115295Srandyf 			break;
3125295Srandyf 
3135295Srandyf 	if (clone == SRN_MAX_CLONE) {
3145295Srandyf 		mutex_exit(&srn_clone_lock);
3155295Srandyf 		return (ENXIO);
3165295Srandyf 	}
3175295Srandyf 	srn.srn_cred[clone] = cr;
3185295Srandyf 	ASSERT(srn_apm_count >= 0);
3195295Srandyf 	srn_apm_count++;
3205295Srandyf 	srn.srn_type[clone] = SRN_TYPE_APM;
3215295Srandyf 	crhold(cr);
3225295Srandyf 
3235295Srandyf 	*devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) +
3245295Srandyf 	    clone);
3255295Srandyf 	srn.srn_clones[clone] = 1;
3265295Srandyf 	srn.srn_cred[clone] = cr;
3275295Srandyf 	crhold(cr);
3285295Srandyf 	mutex_exit(&srn_clone_lock);
3295295Srandyf 	PMD(PMD_SX, ("srn open OK\n"))
3305295Srandyf 	return (0);
3315295Srandyf }
3325295Srandyf 
3335295Srandyf /*ARGSUSED1*/
3345295Srandyf static int
srn_close(dev_t dev,int flag,int otyp,cred_t * cr)3355295Srandyf srn_close(dev_t dev, int flag, int otyp, cred_t *cr)
3365295Srandyf {
3375295Srandyf 	int clone;
3385295Srandyf 
3395295Srandyf 	if (otyp != OTYP_CHR)
3405295Srandyf 		return (EINVAL);
3415295Srandyf 
3425295Srandyf 	clone = SRN_MINOR_TO_CLONE(getminor(dev));
3435295Srandyf 	PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev),
3445295Srandyf 	    clone))
3455295Srandyf 	mutex_enter(&srn_clone_lock);
3465295Srandyf 	crfree(srn.srn_cred[clone]);
3475295Srandyf 	srn.srn_cred[clone] = 0;
3485295Srandyf 	srn_poll_cnt[clone] = 0;
34910311SRandy.Fishel@Sun.COM 	srn.srn_fault[clone] = 0;
3505295Srandyf 	if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) {
3515295Srandyf 		srn.srn_pending[clone].ae_type = 0;
3525295Srandyf 		srn.srn_delivered[clone] = 0;
3535295Srandyf 		cv_signal(&srn_clones_cv[clone]);
3545295Srandyf 	}
3555295Srandyf 	switch (srn.srn_type[clone]) {
3565295Srandyf 	case SRN_TYPE_AUTOSX:
3575295Srandyf 		ASSERT(srn_autosx_count);
3585295Srandyf 		srn_autosx_count--;
3595295Srandyf 		break;
3605295Srandyf 	case SRN_TYPE_APM:
3615295Srandyf 		ASSERT(srn_apm_count);
3625295Srandyf 		srn_apm_count--;
3635295Srandyf 		break;
3645295Srandyf 	default:
3655295Srandyf 		ASSERT(0);
3665295Srandyf 		return (EINVAL);
3675295Srandyf 	}
3685295Srandyf 	srn.srn_clones[clone] = 0;
3695295Srandyf 	mutex_exit(&srn_clone_lock);
3705295Srandyf 	return (0);
3715295Srandyf }
3725295Srandyf 
3735295Srandyf /*ARGSUSED*/
3745295Srandyf static int
srn_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval_p)3755295Srandyf srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p)
3765295Srandyf {
3775295Srandyf 	int clone = SRN_MINOR_TO_CLONE(getminor(dev));
3785295Srandyf 
3795295Srandyf 	PMD(PMD_SX, ("ioctl: %x: begin\n", cmd))
3805295Srandyf 
3815295Srandyf 	switch (cmd) {
3825295Srandyf 	case SRN_IOC_NEXTEVENT:
3835295Srandyf 	case SRN_IOC_SUSPEND:
3845295Srandyf 	case SRN_IOC_RESUME:
3855295Srandyf 	case SRN_IOC_AUTOSX:
3865295Srandyf 		break;
3875295Srandyf 	default:
3885295Srandyf 		return (ENOTTY);
3895295Srandyf 	}
3905295Srandyf 
3915295Srandyf 	if (!srn_perms(SU | SG, srn.srn_cred[clone])) {
3925295Srandyf 		return (EPERM);
3935295Srandyf 	}
3945295Srandyf 	switch (cmd) {
3955295Srandyf 	case SRN_IOC_AUTOSX:
3965295Srandyf 		PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n"))
3975295Srandyf 		mutex_enter(&srn_clone_lock);
3985295Srandyf 		if (!srn.srn_clones[clone]) {
3995295Srandyf 			PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n"))
4005295Srandyf 			mutex_exit(&srn_clone_lock);
4015295Srandyf 			return (EINVAL);
4025295Srandyf 		}
4035295Srandyf 		if (srn.srn_pending[clone].ae_type) {
4045295Srandyf 			PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n"))
4055295Srandyf 			mutex_exit(&srn_clone_lock);
4065295Srandyf 			return (EBUSY);
4075295Srandyf 		}
4085295Srandyf 		if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) {
4095295Srandyf 			PMD(PMD_SX, ("AUTOSX already--EBUSY\n"))
4105295Srandyf 			mutex_exit(&srn_clone_lock);
4115295Srandyf 			return (EBUSY);
4125295Srandyf 		}
4135295Srandyf 		ASSERT(srn.srn_type[clone] == SRN_TYPE_APM);
4145295Srandyf 		srn.srn_type[clone] = SRN_TYPE_AUTOSX;
41510311SRandy.Fishel@Sun.COM 		srn.srn_fault[clone] = 0;
4165295Srandyf 		srn_apm_count--;
4175295Srandyf 		ASSERT(srn_apm_count >= 0);
4185295Srandyf 		ASSERT(srn_autosx_count >= 0);
4195295Srandyf 		srn_autosx_count++;
4205295Srandyf 		mutex_exit(&srn_clone_lock);
4215295Srandyf 		PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n"))
4225295Srandyf 		return (0);
4235295Srandyf 
4245295Srandyf 	case SRN_IOC_NEXTEVENT:
4255295Srandyf 		/*
4265295Srandyf 		 * return the next suspend or resume event;  there should
4275295Srandyf 		 * be one, cause we only get called if we've signalled a
4285295Srandyf 		 * poll data completion
4295295Srandyf 		 * then wake up the kernel thread sleeping for the delivery
4305295Srandyf 		 */
4315295Srandyf 		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n"))
43210311SRandy.Fishel@Sun.COM 		if (srn.srn_fault[clone]) {
43310311SRandy.Fishel@Sun.COM 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d fault "
43410311SRandy.Fishel@Sun.COM 			    "cleared\n", clone))
43510311SRandy.Fishel@Sun.COM 			srn.srn_fault[clone] = 0;
43610311SRandy.Fishel@Sun.COM 		}
4375295Srandyf 		mutex_enter(&srn_clone_lock);
4385295Srandyf 		if (srn_poll_cnt[clone] == 0) {
4395295Srandyf 			mutex_exit(&srn_clone_lock);
4405295Srandyf 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d "
4415295Srandyf 			    "EWOULDBLOCK\n", clone))
4425295Srandyf 			return (EWOULDBLOCK);
4435295Srandyf 		}
4445295Srandyf 		ASSERT(srn.srn_pending[clone].ae_type);
4455295Srandyf 		if (ddi_copyout(&srn.srn_pending[clone], (void *)arg,
4465295Srandyf 		    sizeof (srn_event_info_t), mode) != 0) {
4475295Srandyf 			mutex_exit(&srn_clone_lock);
4485295Srandyf 			PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n",
4495295Srandyf 			    clone))
4505295Srandyf 			return (EFAULT);
4515295Srandyf 		}
4525295Srandyf 		if (srn.srn_type[clone] == SRN_TYPE_APM)
4535295Srandyf 			srn.srn_delivered[clone] =
4545295Srandyf 			    srn.srn_pending[clone].ae_type;
4555295Srandyf 		PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n",
4565295Srandyf 		    clone, srn.srn_pending[clone].ae_type))
4575295Srandyf 		srn_poll_cnt[clone] = 0;
4585295Srandyf 		mutex_exit(&srn_clone_lock);
4595295Srandyf 		return (0);
4605295Srandyf 
4615295Srandyf 	case SRN_IOC_SUSPEND:
4625295Srandyf 		/* ack suspend */
4635295Srandyf 		PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone))
46410311SRandy.Fishel@Sun.COM 		if (srn.srn_fault[clone]) {
46510311SRandy.Fishel@Sun.COM 			PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d fault "
46610311SRandy.Fishel@Sun.COM 			    "cleared\n", clone))
46710311SRandy.Fishel@Sun.COM 			srn.srn_fault[clone] = 0;
46810311SRandy.Fishel@Sun.COM 		}
4695295Srandyf 		mutex_enter(&srn_clone_lock);
4705295Srandyf 		if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) {
4715295Srandyf 			mutex_exit(&srn_clone_lock);
4725295Srandyf 			PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n"))
4735295Srandyf 			return (EINVAL);
4745295Srandyf 		}
4755295Srandyf 		srn.srn_delivered[clone] = 0;
4765295Srandyf 		srn.srn_pending[clone].ae_type = 0;
4775295Srandyf 		/* notify the kernel suspend thread  to continue */
4785295Srandyf 		PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone))
4795295Srandyf 		cv_signal(&srn_clones_cv[clone]);
4805295Srandyf 		mutex_exit(&srn_clone_lock);
4815295Srandyf 		return (0);
4825295Srandyf 
4835295Srandyf 	case SRN_IOC_RESUME:
4845295Srandyf 		/* ack resume */
4855295Srandyf 		PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone))
48610311SRandy.Fishel@Sun.COM 		if (srn.srn_fault[clone]) {
48710311SRandy.Fishel@Sun.COM 			PMD(PMD_SX, ("SRN_IOC_RESUME clone %d fault "
48810311SRandy.Fishel@Sun.COM 			    "cleared\n", clone))
48910311SRandy.Fishel@Sun.COM 			srn.srn_fault[clone] = 0;
49010311SRandy.Fishel@Sun.COM 		}
4915295Srandyf 		mutex_enter(&srn_clone_lock);
4925295Srandyf 		if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) {
4935295Srandyf 			mutex_exit(&srn_clone_lock);
4945295Srandyf 			PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n"))
4955295Srandyf 			return (EINVAL);
4965295Srandyf 		}
4975295Srandyf 		srn.srn_delivered[clone] = 0;
4985295Srandyf 		srn.srn_pending[clone].ae_type = 0;
4995295Srandyf 		/* notify the kernel resume thread  to continue */
5005295Srandyf 		PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone))
5015295Srandyf 		cv_signal(&srn_clones_cv[clone]);
5025295Srandyf 		mutex_exit(&srn_clone_lock);
5035295Srandyf 		return (0);
5045295Srandyf 
5055295Srandyf 	default:
5065295Srandyf 		PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n"))
5075295Srandyf 		return (EINVAL);
5085295Srandyf 	}
5095295Srandyf }
5105295Srandyf /*
5115295Srandyf  * A very simple handshake with the srn driver,
5125295Srandyf  * only one outstanding event at a time.
5135295Srandyf  * The OS delivers the event and depending on type,
5145295Srandyf  * either blocks waiting for the ack, or drives on
5155295Srandyf  */
5165295Srandyf void
srn_notify(int type,int event)5175295Srandyf srn_notify(int type, int event)
5185295Srandyf {
5195295Srandyf 	int clone, count;
5205295Srandyf 	PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n",
5215295Srandyf 	    type, event));
5225295Srandyf 	ASSERT(mutex_owned(&srn_clone_lock));
5235295Srandyf 	switch (type) {
5245295Srandyf 	case SRN_TYPE_APM:
5255295Srandyf 		if (srn_apm_count == 0) {
5265295Srandyf 			PMD(PMD_SX, ("no apm types\n"))
5275295Srandyf 			return;
5285295Srandyf 		}
5295295Srandyf 		count = srn_apm_count;
5305295Srandyf 		break;
5315295Srandyf 	case SRN_TYPE_AUTOSX:
5325295Srandyf 		if (srn_autosx_count == 0) {
5335295Srandyf 			PMD(PMD_SX, ("no autosx types\n"))
5345295Srandyf 			return;
5355295Srandyf 		}
5365295Srandyf 		count = srn_autosx_count;
5375295Srandyf 		break;
5385295Srandyf 	default:
5395295Srandyf 		ASSERT(0);
5405295Srandyf 		break;
5415295Srandyf 	}
5425295Srandyf 	ASSERT(count > 0);
5435295Srandyf 	PMD(PMD_SX, ("count %d\n", count))
5445295Srandyf 	for (clone = 0; clone < SRN_MAX_CLONE; clone++) {
5455295Srandyf 		if (srn.srn_type[clone] == type) {
54610311SRandy.Fishel@Sun.COM #ifdef DEBUG
547*10642SRandy.Fishel@Sun.COM 			if (type == SRN_TYPE_APM && !srn.srn_fault[clone]) {
5485295Srandyf 				ASSERT(srn.srn_pending[clone].ae_type == 0);
5495295Srandyf 				ASSERT(srn_poll_cnt[clone] == 0);
5505295Srandyf 				ASSERT(srn.srn_delivered[clone] == 0);
5515295Srandyf 			}
55210311SRandy.Fishel@Sun.COM #endif
5535295Srandyf 			srn.srn_pending[clone].ae_type = event;
5545295Srandyf 			srn_poll_cnt[clone] = 1;
5555295Srandyf 			PMD(PMD_SX, ("pollwake %d\n", clone))
5565295Srandyf 			pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN));
5575295Srandyf 			count--;
5585295Srandyf 			if (count == 0)
5595295Srandyf 				break;
5605295Srandyf 		}
5615295Srandyf 	}
5625295Srandyf 	if (type == SRN_TYPE_AUTOSX) {		/* we don't wait */
5635295Srandyf 		PMD(PMD_SX, ("Not waiting for AUTOSX ack\n"))
5645295Srandyf 		return;
5655295Srandyf 	}
5665295Srandyf 	ASSERT(type == SRN_TYPE_APM);
5675295Srandyf 	/* otherwise wait for acks */
5685295Srandyf restart:
5695295Srandyf 	/*
57010311SRandy.Fishel@Sun.COM 	 * We wait until all of the pending events are cleared.
5715295Srandyf 	 * We have to start over every time we do a cv_wait because
5725295Srandyf 	 * we give up the mutex and can be re-entered
5735295Srandyf 	 */
5745295Srandyf 	for (clone = 1; clone < SRN_MAX_CLONE; clone++) {
5755295Srandyf 		if (srn.srn_clones[clone] == 0 ||
5765295Srandyf 		    srn.srn_type[clone] != SRN_TYPE_APM)
5775295Srandyf 			continue;
57810311SRandy.Fishel@Sun.COM 		if (srn.srn_pending[clone].ae_type && !srn.srn_fault[clone]) {
5795295Srandyf 			PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, "
5805295Srandyf 			    "event %x\n", clone, event))
58110311SRandy.Fishel@Sun.COM 			if (cv_timedwait(&srn_clones_cv[clone],
58210311SRandy.Fishel@Sun.COM 			    &srn_clone_lock, ddi_get_lbolt() +
58310311SRandy.Fishel@Sun.COM 			    drv_usectohz(srn_timeout * 1000000)) == -1) {
58410311SRandy.Fishel@Sun.COM 				/*
58510311SRandy.Fishel@Sun.COM 				 * Client didn't respond, mark it as faulted
58610311SRandy.Fishel@Sun.COM 				 * and continue as if a regular signal.
58710311SRandy.Fishel@Sun.COM 				 */
58810311SRandy.Fishel@Sun.COM 				PMD(PMD_SX, ("srn_notify: clone %d did not "
58910311SRandy.Fishel@Sun.COM 				    "ack event %x\n", clone, event))
59010311SRandy.Fishel@Sun.COM 				cmn_err(CE_WARN, "srn_notify: clone %d did "
59110311SRandy.Fishel@Sun.COM 				    "not ack event %x\n", clone, event);
59210311SRandy.Fishel@Sun.COM 				srn.srn_fault[clone] = 1;
59310311SRandy.Fishel@Sun.COM 			}
5945295Srandyf 			goto restart;
5955295Srandyf 		}
5965295Srandyf 	}
5975295Srandyf 	PMD(PMD_SX, ("srn_notify done with %x\n", event))
5985295Srandyf }
599