13941Svenki /*
23941Svenki * CDDL HEADER START
33941Svenki *
43941Svenki * The contents of this file are subject to the terms of the
53941Svenki * Common Development and Distribution License (the "License").
63941Svenki * You may not use this file except in compliance with the License.
73941Svenki *
83941Svenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93941Svenki * or http://www.opensolaris.org/os/licensing.
103941Svenki * See the License for the specific language governing permissions
113941Svenki * and limitations under the License.
123941Svenki *
133941Svenki * When distributing Covered Code, include this CDDL HEADER in each
143941Svenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153941Svenki * If applicable, add the following below this CDDL HEADER, with the
163941Svenki * fields enclosed by brackets "[]" replaced with your own identifying
173941Svenki * information: Portions Copyright [yyyy] [name of copyright owner]
183941Svenki *
193941Svenki * CDDL HEADER END
203941Svenki */
213941Svenki /*
22*12392SMichael.Bergknoff@Oracle.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
233941Svenki */
243941Svenki
253941Svenki
263941Svenki /*
273941Svenki * sun4v domain services SNMP driver
283941Svenki */
293941Svenki
303941Svenki #include <sys/types.h>
313941Svenki #include <sys/file.h>
323941Svenki #include <sys/errno.h>
333941Svenki #include <sys/open.h>
343941Svenki #include <sys/cred.h>
353941Svenki #include <sys/uio.h>
363941Svenki #include <sys/stat.h>
373941Svenki #include <sys/ksynch.h>
383941Svenki #include <sys/modctl.h>
393941Svenki #include <sys/conf.h>
403941Svenki #include <sys/devops.h>
413941Svenki #include <sys/debug.h>
423941Svenki #include <sys/cmn_err.h>
433941Svenki #include <sys/ddi.h>
443941Svenki #include <sys/sunddi.h>
453941Svenki #include <sys/ds.h>
463941Svenki #include <sys/ds_snmp.h>
473941Svenki
483941Svenki #define DS_SNMP_NAME "ds_snmp"
493941Svenki #define DS_SNMP_MAX_OPENS 256
503941Svenki #define DS_BITS_IN_UINT64 64
513941Svenki #define DS_MINOR_POOL_SZ (DS_SNMP_MAX_OPENS / DS_BITS_IN_UINT64)
523941Svenki #define DS_SNMP_MINOR_SHIFT 56
533941Svenki #define DS_SNMP_DBG if (ds_snmp_debug) printf
543941Svenki
553941Svenki typedef struct {
563941Svenki uint64_t seq_num;
573941Svenki uint64_t type;
583941Svenki } ds_snmp_msg_t;
593941Svenki
603941Svenki typedef enum {
613941Svenki DS_SNMP_REQUEST = 0,
623941Svenki DS_SNMP_REPLY = 1,
633941Svenki DS_SNMP_ERROR = 2
643941Svenki } ds_snmp_msg_type_t;
653941Svenki
663941Svenki typedef enum {
673941Svenki DS_SNMP_READY = 0x0,
683941Svenki DS_SNMP_REQUESTED = 0x1,
693941Svenki DS_SNMP_DATA_AVL = 0x2,
703941Svenki DS_SNMP_DATA_ERR = 0x3
713941Svenki } ds_snmp_flags_t;
723941Svenki
733941Svenki /*
743941Svenki * The single mutex 'lock' protects all the SNMP/DS variables in the state
753941Svenki * structure.
763941Svenki *
773941Svenki * The condition variable 'state_cv' helps serialize write() calls for a
783941Svenki * single descriptor. When write() is called, it sets a flag to indicate
793941Svenki * that an SNMP request has been made to the agent. No more write()'s on
803941Svenki * the same open descriptor will be allowed until this flag is cleared via
813941Svenki * a matching read(), where the requested packet is consumed on arrival.
823941Svenki * Read() then wakes up any waiters blocked in write() for sending the next
833941Svenki * SNMP request to the agent.
843941Svenki */
853941Svenki typedef struct ds_snmp_state {
863941Svenki dev_info_t *dip;
873941Svenki int instance;
883941Svenki dev_t dev;
893941Svenki
903941Svenki /* SNMP/DS */
913941Svenki kmutex_t lock;
923941Svenki kcondvar_t state_cv;
933941Svenki ds_snmp_flags_t state;
943941Svenki void *data;
953941Svenki size_t data_len;
963941Svenki uint64_t req_id;
973941Svenki uint64_t last_req_id;
983941Svenki uint64_t gencount;
993941Svenki boolean_t sc_reset;
1003941Svenki } ds_snmp_state_t;
1013941Svenki
1023941Svenki
1033941Svenki static uint_t ds_snmp_debug = 0;
1043941Svenki static void *ds_snmp_statep = NULL;
1053941Svenki static int ds_snmp_instance = -1;
1063941Svenki static dev_info_t *ds_snmp_devi = NULL;
1073941Svenki
1083941Svenki /*
1093941Svenki * The ds_snmp_lock mutex protects the following data global to the
1103941Svenki * driver.
1113941Svenki *
1123941Svenki * The ds_snmp_service_cv condition variable is used to resolve the
1133941Svenki * potential race between the registration of snmp service via a
1143941Svenki * ds_cap_init() in attach(), the acknowledgement of this registration
1153941Svenki * at a later time in ds_snmp_reg_handler(), and a possible open() at
1163941Svenki * a time inbetween. The ds_snmp_has_service and ds_snmp_handle are
1173941Svenki * used to indicate whether the registration acknowledgement has happened
1183941Svenki * or not.
1193941Svenki *
1203941Svenki * The ds_snmp_minor_pool[] is a bitmask to allocate and keep track of
1213941Svenki * minor numbers dynamically.
1223941Svenki */
1233941Svenki static kmutex_t ds_snmp_lock;
1243941Svenki static kcondvar_t ds_snmp_service_cv;
1253941Svenki static int ds_snmp_has_service = B_FALSE;
1263941Svenki static ds_svc_hdl_t ds_snmp_handle = DS_INVALID_HDL;
1273941Svenki static uint64_t ds_snmp_minor_pool[DS_MINOR_POOL_SZ]; /* bitmask */
1283941Svenki static int ds_snmp_num_opens = 0;
1293941Svenki
1303941Svenki static int ds_snmp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
1313941Svenki static int ds_snmp_attach(dev_info_t *, ddi_attach_cmd_t);
1323941Svenki static int ds_snmp_detach(dev_info_t *, ddi_detach_cmd_t);
1333941Svenki static int ds_snmp_open(dev_t *, int, int, cred_t *);
1343941Svenki static int ds_snmp_close(dev_t, int, int, cred_t *);
1353941Svenki static int ds_snmp_read(dev_t, struct uio *, cred_t *);
1363941Svenki static int ds_snmp_write(dev_t, struct uio *, cred_t *);
1373941Svenki static int ds_snmp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1383941Svenki
1393941Svenki /*
1403941Svenki * DS Callbacks
1413941Svenki */
1423941Svenki static void ds_snmp_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
1433941Svenki static void ds_snmp_unreg_handler(ds_cb_arg_t arg);
1443941Svenki static void ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
1453941Svenki
1463941Svenki /*
1473941Svenki * SNMP DS capability registration
1483941Svenki */
1493941Svenki static ds_ver_t ds_snmp_ver_1_0 = { 1, 0 };
1503941Svenki static ds_capability_t ds_snmp_cap = {
1513941Svenki "snmp",
1523941Svenki &ds_snmp_ver_1_0,
1533941Svenki 1
1543941Svenki };
1553941Svenki
1563941Svenki /*
1573941Svenki * SNMP DS Client callback vector
1583941Svenki */
1593941Svenki static ds_clnt_ops_t ds_snmp_ops = {
1603941Svenki ds_snmp_reg_handler, /* ds_reg_cb */
1613941Svenki ds_snmp_unreg_handler, /* ds_unreg_cb */
1623941Svenki ds_snmp_data_handler, /* ds_data_cb */
1633941Svenki NULL /* cb_arg */
1643941Svenki };
1653941Svenki
1663941Svenki /*
1673941Svenki * DS SNMP driver Ops Vector
1683941Svenki */
1693941Svenki static struct cb_ops ds_snmp_cb_ops = {
1703941Svenki ds_snmp_open, /* cb_open */
1713941Svenki ds_snmp_close, /* cb_close */
1723941Svenki nodev, /* cb_strategy */
1733941Svenki nodev, /* cb_print */
1743941Svenki nodev, /* cb_dump */
1753941Svenki ds_snmp_read, /* cb_read */
1763941Svenki ds_snmp_write, /* cb_write */
1773941Svenki ds_snmp_ioctl, /* cb_ioctl */
1783941Svenki nodev, /* cb_devmap */
1793941Svenki nodev, /* cb_mmap */
1803941Svenki nodev, /* cb_segmap */
1813941Svenki nochpoll, /* cb_chpoll */
1823941Svenki ddi_prop_op, /* cb_prop_op */
1833941Svenki (struct streamtab *)NULL, /* cb_str */
1843941Svenki D_MP | D_64BIT, /* cb_flag */
1853941Svenki CB_REV, /* cb_rev */
1863941Svenki nodev, /* cb_aread */
1873941Svenki nodev /* cb_awrite */
1883941Svenki };
1893941Svenki
1903941Svenki static struct dev_ops ds_snmp_dev_ops = {
1913941Svenki DEVO_REV, /* devo_rev */
1923941Svenki 0, /* devo_refcnt */
1933941Svenki ds_snmp_getinfo, /* devo_getinfo */
1943941Svenki nulldev, /* devo_identify */
1953941Svenki nulldev, /* devo_probe */
1963941Svenki ds_snmp_attach, /* devo_attach */
1973941Svenki ds_snmp_detach, /* devo_detach */
1983941Svenki nodev, /* devo_reset */
1993941Svenki &ds_snmp_cb_ops, /* devo_cb_ops */
2003941Svenki (struct bus_ops *)NULL, /* devo_bus_ops */
2017656SSherry.Moore@Sun.COM nulldev, /* devo_power */
2027656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* devo_quiesce */
2033941Svenki };
2043941Svenki
2053941Svenki static struct modldrv modldrv = {
2063941Svenki &mod_driverops,
2077656SSherry.Moore@Sun.COM "Domain Services SNMP Driver",
2083941Svenki &ds_snmp_dev_ops
2093941Svenki };
2103941Svenki
2113941Svenki static struct modlinkage modlinkage = {
2123941Svenki MODREV_1,
2133941Svenki (void *)&modldrv,
2143941Svenki NULL
2153941Svenki };
2163941Svenki
2173941Svenki int
_init(void)2183941Svenki _init(void)
2193941Svenki {
2203941Svenki int retval;
2213941Svenki
2223941Svenki mutex_init(&ds_snmp_lock, NULL, MUTEX_DRIVER, NULL);
2233941Svenki cv_init(&ds_snmp_service_cv, NULL, CV_DRIVER, NULL);
2243941Svenki
2253941Svenki retval = ddi_soft_state_init(&ds_snmp_statep,
2263941Svenki sizeof (ds_snmp_state_t), DS_SNMP_MAX_OPENS);
2273941Svenki if (retval != 0) {
2283941Svenki cv_destroy(&ds_snmp_service_cv);
2293941Svenki mutex_destroy(&ds_snmp_lock);
2303941Svenki return (retval);
2313941Svenki }
2323941Svenki
2333941Svenki retval = mod_install(&modlinkage);
2343941Svenki if (retval != 0) {
2353941Svenki ddi_soft_state_fini(&ds_snmp_statep);
2363941Svenki cv_destroy(&ds_snmp_service_cv);
2373941Svenki mutex_destroy(&ds_snmp_lock);
2383941Svenki }
2393941Svenki
2403941Svenki return (retval);
2413941Svenki }
2423941Svenki
2433941Svenki int
_info(struct modinfo * modinfop)2443941Svenki _info(struct modinfo *modinfop)
2453941Svenki {
2463941Svenki return (mod_info(&modlinkage, modinfop));
2473941Svenki }
2483941Svenki
2493941Svenki int
_fini(void)2503941Svenki _fini(void)
2513941Svenki {
2523941Svenki int retval;
2533941Svenki
2543941Svenki if ((retval = mod_remove(&modlinkage)) != 0)
2553941Svenki return (retval);
2563941Svenki
2573941Svenki ddi_soft_state_fini(&ds_snmp_statep);
2583941Svenki
2593941Svenki cv_destroy(&ds_snmp_service_cv);
2603941Svenki mutex_destroy(&ds_snmp_lock);
2613941Svenki
2623941Svenki return (retval);
2633941Svenki }
2643941Svenki
2653941Svenki /*ARGSUSED*/
2663941Svenki static int
ds_snmp_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)2673941Svenki ds_snmp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
2683941Svenki {
2693941Svenki ds_snmp_state_t *sp;
2703941Svenki int retval = DDI_FAILURE;
2713941Svenki
2723941Svenki ASSERT(resultp != NULL);
2733941Svenki
2743941Svenki switch (cmd) {
2753941Svenki case DDI_INFO_DEVT2DEVINFO:
2763941Svenki sp = ddi_get_soft_state(ds_snmp_statep, getminor((dev_t)arg));
2773941Svenki if (sp != NULL) {
2783941Svenki *resultp = sp->dip;
2793941Svenki retval = DDI_SUCCESS;
2803941Svenki } else
2813941Svenki *resultp = NULL;
2823941Svenki break;
2833941Svenki
2843941Svenki case DDI_INFO_DEVT2INSTANCE:
2853941Svenki *resultp = (void *)(uintptr_t)getminor((dev_t)arg);
2863941Svenki retval = DDI_SUCCESS;
2873941Svenki break;
2883941Svenki }
2893941Svenki
2903941Svenki return (retval);
2913941Svenki }
2923941Svenki
2933941Svenki static int
ds_snmp_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2943941Svenki ds_snmp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2953941Svenki {
2963941Svenki int rv;
2973941Svenki
2983941Svenki switch (cmd) {
2993941Svenki case DDI_ATTACH:
3003941Svenki if (ds_snmp_instance != -1)
3013941Svenki return (DDI_FAILURE);
3023941Svenki break;
3033941Svenki
3043941Svenki case DDI_RESUME:
3053941Svenki return (DDI_SUCCESS);
3063941Svenki
3073941Svenki default:
3083941Svenki return (DDI_FAILURE);
3093941Svenki }
3103941Svenki
3113941Svenki ds_snmp_instance = ddi_get_instance(dip);
3123941Svenki if (ddi_create_minor_node(dip, DS_SNMP_NAME, S_IFCHR, ds_snmp_instance,
3135820Sfw157321 DDI_PSEUDO, 0) != DDI_SUCCESS) {
3143941Svenki cmn_err(CE_WARN, "%s@%d: Unable to create minor node",
3153941Svenki DS_SNMP_NAME, ds_snmp_instance);
3163941Svenki return (DDI_FAILURE);
3173941Svenki }
3183941Svenki
3193941Svenki bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t));
3203941Svenki
3213941Svenki ds_snmp_ops.cb_arg = dip;
3223941Svenki if ((rv = ds_cap_init(&ds_snmp_cap, &ds_snmp_ops)) != 0) {
3233941Svenki cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
3243941Svenki ddi_remove_minor_node(dip, NULL);
3253941Svenki ds_snmp_instance = -1;
3263941Svenki return (DDI_FAILURE);
3273941Svenki }
3283941Svenki
3293941Svenki ds_snmp_devi = dip;
3303941Svenki ddi_report_dev(dip);
3313941Svenki
3323941Svenki return (DDI_SUCCESS);
3333941Svenki }
3343941Svenki
3353941Svenki /*ARGSUSED*/
3363941Svenki static int
ds_snmp_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3373941Svenki ds_snmp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3383941Svenki {
3393941Svenki switch (cmd) {
3403941Svenki case DDI_DETACH:
3413941Svenki if (ds_snmp_instance == -1)
3423941Svenki return (DDI_FAILURE);
3433941Svenki break;
3443941Svenki
3453941Svenki case DDI_SUSPEND:
3463941Svenki return (DDI_SUCCESS);
3473941Svenki
3483941Svenki default:
3493941Svenki return (DDI_FAILURE);
3503941Svenki }
3513941Svenki
3523941Svenki (void) ds_cap_fini(&ds_snmp_cap);
3533941Svenki
3543941Svenki ddi_remove_minor_node(ds_snmp_devi, NULL);
3553941Svenki bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t));
3563941Svenki
3573941Svenki ds_snmp_instance = -1;
3583941Svenki ds_snmp_devi = NULL;
3593941Svenki
3603941Svenki return (DDI_SUCCESS);
3613941Svenki }
3623941Svenki
3633941Svenki static minor_t
ds_snmp_get_minor(void)3643941Svenki ds_snmp_get_minor(void)
3653941Svenki {
3663941Svenki uint64_t val;
3673941Svenki int i, ndx;
3683941Svenki minor_t minor;
3693941Svenki
3703941Svenki mutex_enter(&ds_snmp_lock);
3713941Svenki for (ndx = 0; ndx < DS_MINOR_POOL_SZ; ndx++) {
3723941Svenki val = ds_snmp_minor_pool[ndx];
3733941Svenki for (i = 0; i < DS_BITS_IN_UINT64; i++) {
3743941Svenki if ((val & 0x1) == 0) {
3753941Svenki ds_snmp_minor_pool[ndx] |= ((uint64_t)1 << i);
3763941Svenki ds_snmp_num_opens++;
3773941Svenki mutex_exit(&ds_snmp_lock);
3783941Svenki
3793941Svenki minor = ndx * DS_BITS_IN_UINT64 + i + 1;
3803941Svenki
3813941Svenki return (minor);
3823941Svenki }
3833941Svenki val >>= 1;
3843941Svenki }
3853941Svenki }
3863941Svenki mutex_exit(&ds_snmp_lock);
3873941Svenki
3883941Svenki return (0);
3893941Svenki }
3903941Svenki
3913941Svenki static void
ds_snmp_rel_minor(minor_t minor)3923941Svenki ds_snmp_rel_minor(minor_t minor)
3933941Svenki {
3943941Svenki int i, ndx;
3953941Svenki
3963941Svenki ndx = (minor - 1) / DS_BITS_IN_UINT64;
3973941Svenki i = (minor - 1) % DS_BITS_IN_UINT64;
3983941Svenki
3993941Svenki ASSERT(ndx < DS_MINOR_POOL_SZ);
4003941Svenki
4013941Svenki mutex_enter(&ds_snmp_lock);
4023941Svenki
4033941Svenki ds_snmp_num_opens--;
4043941Svenki ds_snmp_minor_pool[ndx] &= ~((uint64_t)1 << i);
4053941Svenki
4063941Svenki mutex_exit(&ds_snmp_lock);
4073941Svenki }
4083941Svenki
4093941Svenki static boolean_t
ds_snmp_is_open(minor_t minor)4103941Svenki ds_snmp_is_open(minor_t minor)
4113941Svenki {
4123941Svenki uint64_t val;
4133941Svenki int i, ndx;
4143941Svenki
4153941Svenki ndx = (minor - 1) / DS_BITS_IN_UINT64;
4163941Svenki i = (minor - 1) % DS_BITS_IN_UINT64;
4173941Svenki
4183941Svenki val = ((uint64_t)1 << i);
4193941Svenki if (ds_snmp_minor_pool[ndx] & val)
4203941Svenki return (B_TRUE);
4213941Svenki else
4223941Svenki return (B_FALSE);
4233941Svenki }
4243941Svenki
4253941Svenki static int
ds_snmp_create_state(dev_t * devp)4263941Svenki ds_snmp_create_state(dev_t *devp)
4273941Svenki {
4283941Svenki major_t major;
4293941Svenki minor_t minor;
4303941Svenki ds_snmp_state_t *sp;
4313941Svenki
4323941Svenki if ((minor = ds_snmp_get_minor()) == 0)
4333941Svenki return (EMFILE);
4343941Svenki
4353941Svenki if (ddi_soft_state_zalloc(ds_snmp_statep, minor) != DDI_SUCCESS) {
4363941Svenki cmn_err(CE_WARN, "%s@%d: Unable to allocate state",
4373941Svenki DS_SNMP_NAME, minor);
4383941Svenki ds_snmp_rel_minor(minor);
4393941Svenki return (ENOMEM);
4403941Svenki }
4413941Svenki
4423941Svenki sp = ddi_get_soft_state(ds_snmp_statep, minor);
4433941Svenki if (devp != NULL)
4443941Svenki major = getemajor(*devp);
4453941Svenki else
4463941Svenki major = ddi_driver_major(ds_snmp_devi);
4473941Svenki
4483941Svenki sp->dev = makedevice(major, minor);
4493941Svenki if (devp != NULL)
4503941Svenki *devp = sp->dev;
4513941Svenki
4523941Svenki sp->instance = minor;
4533941Svenki sp->data = NULL;
4543941Svenki sp->data_len = 0;
4553941Svenki sp->req_id = 0;
4563941Svenki sp->last_req_id = 0;
4573941Svenki sp->state = DS_SNMP_READY;
4583941Svenki sp->sc_reset = B_FALSE;
4593941Svenki
4603941Svenki mutex_init(&sp->lock, NULL, MUTEX_DRIVER, NULL);
4613941Svenki cv_init(&sp->state_cv, NULL, CV_DRIVER, NULL);
4623941Svenki
4633941Svenki return (0);
4643941Svenki }
4653941Svenki
4663941Svenki static int
ds_snmp_destroy_state(dev_t dev)4673941Svenki ds_snmp_destroy_state(dev_t dev)
4683941Svenki {
4693941Svenki ds_snmp_state_t *sp;
4703941Svenki minor_t minor;
4713941Svenki
4723941Svenki minor = getminor(dev);
4733941Svenki
4743941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
4753941Svenki return (ENXIO);
4763941Svenki
4773941Svenki ASSERT(sp->instance == minor);
4783941Svenki
4793941Svenki /*
4803941Svenki * If the app has not exited cleanly, the data may not have been
4813941Svenki * read/memory freed, hence take care of that here
4823941Svenki */
4833941Svenki if (sp->data) {
4843941Svenki kmem_free(sp->data, sp->data_len);
4853941Svenki }
4863941Svenki cv_destroy(&sp->state_cv);
4873941Svenki mutex_destroy(&sp->lock);
4883941Svenki
4893941Svenki ddi_soft_state_free(ds_snmp_statep, minor);
4903941Svenki ds_snmp_rel_minor(minor);
4913941Svenki
4923941Svenki return (0);
4933941Svenki }
4943941Svenki
4953941Svenki /*ARGSUSED*/
4963941Svenki static int
ds_snmp_open(dev_t * devp,int flag,int otyp,cred_t * credp)4973941Svenki ds_snmp_open(dev_t *devp, int flag, int otyp, cred_t *credp)
4983941Svenki {
4993941Svenki
5003941Svenki if (otyp != OTYP_CHR)
5013941Svenki return (EINVAL);
5023941Svenki
5033941Svenki if (ds_snmp_instance == -1)
5043941Svenki return (ENXIO);
5053941Svenki
5063941Svenki /*
5073941Svenki * Avoid possible race condition - ds service may not be there yet
5083941Svenki */
5093941Svenki mutex_enter(&ds_snmp_lock);
5103941Svenki while (ds_snmp_has_service == B_FALSE) {
5113941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
5123941Svenki mutex_exit(&ds_snmp_lock);
5133941Svenki return (EINTR);
5143941Svenki }
5153941Svenki }
5163941Svenki mutex_exit(&ds_snmp_lock);
5173941Svenki
5183941Svenki return (ds_snmp_create_state(devp));
5193941Svenki }
5203941Svenki
5213941Svenki
5223941Svenki /*ARGSUSED*/
5233941Svenki static int
ds_snmp_close(dev_t dev,int flag,int otyp,cred_t * credp)5243941Svenki ds_snmp_close(dev_t dev, int flag, int otyp, cred_t *credp)
5253941Svenki {
5263941Svenki if (otyp != OTYP_CHR)
5273941Svenki return (EINVAL);
5283941Svenki
5293941Svenki if (ds_snmp_instance == -1)
5303941Svenki return (ENXIO);
5313941Svenki
5323941Svenki if (ds_snmp_handle == DS_INVALID_HDL)
5333941Svenki return (EIO);
5343941Svenki
5353941Svenki return (ds_snmp_destroy_state(dev));
5363941Svenki }
5373941Svenki
5383941Svenki /*ARGSUSED*/
5393941Svenki static int
ds_snmp_read(dev_t dev,struct uio * uiop,cred_t * credp)5403941Svenki ds_snmp_read(dev_t dev, struct uio *uiop, cred_t *credp)
5413941Svenki {
5423941Svenki ds_snmp_state_t *sp;
5433941Svenki minor_t minor;
5443941Svenki size_t len;
5453941Svenki int retval;
5463941Svenki caddr_t tmpbufp = (caddr_t)NULL;
5473941Svenki
5483941Svenki /*
5493941Svenki * Given that now we can have sc resets happening at any
5503941Svenki * time, it is possible that it happened since the last time
5513941Svenki * we issued a read, write or ioctl. If so, we need to wait
5523941Svenki * for the unreg-reg pair to complete before we can do
5533941Svenki * anything.
5543941Svenki */
5553941Svenki mutex_enter(&ds_snmp_lock);
5563941Svenki while (ds_snmp_has_service == B_FALSE) {
5573941Svenki DS_SNMP_DBG("ds_snmp_read: waiting for service\n");
5583941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
5593941Svenki mutex_exit(&ds_snmp_lock);
5603941Svenki return (EINTR);
5613941Svenki }
5623941Svenki }
5633941Svenki mutex_exit(&ds_snmp_lock);
5643941Svenki
5653941Svenki if ((len = uiop->uio_resid) == 0)
5663941Svenki return (0);
5673941Svenki
5683941Svenki minor = getminor(dev);
5693941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
5703941Svenki return (ENXIO);
5713941Svenki
5723941Svenki mutex_enter(&sp->lock);
5733941Svenki
5743941Svenki if (sp->sc_reset == B_TRUE) {
5753941Svenki mutex_exit(&sp->lock);
5763941Svenki return (ECANCELED);
5773941Svenki }
5783941Svenki
5793941Svenki /*
5803941Svenki * Block or bail if there is no SNMP data
5813941Svenki */
5823941Svenki if (sp->state != DS_SNMP_DATA_AVL && sp->state != DS_SNMP_DATA_ERR) {
5833941Svenki DS_SNMP_DBG("ds_snmp_read: no SNMP data\n");
5843941Svenki if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
5853941Svenki mutex_exit(&sp->lock);
5863941Svenki return (EAGAIN);
5873941Svenki }
5883941Svenki while (sp->state != DS_SNMP_DATA_AVL &&
5895820Sfw157321 sp->state != DS_SNMP_DATA_ERR) {
5903941Svenki if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
5913941Svenki mutex_exit(&sp->lock);
5923941Svenki return (EINTR);
5933941Svenki }
5943941Svenki }
5953941Svenki }
5963941Svenki
5973941Svenki /*
5983941Svenki * If there has been an error, it could be because the agent
5993941Svenki * returned failure and there is no data to read, or an ldc-reset
6003941Svenki * has happened. Figure out which and return appropriate
6013941Svenki * error to the caller.
6023941Svenki */
6033941Svenki if (sp->state == DS_SNMP_DATA_ERR) {
6043941Svenki if (sp->sc_reset == B_TRUE) {
6053941Svenki mutex_exit(&sp->lock);
6063941Svenki DS_SNMP_DBG("ds_snmp_read: sc got reset, "
6073941Svenki "returning ECANCELED\n");
6083941Svenki return (ECANCELED);
6093941Svenki } else {
6103941Svenki sp->state = DS_SNMP_READY;
6113941Svenki cv_broadcast(&sp->state_cv);
6123941Svenki mutex_exit(&sp->lock);
6133941Svenki DS_SNMP_DBG("ds_snmp_read: data error, "
6143941Svenki "returning EIO\n");
6153941Svenki return (EIO);
6163941Svenki }
6173941Svenki }
6183941Svenki
6193941Svenki if (len > sp->data_len)
6203941Svenki len = sp->data_len;
6213941Svenki
6223941Svenki tmpbufp = kmem_alloc(len, KM_SLEEP);
6233941Svenki
6243941Svenki bcopy(sp->data, (void *)tmpbufp, len);
6253941Svenki kmem_free(sp->data, sp->data_len);
6263941Svenki sp->data = (caddr_t)NULL;
6273941Svenki sp->data_len = 0;
6283941Svenki
6293941Svenki /*
6303941Svenki * SNMP data has been consumed, wake up anyone waiting to send
6313941Svenki */
6323941Svenki sp->state = DS_SNMP_READY;
6333941Svenki cv_broadcast(&sp->state_cv);
6343941Svenki
6353941Svenki mutex_exit(&sp->lock);
6363941Svenki
6373941Svenki retval = uiomove(tmpbufp, len, UIO_READ, uiop);
6383941Svenki kmem_free(tmpbufp, len);
6393941Svenki
6403941Svenki return (retval);
6413941Svenki }
6423941Svenki
6433941Svenki /*ARGSUSED*/
6443941Svenki static int
ds_snmp_write(dev_t dev,struct uio * uiop,cred_t * credp)6453941Svenki ds_snmp_write(dev_t dev, struct uio *uiop, cred_t *credp)
6463941Svenki {
6473941Svenki ds_snmp_state_t *sp;
6483941Svenki ds_snmp_msg_t hdr;
6493941Svenki minor_t minor;
6503941Svenki size_t len;
6513941Svenki caddr_t tmpbufp;
652*12392SMichael.Bergknoff@Oracle.COM size_t orig_size;
6533941Svenki
6543941Svenki /*
6553941Svenki * Check if there was an sc reset; if yes, wait until we have the
6563941Svenki * service back again.
6573941Svenki */
6583941Svenki mutex_enter(&ds_snmp_lock);
6593941Svenki while (ds_snmp_has_service == B_FALSE) {
6603941Svenki DS_SNMP_DBG("ds_snmp_write: waiting for service\n");
6613941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
6623941Svenki mutex_exit(&ds_snmp_lock);
6633941Svenki return (EINTR);
6643941Svenki }
6653941Svenki }
6663941Svenki mutex_exit(&ds_snmp_lock);
6673941Svenki
6683941Svenki minor = getminor(dev);
6693941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
6703941Svenki return (ENXIO);
6713941Svenki
672*12392SMichael.Bergknoff@Oracle.COM orig_size = uiop->uio_resid;
6733941Svenki len = uiop->uio_resid + sizeof (ds_snmp_msg_t);
6743941Svenki tmpbufp = kmem_alloc(len, KM_SLEEP);
6753941Svenki
6763941Svenki if (uiomove(tmpbufp + sizeof (ds_snmp_msg_t),
6773941Svenki len - sizeof (ds_snmp_msg_t), UIO_WRITE, uiop) != 0) {
6783941Svenki kmem_free(tmpbufp, len);
6793941Svenki return (EIO);
6803941Svenki }
6813941Svenki
6823941Svenki mutex_enter(&sp->lock);
6833941Svenki
6843941Svenki if (sp->sc_reset == B_TRUE) {
6853941Svenki mutex_exit(&sp->lock);
6863941Svenki kmem_free(tmpbufp, len);
6873941Svenki DS_SNMP_DBG("ds_snmp_write: sc_reset is TRUE, "
6883941Svenki "returning ECANCELD\n");
6893941Svenki return (ECANCELED);
6903941Svenki }
6913941Svenki
6923941Svenki /*
6933941Svenki * wait if earlier transaction is not yet completed
6943941Svenki */
6953941Svenki while (sp->state != DS_SNMP_READY) {
6963941Svenki if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
6973941Svenki mutex_exit(&sp->lock);
6983941Svenki kmem_free(tmpbufp, len);
699*12392SMichael.Bergknoff@Oracle.COM uiop->uio_resid = orig_size;
7003941Svenki return (EINTR);
7013941Svenki }
7023941Svenki /*
7033941Svenki * Normally, only a reader would ever wake us up. But if we
7043941Svenki * did get signalled with an ERROR, it could only mean there
7053941Svenki * was an sc reset and there's no point waiting; we need to
7063941Svenki * fail this write().
7073941Svenki */
7083941Svenki if (sp->state == DS_SNMP_DATA_ERR && sp->sc_reset == B_TRUE) {
7093941Svenki DS_SNMP_DBG("ds_snmp_write: woke up with an sc_reset, "
7103941Svenki "returning ECANCELED\n");
7113941Svenki mutex_exit(&sp->lock);
7123941Svenki kmem_free(tmpbufp, len);
7133941Svenki return (ECANCELED);
7143941Svenki }
7153941Svenki }
7163941Svenki
7173941Svenki if (sp->req_id == (((uint64_t)1 << DS_SNMP_MINOR_SHIFT) - 1))
7183941Svenki sp->req_id = 0; /* Reset */
7193941Svenki
7203941Svenki hdr.seq_num = ((uint64_t)minor << DS_SNMP_MINOR_SHIFT) | sp->req_id;
7213941Svenki sp->last_req_id = hdr.seq_num;
7223941Svenki (sp->req_id)++;
7233941Svenki
7243941Svenki /*
7253941Svenki * Set state to SNMP_REQUESTED, but don't wakeup anyone yet
7263941Svenki */
7273941Svenki sp->state = DS_SNMP_REQUESTED;
7283941Svenki
7293941Svenki mutex_exit(&sp->lock);
7303941Svenki
7313941Svenki hdr.type = DS_SNMP_REQUEST;
7323941Svenki bcopy((void *)&hdr, (void *)tmpbufp, sizeof (hdr));
7333941Svenki
7343941Svenki /*
7353941Svenki * If the service went away since the time we entered this
7363941Svenki * routine and now, tough luck. Just ignore the current
7373941Svenki * write() and return.
7383941Svenki */
7393941Svenki mutex_enter(&ds_snmp_lock);
7403941Svenki if (ds_snmp_has_service == B_FALSE) {
7413941Svenki DS_SNMP_DBG("ds_snmp_write: service went away, aborting "
7423941Svenki "write, returning ECANCELED\n");
7433941Svenki mutex_exit(&ds_snmp_lock);
7443941Svenki kmem_free(tmpbufp, len);
7453941Svenki return (ECANCELED);
7463941Svenki }
7473941Svenki DS_SNMP_DBG("ds_snmp_write: ds_cap_send(0x%lx, %lu) called.\n",
7483941Svenki ds_snmp_handle, len);
7493941Svenki (void) ds_cap_send(ds_snmp_handle, tmpbufp, len);
7503941Svenki mutex_exit(&ds_snmp_lock);
7513941Svenki
7523941Svenki kmem_free(tmpbufp, len);
7533941Svenki
7543941Svenki return (0);
7553941Svenki }
7563941Svenki
7573941Svenki /*ARGSUSED*/
7583941Svenki static int
ds_snmp_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)7593941Svenki ds_snmp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
7603941Svenki int *rvalp)
7613941Svenki {
7623941Svenki ds_snmp_state_t *sp;
7633941Svenki struct dssnmp_info info;
7643941Svenki minor_t minor;
7653941Svenki
7663941Svenki /*
7673941Svenki * Check if there was an sc reset; if yes, wait until we have the
7683941Svenki * service back again.
7693941Svenki */
7703941Svenki mutex_enter(&ds_snmp_lock);
7713941Svenki while (ds_snmp_has_service == B_FALSE) {
7723941Svenki DS_SNMP_DBG("ds_snmp_ioctl: waiting for service\n");
7733941Svenki if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
7743941Svenki mutex_exit(&ds_snmp_lock);
7753941Svenki return (EINTR);
7763941Svenki }
7773941Svenki }
7783941Svenki mutex_exit(&ds_snmp_lock);
7793941Svenki
7803941Svenki DS_SNMP_DBG("ds_snmp_ioctl: hdl=0x%lx\n", ds_snmp_handle);
7813941Svenki
7823941Svenki minor = getminor(dev);
7833941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
7843941Svenki return (ENXIO);
7853941Svenki
7863941Svenki if (!(mode & FREAD))
7873941Svenki return (EACCES);
7883941Svenki
7893941Svenki switch (cmd) {
7903941Svenki case DSSNMP_GETINFO:
7913941Svenki mutex_enter(&sp->lock);
7923941Svenki
7933941Svenki if (sp->sc_reset == B_TRUE) {
7943941Svenki mutex_exit(&sp->lock);
7953941Svenki DS_SNMP_DBG("ds_snmp_ioctl: returning ECANCELED\n");
7963941Svenki return (ECANCELED);
7973941Svenki }
7983941Svenki
7993941Svenki while (sp->state != DS_SNMP_DATA_AVL &&
8003941Svenki sp->state != DS_SNMP_DATA_ERR) {
8013941Svenki DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, "
8023941Svenki "waiting for data\n", sp->state, sp->sc_reset);
8033941Svenki if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
8045820Sfw157321 sp->state = DS_SNMP_READY;
8053941Svenki mutex_exit(&sp->lock);
8063941Svenki return (EINTR);
8073941Svenki }
8083941Svenki }
8093941Svenki DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, "
8103941Svenki "out of wait!\n", sp->state, sp->sc_reset);
8113941Svenki
8123941Svenki /*
8133941Svenki * If there has been an error, it could be because the
8143941Svenki * agent returned failure and there is no data to read,
8153941Svenki * or an ldc-reset has happened. Figure out which and
8163941Svenki * return appropriate error to the caller.
8173941Svenki */
8183941Svenki if (sp->state == DS_SNMP_DATA_ERR) {
8193941Svenki if (sp->sc_reset == B_TRUE) {
8203941Svenki mutex_exit(&sp->lock);
8213941Svenki DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=TRUE "
8223941Svenki "returning ECANCELED\n");
8233941Svenki return (ECANCELED);
8243941Svenki } else {
8253941Svenki sp->state = DS_SNMP_READY;
8263941Svenki cv_broadcast(&sp->state_cv);
8273941Svenki mutex_exit(&sp->lock);
8283941Svenki DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=FALSE "
8293941Svenki "returning EIO\n");
8303941Svenki return (EIO);
8313941Svenki }
8323941Svenki }
8333941Svenki
8343941Svenki info.size = sp->data_len;
8353941Svenki info.token = sp->gencount;
8363941Svenki
8373941Svenki mutex_exit(&sp->lock);
8383941Svenki
8393941Svenki if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
8403941Svenki return (EFAULT);
8413941Svenki break;
8423941Svenki
8433941Svenki case DSSNMP_CLRLNKRESET:
8443941Svenki mutex_enter(&sp->lock);
8453941Svenki
8463941Svenki DS_SNMP_DBG("ds_snmp_ioctl: DSSNMP_CLRLNKRESET\n");
8473941Svenki DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=%d\n", sp->sc_reset);
8483941Svenki
8493941Svenki if (sp->sc_reset == B_TRUE) {
8503941Svenki if (sp->data) {
8513941Svenki DS_SNMP_DBG("ds_snmp_ioctl: data=%p, len=%lu\n",
8523941Svenki sp->data, sp->data_len);
8533941Svenki kmem_free(sp->data, sp->data_len);
8543941Svenki }
8553941Svenki sp->data = NULL;
8563941Svenki sp->data_len = 0;
8573941Svenki sp->state = DS_SNMP_READY;
8583941Svenki sp->req_id = 0;
8593941Svenki sp->last_req_id = 0;
8603941Svenki sp->sc_reset = B_FALSE;
8613941Svenki }
8623941Svenki mutex_exit(&sp->lock);
8633941Svenki break;
8643941Svenki
8653941Svenki default:
8663941Svenki return (ENOTTY);
8673941Svenki }
8683941Svenki
8693941Svenki return (0);
8703941Svenki }
8713941Svenki
8723941Svenki /*
8733941Svenki * DS Callbacks
8743941Svenki */
8753941Svenki /*ARGSUSED*/
8763941Svenki static void
ds_snmp_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)8773941Svenki ds_snmp_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
8783941Svenki {
8793941Svenki DS_SNMP_DBG("ds_snmp_reg_handler: registering handle 0x%lx for version "
8803941Svenki "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
8813941Svenki
8823941Svenki mutex_enter(&ds_snmp_lock);
8833941Svenki
8843941Svenki ASSERT(ds_snmp_handle == DS_INVALID_HDL);
8853941Svenki
8863941Svenki ds_snmp_handle = hdl;
8873941Svenki ds_snmp_has_service = B_TRUE;
8883941Svenki
8893941Svenki cv_broadcast(&ds_snmp_service_cv);
8903941Svenki
8913941Svenki mutex_exit(&ds_snmp_lock);
8923941Svenki
8933941Svenki }
8943941Svenki
8953941Svenki /*ARGSUSED*/
8963941Svenki static void
ds_snmp_unreg_handler(ds_cb_arg_t arg)8973941Svenki ds_snmp_unreg_handler(ds_cb_arg_t arg)
8983941Svenki {
8993941Svenki minor_t minor;
9003941Svenki ds_snmp_state_t *sp;
9013941Svenki
9023941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: un-registering ds_snmp service\n");
9033941Svenki
9043941Svenki mutex_enter(&ds_snmp_lock);
9053941Svenki
9063941Svenki if (ds_snmp_num_opens) {
9073941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: %d opens, sc reset!\n",
9083941Svenki ds_snmp_num_opens);
9093941Svenki for (minor = 1; minor <= DS_SNMP_MAX_OPENS; minor++) {
9103941Svenki if (ds_snmp_is_open(minor)) {
9113941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: minor %d "
9123941Svenki "open\n", minor);
9133941Svenki sp = ddi_get_soft_state(ds_snmp_statep, minor);
9143941Svenki if (sp == NULL)
9153941Svenki continue;
9163941Svenki
9173941Svenki /*
9183941Svenki * Set the sc_reset flag and break any waiters
9193941Svenki * out of their existing reads/writes/ioctls.
9203941Svenki */
9213941Svenki DS_SNMP_DBG("ds_snmp_unreg_hdlr: about to "
9223941Svenki "signal waiters\n");
9233941Svenki mutex_enter(&sp->lock);
9243941Svenki sp->sc_reset = B_TRUE;
9253941Svenki sp->state = DS_SNMP_DATA_ERR;
9263941Svenki cv_broadcast(&sp->state_cv);
9273941Svenki mutex_exit(&sp->lock);
9283941Svenki }
9293941Svenki }
9303941Svenki }
9313941Svenki
9323941Svenki ds_snmp_handle = DS_INVALID_HDL;
9333941Svenki ds_snmp_has_service = B_FALSE;
9343941Svenki
9353941Svenki DS_SNMP_DBG("ds_snmp_unreg_handler: handle invalidated\n");
9363941Svenki
9373941Svenki mutex_exit(&ds_snmp_lock);
9383941Svenki }
9393941Svenki
9403941Svenki /*ARGSUSED*/
9413941Svenki static void
ds_snmp_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)9423941Svenki ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
9433941Svenki {
9443941Svenki ds_snmp_state_t *sp;
9453941Svenki ds_snmp_msg_t hdr;
9463941Svenki size_t snmp_size;
9473941Svenki minor_t minor;
9483941Svenki
9493941Svenki /*
9503941Svenki * Make sure the header is at least valid
9513941Svenki */
9523941Svenki if (buflen < sizeof (hdr)) {
9533941Svenki cmn_err(CE_WARN,
9543941Svenki "ds_snmp_data_handler: buflen <%lu> too small", buflen);
9553941Svenki return;
9563941Svenki }
9573941Svenki
9583941Svenki ASSERT(buf != NULL);
9593941Svenki bcopy(buf, (void *)&hdr, sizeof (hdr));
9603941Svenki
9613941Svenki DS_SNMP_DBG("ds_snmp_data_handler: msg buf len 0x%lx : type 0x%lx, "
9623941Svenki "seqn 0x%lx\n", buflen, hdr.type, hdr.seq_num);
9633941Svenki
9643941Svenki minor = (int)(hdr.seq_num >> DS_SNMP_MINOR_SHIFT);
9653941Svenki if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
9663941Svenki return;
9673941Svenki
9683941Svenki mutex_enter(&sp->lock);
9693941Svenki
9703941Svenki /*
9713941Svenki * If there is no pending SNMP request, then we've received
9725820Sfw157321 * bogus data or an SNMP trap or the reader was interrupted.
9735820Sfw157321 * Since we don't yet support SNMP traps, ignore it.
9743941Svenki */
9753941Svenki if (sp->state != DS_SNMP_REQUESTED) {
9765820Sfw157321 DS_SNMP_DBG("Received SNMP data without request");
9773941Svenki mutex_exit(&sp->lock);
9783941Svenki return;
9793941Svenki }
9803941Svenki
9813941Svenki /*
9823941Svenki * Response to a request therefore old SNMP must've been consumed
9833941Svenki */
9843941Svenki ASSERT(sp->data_len == 0);
9853941Svenki ASSERT(sp->data == NULL);
9863941Svenki
9873941Svenki /*
9883941Svenki * Response seq_num should match our request seq_num
9893941Svenki */
9903941Svenki if (hdr.seq_num != sp->last_req_id) {
9913941Svenki cmn_err(CE_WARN, "Received DS snmp data out of sequence with "
9923941Svenki "request");
9933941Svenki mutex_exit(&sp->lock);
9943941Svenki return;
9953941Svenki }
9963941Svenki
9973941Svenki if (hdr.type == DS_SNMP_ERROR) {
9983941Svenki sp->state = DS_SNMP_DATA_ERR;
9993941Svenki DS_SNMP_DBG("ds_snmp_data_handler: hdr.type = DS_SNMP_ERROR\n");
10003941Svenki } else {
10013941Svenki snmp_size = buflen - sizeof (ds_snmp_msg_t);
10023941Svenki sp->data = kmem_alloc(snmp_size, KM_SLEEP);
10033941Svenki sp->data_len = snmp_size;
10043941Svenki sp->state = DS_SNMP_DATA_AVL;
10053941Svenki
10063941Svenki bcopy((caddr_t)buf + sizeof (ds_snmp_msg_t),
10073941Svenki sp->data, sp->data_len);
10083941Svenki }
10093941Svenki
10103941Svenki sp->gencount++;
10113941Svenki
10123941Svenki /*
10133941Svenki * Wake up any readers waiting for data
10143941Svenki */
10153941Svenki cv_broadcast(&sp->state_cv);
10163941Svenki mutex_exit(&sp->lock);
10173941Svenki }
1018