xref: /onnv-gate/usr/src/uts/sun4v/io/ds_snmp.c (revision 12392:40e20d07685e)
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