12df1fe9cSrandyf /* 22df1fe9cSrandyf * CDDL HEADER START 32df1fe9cSrandyf * 42df1fe9cSrandyf * The contents of this file are subject to the terms of the 52df1fe9cSrandyf * Common Development and Distribution License (the "License"). 62df1fe9cSrandyf * You may not use this file except in compliance with the License. 72df1fe9cSrandyf * 82df1fe9cSrandyf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92df1fe9cSrandyf * or http://www.opensolaris.org/os/licensing. 102df1fe9cSrandyf * See the License for the specific language governing permissions 112df1fe9cSrandyf * and limitations under the License. 122df1fe9cSrandyf * 132df1fe9cSrandyf * When distributing Covered Code, include this CDDL HEADER in each 142df1fe9cSrandyf * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152df1fe9cSrandyf * If applicable, add the following below this CDDL HEADER, with the 162df1fe9cSrandyf * fields enclosed by brackets "[]" replaced with your own identifying 172df1fe9cSrandyf * information: Portions Copyright [yyyy] [name of copyright owner] 182df1fe9cSrandyf * 192df1fe9cSrandyf * CDDL HEADER END 202df1fe9cSrandyf */ 212df1fe9cSrandyf 222df1fe9cSrandyf /* 232fc97812SRandy Fishel * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 242df1fe9cSrandyf * Use is subject to license terms. 252df1fe9cSrandyf */ 262df1fe9cSrandyf 272df1fe9cSrandyf 282df1fe9cSrandyf /* 292df1fe9cSrandyf * srn Provide apm-like interfaces to Xorg 302df1fe9cSrandyf */ 312df1fe9cSrandyf 322df1fe9cSrandyf #include <sys/types.h> 332df1fe9cSrandyf #include <sys/errno.h> 342df1fe9cSrandyf #include <sys/modctl.h> 352df1fe9cSrandyf #include <sys/conf.h> /* driver flags and functions */ 362df1fe9cSrandyf #include <sys/open.h> /* OTYP_CHR definition */ 372df1fe9cSrandyf #include <sys/stat.h> /* S_IFCHR definition */ 382df1fe9cSrandyf #include <sys/pathname.h> /* name -> dev_info xlation */ 392df1fe9cSrandyf #include <sys/kmem.h> /* memory alloc stuff */ 402df1fe9cSrandyf #include <sys/debug.h> 412df1fe9cSrandyf #include <sys/pm.h> 422df1fe9cSrandyf #include <sys/ddi.h> 432df1fe9cSrandyf #include <sys/sunddi.h> 442df1fe9cSrandyf #include <sys/epm.h> 452df1fe9cSrandyf #include <sys/vfs.h> 462df1fe9cSrandyf #include <sys/mode.h> 472df1fe9cSrandyf #include <sys/mkdev.h> 482df1fe9cSrandyf #include <sys/promif.h> 492df1fe9cSrandyf #include <sys/consdev.h> 502df1fe9cSrandyf #include <sys/ddi_impldefs.h> 512df1fe9cSrandyf #include <sys/poll.h> 522df1fe9cSrandyf #include <sys/note.h> 532df1fe9cSrandyf #include <sys/taskq.h> 542df1fe9cSrandyf #include <sys/policy.h> 552df1fe9cSrandyf #include <sys/srn.h> 562df1fe9cSrandyf 572df1fe9cSrandyf /* 582df1fe9cSrandyf * Minor number is instance<<8 + clone minor from range 1-255; 592df1fe9cSrandyf * But only one will be allocated 602df1fe9cSrandyf */ 612df1fe9cSrandyf #define SRN_MINOR_TO_CLONE(minor) ((minor) & (SRN_MAX_CLONE - 1)) 622df1fe9cSrandyf #define SU 0x002 632df1fe9cSrandyf #define SG 0x004 642df1fe9cSrandyf 652df1fe9cSrandyf extern kmutex_t srn_clone_lock; /* protects srn_clones array */ 662df1fe9cSrandyf extern kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; 672df1fe9cSrandyf extern uint_t srn_poll_cnt[SRN_MAX_CLONE]; 682df1fe9cSrandyf 692df1fe9cSrandyf /* 702df1fe9cSrandyf * The soft state of the srn driver. Since there will only be 712df1fe9cSrandyf * one of these, just reference it through a static struct. 722df1fe9cSrandyf */ 732df1fe9cSrandyf static struct srnstate { 742df1fe9cSrandyf dev_info_t *srn_dip; /* ptr to our dev_info node */ 752df1fe9cSrandyf int srn_instance; /* for ddi_get_instance() */ 762df1fe9cSrandyf uchar_t srn_clones[SRN_MAX_CLONE]; /* unique opens */ 772df1fe9cSrandyf struct cred *srn_cred[SRN_MAX_CLONE]; /* cred for each open */ 782df1fe9cSrandyf int srn_type[SRN_MAX_CLONE]; /* type of handshake */ 792df1fe9cSrandyf int srn_delivered[SRN_MAX_CLONE]; 802df1fe9cSrandyf srn_event_info_t srn_pending[SRN_MAX_CLONE]; 812fc97812SRandy Fishel int srn_fault[SRN_MAX_CLONE]; 822df1fe9cSrandyf } srn = { NULL, -1}; 832df1fe9cSrandyf typedef struct srnstate *srn_state_t; 842df1fe9cSrandyf 852df1fe9cSrandyf kcondvar_t srn_clones_cv[SRN_MAX_CLONE]; 862df1fe9cSrandyf uint_t srn_poll_cnt[SRN_MAX_CLONE]; /* count of events for poll */ 872df1fe9cSrandyf int srn_apm_count; 882df1fe9cSrandyf int srn_autosx_count; 892fc97812SRandy Fishel /* Number of seconds to wait for clients to ack a poll */ 902fc97812SRandy Fishel int srn_timeout = 10; 912fc97812SRandy Fishel 922df1fe9cSrandyf struct pollhead srn_pollhead[SRN_MAX_CLONE]; 932df1fe9cSrandyf 942df1fe9cSrandyf static int srn_open(dev_t *, int, int, cred_t *); 952df1fe9cSrandyf static int srn_close(dev_t, int, int, cred_t *); 962df1fe9cSrandyf static int srn_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 972df1fe9cSrandyf static int srn_chpoll(dev_t, short, int, short *, struct pollhead **); 982df1fe9cSrandyf 992df1fe9cSrandyf static struct cb_ops srn_cb_ops = { 1002df1fe9cSrandyf srn_open, /* open */ 1012df1fe9cSrandyf srn_close, /* close */ 1022df1fe9cSrandyf nodev, /* strategy */ 1032df1fe9cSrandyf nodev, /* print */ 1042df1fe9cSrandyf nodev, /* dump */ 1052df1fe9cSrandyf nodev, /* read */ 1062df1fe9cSrandyf nodev, /* write */ 1072df1fe9cSrandyf srn_ioctl, /* ioctl */ 1082df1fe9cSrandyf nodev, /* devmap */ 1092df1fe9cSrandyf nodev, /* mmap */ 1102df1fe9cSrandyf nodev, /* segmap */ 1112df1fe9cSrandyf srn_chpoll, /* poll */ 1122df1fe9cSrandyf ddi_prop_op, /* prop_op */ 1132df1fe9cSrandyf NULL, /* streamtab */ 1142df1fe9cSrandyf D_NEW | D_MP /* driver compatibility flag */ 1152df1fe9cSrandyf }; 1162df1fe9cSrandyf 1172df1fe9cSrandyf static int srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 1182df1fe9cSrandyf void **result); 1192df1fe9cSrandyf static int srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 1202df1fe9cSrandyf static int srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 1212df1fe9cSrandyf static void srn_notify(int type, int event); 1222df1fe9cSrandyf 1232df1fe9cSrandyf static struct dev_ops srn_ops = { 1242df1fe9cSrandyf DEVO_REV, /* devo_rev */ 1252df1fe9cSrandyf 0, /* refcnt */ 1262df1fe9cSrandyf srn_getinfo, /* info */ 1272df1fe9cSrandyf nulldev, /* identify */ 1282df1fe9cSrandyf nulldev, /* probe */ 1292df1fe9cSrandyf srn_attach, /* attach */ 1302df1fe9cSrandyf srn_detach, /* detach */ 1312df1fe9cSrandyf nodev, /* reset */ 1322df1fe9cSrandyf &srn_cb_ops, /* driver operations */ 1332df1fe9cSrandyf NULL, /* bus operations */ 13419397407SSherry Moore NULL, /* power */ 13519397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 1362df1fe9cSrandyf }; 1372df1fe9cSrandyf 1382df1fe9cSrandyf static struct modldrv modldrv = { 1392df1fe9cSrandyf &mod_driverops, 14019397407SSherry Moore "srn driver", 1412df1fe9cSrandyf &srn_ops 1422df1fe9cSrandyf }; 1432df1fe9cSrandyf 1442df1fe9cSrandyf static struct modlinkage modlinkage = { 1452df1fe9cSrandyf MODREV_1, &modldrv, 0 1462df1fe9cSrandyf }; 1472df1fe9cSrandyf 1482df1fe9cSrandyf /* Local functions */ 1492df1fe9cSrandyf 1502df1fe9cSrandyf int 1512df1fe9cSrandyf _init(void) 1522df1fe9cSrandyf { 1532df1fe9cSrandyf return (mod_install(&modlinkage)); 1542df1fe9cSrandyf } 1552df1fe9cSrandyf 1562df1fe9cSrandyf int 1572df1fe9cSrandyf _fini(void) 1582df1fe9cSrandyf { 1592df1fe9cSrandyf return (mod_remove(&modlinkage)); 1602df1fe9cSrandyf } 1612df1fe9cSrandyf 1622df1fe9cSrandyf int 1632df1fe9cSrandyf _info(struct modinfo *modinfop) 1642df1fe9cSrandyf { 1652df1fe9cSrandyf return (mod_info(&modlinkage, modinfop)); 1662df1fe9cSrandyf } 1672df1fe9cSrandyf 1682df1fe9cSrandyf static int 1692df1fe9cSrandyf srn_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1702df1fe9cSrandyf { 1712df1fe9cSrandyf int i; 1722df1fe9cSrandyf extern void (*srn_signal)(int, int); 1732df1fe9cSrandyf 1742df1fe9cSrandyf switch (cmd) { 1752df1fe9cSrandyf 1762df1fe9cSrandyf case DDI_ATTACH: 1772df1fe9cSrandyf if (srn.srn_instance != -1) /* Only allow one instance */ 1782df1fe9cSrandyf return (DDI_FAILURE); 1792df1fe9cSrandyf srn.srn_instance = ddi_get_instance(dip); 1802df1fe9cSrandyf if (ddi_create_minor_node(dip, "srn", S_IFCHR, 1812df1fe9cSrandyf (srn.srn_instance << 8) + 0, DDI_PSEUDO, 0) 1822df1fe9cSrandyf != DDI_SUCCESS) { 1832df1fe9cSrandyf return (DDI_FAILURE); 1842df1fe9cSrandyf } 1852df1fe9cSrandyf srn.srn_dip = dip; /* srn_init and getinfo depend on it */ 1862df1fe9cSrandyf 1872df1fe9cSrandyf for (i = 0; i < SRN_MAX_CLONE; i++) 1882df1fe9cSrandyf cv_init(&srn_clones_cv[i], NULL, CV_DEFAULT, NULL); 1892df1fe9cSrandyf 1902df1fe9cSrandyf srn.srn_instance = ddi_get_instance(dip); 1912df1fe9cSrandyf mutex_enter(&srn_clone_lock); 1922df1fe9cSrandyf srn_signal = srn_notify; 1932df1fe9cSrandyf mutex_exit(&srn_clone_lock); 1942df1fe9cSrandyf ddi_report_dev(dip); 1952df1fe9cSrandyf return (DDI_SUCCESS); 1962df1fe9cSrandyf 1972df1fe9cSrandyf default: 1982df1fe9cSrandyf return (DDI_FAILURE); 1992df1fe9cSrandyf } 2002df1fe9cSrandyf } 2012df1fe9cSrandyf 2022df1fe9cSrandyf /* ARGSUSED */ 2032df1fe9cSrandyf static int 2042df1fe9cSrandyf srn_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2052df1fe9cSrandyf { 2062df1fe9cSrandyf int i; 2072df1fe9cSrandyf extern int srn_inuse; 2082df1fe9cSrandyf extern void (*srn_signal)(int, int); 2092df1fe9cSrandyf 2102df1fe9cSrandyf switch (cmd) { 2112df1fe9cSrandyf case DDI_DETACH: 2122df1fe9cSrandyf 2132df1fe9cSrandyf mutex_enter(&srn_clone_lock); 2142df1fe9cSrandyf while (srn_inuse) { 2152df1fe9cSrandyf mutex_exit(&srn_clone_lock); 2162df1fe9cSrandyf delay(1); 2172df1fe9cSrandyf mutex_enter(&srn_clone_lock); 2182df1fe9cSrandyf } 2192df1fe9cSrandyf srn_signal = NULL; 2202df1fe9cSrandyf mutex_exit(&srn_clone_lock); 2212df1fe9cSrandyf 2222df1fe9cSrandyf for (i = 0; i < SRN_MAX_CLONE; i++) 2232df1fe9cSrandyf cv_destroy(&srn_clones_cv[i]); 2242df1fe9cSrandyf 2252df1fe9cSrandyf ddi_remove_minor_node(dip, NULL); 2262df1fe9cSrandyf srn.srn_instance = -1; 2272df1fe9cSrandyf return (DDI_SUCCESS); 2282df1fe9cSrandyf 2292df1fe9cSrandyf default: 2302df1fe9cSrandyf return (DDI_FAILURE); 2312df1fe9cSrandyf } 2322df1fe9cSrandyf } 2332df1fe9cSrandyf 2342df1fe9cSrandyf 2352df1fe9cSrandyf #ifdef DEBUG 2362df1fe9cSrandyf char *srn_cmd_string; 2372df1fe9cSrandyf int srn_cmd; 2382df1fe9cSrandyf #endif 2392df1fe9cSrandyf 2402df1fe9cSrandyf /* 2412df1fe9cSrandyf * Returns true if permission granted by credentials 2422df1fe9cSrandyf * XXX 2432df1fe9cSrandyf */ 2442df1fe9cSrandyf static int 2452df1fe9cSrandyf srn_perms(int perm, cred_t *cr) 2462df1fe9cSrandyf { 2472df1fe9cSrandyf if ((perm & SU) && secpolicy_power_mgmt(cr) == 0) /* privileged? */ 2482df1fe9cSrandyf return (1); 2492df1fe9cSrandyf if ((perm & SG) && (crgetgid(cr) == 0)) /* group 0 is ok */ 2502df1fe9cSrandyf return (1); 2512df1fe9cSrandyf return (0); 2522df1fe9cSrandyf } 2532df1fe9cSrandyf 2542df1fe9cSrandyf static int 2552df1fe9cSrandyf srn_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 2562df1fe9cSrandyf struct pollhead **phpp) 2572df1fe9cSrandyf { 2582fc97812SRandy Fishel extern struct pollhead srn_pollhead[]; 2592df1fe9cSrandyf int clone; 2602df1fe9cSrandyf 2612df1fe9cSrandyf clone = SRN_MINOR_TO_CLONE(getminor(dev)); 2622df1fe9cSrandyf if ((events & (POLLIN | POLLRDNORM)) && srn_poll_cnt[clone]) { 2632df1fe9cSrandyf *reventsp |= (POLLIN | POLLRDNORM); 2642df1fe9cSrandyf } else { 2652df1fe9cSrandyf *reventsp = 0; 2662df1fe9cSrandyf if (!anyyet) { 2672df1fe9cSrandyf *phpp = &srn_pollhead[clone]; 2682df1fe9cSrandyf } 2692df1fe9cSrandyf } 2702df1fe9cSrandyf return (0); 2712df1fe9cSrandyf } 2722df1fe9cSrandyf 2732df1fe9cSrandyf /*ARGSUSED*/ 2742df1fe9cSrandyf static int 2752df1fe9cSrandyf srn_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 2762df1fe9cSrandyf { 2772df1fe9cSrandyf dev_t dev; 2782df1fe9cSrandyf int instance; 2792df1fe9cSrandyf 2802df1fe9cSrandyf switch (infocmd) { 2812df1fe9cSrandyf case DDI_INFO_DEVT2DEVINFO: 2822df1fe9cSrandyf if (srn.srn_instance == -1) 2832df1fe9cSrandyf return (DDI_FAILURE); 2842df1fe9cSrandyf *result = srn.srn_dip; 2852df1fe9cSrandyf return (DDI_SUCCESS); 2862df1fe9cSrandyf 2872df1fe9cSrandyf case DDI_INFO_DEVT2INSTANCE: 2882df1fe9cSrandyf dev = (dev_t)arg; 2892df1fe9cSrandyf instance = getminor(dev) >> 8; 2902df1fe9cSrandyf *result = (void *)(uintptr_t)instance; 2912df1fe9cSrandyf return (DDI_SUCCESS); 2922df1fe9cSrandyf 2932df1fe9cSrandyf default: 2942df1fe9cSrandyf return (DDI_FAILURE); 2952df1fe9cSrandyf } 2962df1fe9cSrandyf } 2972df1fe9cSrandyf 2982df1fe9cSrandyf 2992df1fe9cSrandyf /*ARGSUSED1*/ 3002df1fe9cSrandyf static int 3012df1fe9cSrandyf srn_open(dev_t *devp, int flag, int otyp, cred_t *cr) 3022df1fe9cSrandyf { 3032df1fe9cSrandyf int clone; 3042df1fe9cSrandyf 3052df1fe9cSrandyf if (otyp != OTYP_CHR) 3062df1fe9cSrandyf return (EINVAL); 3072df1fe9cSrandyf 3082df1fe9cSrandyf mutex_enter(&srn_clone_lock); 3092df1fe9cSrandyf for (clone = 1; clone < SRN_MAX_CLONE - 1; clone++) 3102df1fe9cSrandyf if (!srn.srn_clones[clone]) 3112df1fe9cSrandyf break; 3122df1fe9cSrandyf 3132df1fe9cSrandyf if (clone == SRN_MAX_CLONE) { 3142df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3152df1fe9cSrandyf return (ENXIO); 3162df1fe9cSrandyf } 3172df1fe9cSrandyf srn.srn_cred[clone] = cr; 3182df1fe9cSrandyf ASSERT(srn_apm_count >= 0); 3192df1fe9cSrandyf srn_apm_count++; 3202df1fe9cSrandyf srn.srn_type[clone] = SRN_TYPE_APM; 3212df1fe9cSrandyf crhold(cr); 3222df1fe9cSrandyf 3232df1fe9cSrandyf *devp = makedevice(getmajor(*devp), (srn.srn_instance << 8) + 3242df1fe9cSrandyf clone); 3252df1fe9cSrandyf srn.srn_clones[clone] = 1; 3262df1fe9cSrandyf srn.srn_cred[clone] = cr; 3272df1fe9cSrandyf crhold(cr); 3282df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3292df1fe9cSrandyf PMD(PMD_SX, ("srn open OK\n")) 3302df1fe9cSrandyf return (0); 3312df1fe9cSrandyf } 3322df1fe9cSrandyf 3332df1fe9cSrandyf /*ARGSUSED1*/ 3342df1fe9cSrandyf static int 3352df1fe9cSrandyf srn_close(dev_t dev, int flag, int otyp, cred_t *cr) 3362df1fe9cSrandyf { 3372df1fe9cSrandyf int clone; 3382df1fe9cSrandyf 3392df1fe9cSrandyf if (otyp != OTYP_CHR) 3402df1fe9cSrandyf return (EINVAL); 3412df1fe9cSrandyf 3422df1fe9cSrandyf clone = SRN_MINOR_TO_CLONE(getminor(dev)); 3432df1fe9cSrandyf PMD(PMD_SX, ("srn_close: minor %x, clone %x\n", getminor(dev), 3442df1fe9cSrandyf clone)) 3452df1fe9cSrandyf mutex_enter(&srn_clone_lock); 3462df1fe9cSrandyf crfree(srn.srn_cred[clone]); 3472df1fe9cSrandyf srn.srn_cred[clone] = 0; 3482df1fe9cSrandyf srn_poll_cnt[clone] = 0; 3492fc97812SRandy Fishel srn.srn_fault[clone] = 0; 3502df1fe9cSrandyf if (srn.srn_pending[clone].ae_type || srn.srn_delivered[clone]) { 3512df1fe9cSrandyf srn.srn_pending[clone].ae_type = 0; 3522df1fe9cSrandyf srn.srn_delivered[clone] = 0; 3532df1fe9cSrandyf cv_signal(&srn_clones_cv[clone]); 3542df1fe9cSrandyf } 3552df1fe9cSrandyf switch (srn.srn_type[clone]) { 3562df1fe9cSrandyf case SRN_TYPE_AUTOSX: 3572df1fe9cSrandyf ASSERT(srn_autosx_count); 3582df1fe9cSrandyf srn_autosx_count--; 3592df1fe9cSrandyf break; 3602df1fe9cSrandyf case SRN_TYPE_APM: 3612df1fe9cSrandyf ASSERT(srn_apm_count); 3622df1fe9cSrandyf srn_apm_count--; 3632df1fe9cSrandyf break; 3642df1fe9cSrandyf default: 3652df1fe9cSrandyf ASSERT(0); 3662df1fe9cSrandyf return (EINVAL); 3672df1fe9cSrandyf } 3682df1fe9cSrandyf srn.srn_clones[clone] = 0; 3692df1fe9cSrandyf mutex_exit(&srn_clone_lock); 3702df1fe9cSrandyf return (0); 3712df1fe9cSrandyf } 3722df1fe9cSrandyf 3732df1fe9cSrandyf /*ARGSUSED*/ 3742df1fe9cSrandyf static int 3752df1fe9cSrandyf srn_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval_p) 3762df1fe9cSrandyf { 3772df1fe9cSrandyf int clone = SRN_MINOR_TO_CLONE(getminor(dev)); 3782df1fe9cSrandyf 3792df1fe9cSrandyf PMD(PMD_SX, ("ioctl: %x: begin\n", cmd)) 3802df1fe9cSrandyf 3812df1fe9cSrandyf switch (cmd) { 3822df1fe9cSrandyf case SRN_IOC_NEXTEVENT: 3832df1fe9cSrandyf case SRN_IOC_SUSPEND: 3842df1fe9cSrandyf case SRN_IOC_RESUME: 3852df1fe9cSrandyf case SRN_IOC_AUTOSX: 3862df1fe9cSrandyf break; 3872df1fe9cSrandyf default: 3882df1fe9cSrandyf return (ENOTTY); 3892df1fe9cSrandyf } 3902df1fe9cSrandyf 3912df1fe9cSrandyf if (!srn_perms(SU | SG, srn.srn_cred[clone])) { 3922df1fe9cSrandyf return (EPERM); 3932df1fe9cSrandyf } 3942df1fe9cSrandyf switch (cmd) { 3952df1fe9cSrandyf case SRN_IOC_AUTOSX: 3962df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_AUTOSX entered\n")) 3972df1fe9cSrandyf mutex_enter(&srn_clone_lock); 3982df1fe9cSrandyf if (!srn.srn_clones[clone]) { 3992df1fe9cSrandyf PMD(PMD_SX, (" ioctl !srn_clones--EINVAL\n")) 4002df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4012df1fe9cSrandyf return (EINVAL); 4022df1fe9cSrandyf } 4032df1fe9cSrandyf if (srn.srn_pending[clone].ae_type) { 4042df1fe9cSrandyf PMD(PMD_SX, ("AUTOSX while pending--EBUSY\n")) 4052df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4062df1fe9cSrandyf return (EBUSY); 4072df1fe9cSrandyf } 4082df1fe9cSrandyf if (srn.srn_type[clone] == SRN_TYPE_AUTOSX) { 4092df1fe9cSrandyf PMD(PMD_SX, ("AUTOSX already--EBUSY\n")) 4102df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4112df1fe9cSrandyf return (EBUSY); 4122df1fe9cSrandyf } 4132df1fe9cSrandyf ASSERT(srn.srn_type[clone] == SRN_TYPE_APM); 4142df1fe9cSrandyf srn.srn_type[clone] = SRN_TYPE_AUTOSX; 4152fc97812SRandy Fishel srn.srn_fault[clone] = 0; 4162df1fe9cSrandyf srn_apm_count--; 4172df1fe9cSrandyf ASSERT(srn_apm_count >= 0); 4182df1fe9cSrandyf ASSERT(srn_autosx_count >= 0); 4192df1fe9cSrandyf srn_autosx_count++; 4202df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4212df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_AUTOSX returns success\n")) 4222df1fe9cSrandyf return (0); 4232df1fe9cSrandyf 4242df1fe9cSrandyf case SRN_IOC_NEXTEVENT: 4252df1fe9cSrandyf /* 4262df1fe9cSrandyf * return the next suspend or resume event; there should 4272df1fe9cSrandyf * be one, cause we only get called if we've signalled a 4282df1fe9cSrandyf * poll data completion 4292df1fe9cSrandyf * then wake up the kernel thread sleeping for the delivery 4302df1fe9cSrandyf */ 4312df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT entered\n")) 4322fc97812SRandy Fishel if (srn.srn_fault[clone]) { 4332fc97812SRandy Fishel PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d fault " 4342fc97812SRandy Fishel "cleared\n", clone)) 4352fc97812SRandy Fishel srn.srn_fault[clone] = 0; 4362fc97812SRandy Fishel } 4372df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4382df1fe9cSrandyf if (srn_poll_cnt[clone] == 0) { 4392df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4402df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d " 4412df1fe9cSrandyf "EWOULDBLOCK\n", clone)) 4422df1fe9cSrandyf return (EWOULDBLOCK); 4432df1fe9cSrandyf } 4442df1fe9cSrandyf ASSERT(srn.srn_pending[clone].ae_type); 4452df1fe9cSrandyf if (ddi_copyout(&srn.srn_pending[clone], (void *)arg, 4462df1fe9cSrandyf sizeof (srn_event_info_t), mode) != 0) { 4472df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4482df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d EFAULT\n", 4492df1fe9cSrandyf clone)) 4502df1fe9cSrandyf return (EFAULT); 4512df1fe9cSrandyf } 4522df1fe9cSrandyf if (srn.srn_type[clone] == SRN_TYPE_APM) 4532df1fe9cSrandyf srn.srn_delivered[clone] = 4542df1fe9cSrandyf srn.srn_pending[clone].ae_type; 4552df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_NEXTEVENT clone %d delivered %x\n", 4562df1fe9cSrandyf clone, srn.srn_pending[clone].ae_type)) 4572df1fe9cSrandyf srn_poll_cnt[clone] = 0; 4582df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4592df1fe9cSrandyf return (0); 4602df1fe9cSrandyf 4612df1fe9cSrandyf case SRN_IOC_SUSPEND: 4622df1fe9cSrandyf /* ack suspend */ 4632df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_SUSPEND entered clone %d\n", clone)) 4642fc97812SRandy Fishel if (srn.srn_fault[clone]) { 4652fc97812SRandy Fishel PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d fault " 4662fc97812SRandy Fishel "cleared\n", clone)) 4672fc97812SRandy Fishel srn.srn_fault[clone] = 0; 4682fc97812SRandy Fishel } 4692df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4702df1fe9cSrandyf if (srn.srn_delivered[clone] != SRN_SUSPEND_REQ) { 4712df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4722df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_SUSPEND EINVAL\n")) 4732df1fe9cSrandyf return (EINVAL); 4742df1fe9cSrandyf } 4752df1fe9cSrandyf srn.srn_delivered[clone] = 0; 4762df1fe9cSrandyf srn.srn_pending[clone].ae_type = 0; 4772df1fe9cSrandyf /* notify the kernel suspend thread to continue */ 4782df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_SUSPEND clone %d ok\n", clone)) 4792df1fe9cSrandyf cv_signal(&srn_clones_cv[clone]); 4802df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4812df1fe9cSrandyf return (0); 4822df1fe9cSrandyf 4832df1fe9cSrandyf case SRN_IOC_RESUME: 4842df1fe9cSrandyf /* ack resume */ 4852df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_RESUME entered clone %d\n", clone)) 4862fc97812SRandy Fishel if (srn.srn_fault[clone]) { 4872fc97812SRandy Fishel PMD(PMD_SX, ("SRN_IOC_RESUME clone %d fault " 4882fc97812SRandy Fishel "cleared\n", clone)) 4892fc97812SRandy Fishel srn.srn_fault[clone] = 0; 4902fc97812SRandy Fishel } 4912df1fe9cSrandyf mutex_enter(&srn_clone_lock); 4922df1fe9cSrandyf if (srn.srn_delivered[clone] != SRN_NORMAL_RESUME) { 4932df1fe9cSrandyf mutex_exit(&srn_clone_lock); 4942df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_RESUME EINVAL\n")) 4952df1fe9cSrandyf return (EINVAL); 4962df1fe9cSrandyf } 4972df1fe9cSrandyf srn.srn_delivered[clone] = 0; 4982df1fe9cSrandyf srn.srn_pending[clone].ae_type = 0; 4992df1fe9cSrandyf /* notify the kernel resume thread to continue */ 5002df1fe9cSrandyf PMD(PMD_SX, ("SRN_IOC_RESUME ok for clone %d\n", clone)) 5012df1fe9cSrandyf cv_signal(&srn_clones_cv[clone]); 5022df1fe9cSrandyf mutex_exit(&srn_clone_lock); 5032df1fe9cSrandyf return (0); 5042df1fe9cSrandyf 5052df1fe9cSrandyf default: 5062df1fe9cSrandyf PMD(PMD_SX, ("srn_ioctl unknown cmd EINVAL\n")) 5072df1fe9cSrandyf return (EINVAL); 5082df1fe9cSrandyf } 5092df1fe9cSrandyf } 5102df1fe9cSrandyf /* 5112df1fe9cSrandyf * A very simple handshake with the srn driver, 5122df1fe9cSrandyf * only one outstanding event at a time. 5132df1fe9cSrandyf * The OS delivers the event and depending on type, 5142df1fe9cSrandyf * either blocks waiting for the ack, or drives on 5152df1fe9cSrandyf */ 5162df1fe9cSrandyf void 5172df1fe9cSrandyf srn_notify(int type, int event) 5182df1fe9cSrandyf { 5192df1fe9cSrandyf int clone, count; 5202df1fe9cSrandyf PMD(PMD_SX, ("srn_notify entered with type %d, event 0x%x\n", 5212df1fe9cSrandyf type, event)); 5222df1fe9cSrandyf ASSERT(mutex_owned(&srn_clone_lock)); 5232df1fe9cSrandyf switch (type) { 5242df1fe9cSrandyf case SRN_TYPE_APM: 5252df1fe9cSrandyf if (srn_apm_count == 0) { 5262df1fe9cSrandyf PMD(PMD_SX, ("no apm types\n")) 5272df1fe9cSrandyf return; 5282df1fe9cSrandyf } 5292df1fe9cSrandyf count = srn_apm_count; 5302df1fe9cSrandyf break; 5312df1fe9cSrandyf case SRN_TYPE_AUTOSX: 5322df1fe9cSrandyf if (srn_autosx_count == 0) { 5332df1fe9cSrandyf PMD(PMD_SX, ("no autosx types\n")) 5342df1fe9cSrandyf return; 5352df1fe9cSrandyf } 5362df1fe9cSrandyf count = srn_autosx_count; 5372df1fe9cSrandyf break; 5382df1fe9cSrandyf default: 5392df1fe9cSrandyf ASSERT(0); 5402df1fe9cSrandyf break; 5412df1fe9cSrandyf } 5422df1fe9cSrandyf ASSERT(count > 0); 5432df1fe9cSrandyf PMD(PMD_SX, ("count %d\n", count)) 5442df1fe9cSrandyf for (clone = 0; clone < SRN_MAX_CLONE; clone++) { 5452df1fe9cSrandyf if (srn.srn_type[clone] == type) { 5462fc97812SRandy Fishel #ifdef DEBUG 547*b785f896SRandy Fishel if (type == SRN_TYPE_APM && !srn.srn_fault[clone]) { 5482df1fe9cSrandyf ASSERT(srn.srn_pending[clone].ae_type == 0); 5492df1fe9cSrandyf ASSERT(srn_poll_cnt[clone] == 0); 5502df1fe9cSrandyf ASSERT(srn.srn_delivered[clone] == 0); 5512df1fe9cSrandyf } 5522fc97812SRandy Fishel #endif 5532df1fe9cSrandyf srn.srn_pending[clone].ae_type = event; 5542df1fe9cSrandyf srn_poll_cnt[clone] = 1; 5552df1fe9cSrandyf PMD(PMD_SX, ("pollwake %d\n", clone)) 5562df1fe9cSrandyf pollwakeup(&srn_pollhead[clone], (POLLRDNORM | POLLIN)); 5572df1fe9cSrandyf count--; 5582df1fe9cSrandyf if (count == 0) 5592df1fe9cSrandyf break; 5602df1fe9cSrandyf } 5612df1fe9cSrandyf } 5622df1fe9cSrandyf if (type == SRN_TYPE_AUTOSX) { /* we don't wait */ 5632df1fe9cSrandyf PMD(PMD_SX, ("Not waiting for AUTOSX ack\n")) 5642df1fe9cSrandyf return; 5652df1fe9cSrandyf } 5662df1fe9cSrandyf ASSERT(type == SRN_TYPE_APM); 5672df1fe9cSrandyf /* otherwise wait for acks */ 5682df1fe9cSrandyf restart: 5692df1fe9cSrandyf /* 5702fc97812SRandy Fishel * We wait until all of the pending events are cleared. 5712df1fe9cSrandyf * We have to start over every time we do a cv_wait because 5722df1fe9cSrandyf * we give up the mutex and can be re-entered 5732df1fe9cSrandyf */ 5742df1fe9cSrandyf for (clone = 1; clone < SRN_MAX_CLONE; clone++) { 5752df1fe9cSrandyf if (srn.srn_clones[clone] == 0 || 5762df1fe9cSrandyf srn.srn_type[clone] != SRN_TYPE_APM) 5772df1fe9cSrandyf continue; 5782fc97812SRandy Fishel if (srn.srn_pending[clone].ae_type && !srn.srn_fault[clone]) { 5792df1fe9cSrandyf PMD(PMD_SX, ("srn_notify waiting for ack for clone %d, " 5802df1fe9cSrandyf "event %x\n", clone, event)) 5812fc97812SRandy Fishel if (cv_timedwait(&srn_clones_cv[clone], 5822fc97812SRandy Fishel &srn_clone_lock, ddi_get_lbolt() + 5832fc97812SRandy Fishel drv_usectohz(srn_timeout * 1000000)) == -1) { 5842fc97812SRandy Fishel /* 5852fc97812SRandy Fishel * Client didn't respond, mark it as faulted 5862fc97812SRandy Fishel * and continue as if a regular signal. 5872fc97812SRandy Fishel */ 5882fc97812SRandy Fishel PMD(PMD_SX, ("srn_notify: clone %d did not " 5892fc97812SRandy Fishel "ack event %x\n", clone, event)) 5902fc97812SRandy Fishel cmn_err(CE_WARN, "srn_notify: clone %d did " 5912fc97812SRandy Fishel "not ack event %x\n", clone, event); 5922fc97812SRandy Fishel srn.srn_fault[clone] = 1; 5932fc97812SRandy Fishel } 5942df1fe9cSrandyf goto restart; 5952df1fe9cSrandyf } 5962df1fe9cSrandyf } 5972df1fe9cSrandyf PMD(PMD_SX, ("srn_notify done with %x\n", event)) 5982df1fe9cSrandyf } 599