xref: /onnv-gate/usr/src/uts/sun4v/io/ds_snmp.c (revision 3941:328be6a20f20)
1*3941Svenki /*
2*3941Svenki  * CDDL HEADER START
3*3941Svenki  *
4*3941Svenki  * The contents of this file are subject to the terms of the
5*3941Svenki  * Common Development and Distribution License (the "License").
6*3941Svenki  * You may not use this file except in compliance with the License.
7*3941Svenki  *
8*3941Svenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*3941Svenki  * or http://www.opensolaris.org/os/licensing.
10*3941Svenki  * See the License for the specific language governing permissions
11*3941Svenki  * and limitations under the License.
12*3941Svenki  *
13*3941Svenki  * When distributing Covered Code, include this CDDL HEADER in each
14*3941Svenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*3941Svenki  * If applicable, add the following below this CDDL HEADER, with the
16*3941Svenki  * fields enclosed by brackets "[]" replaced with your own identifying
17*3941Svenki  * information: Portions Copyright [yyyy] [name of copyright owner]
18*3941Svenki  *
19*3941Svenki  * CDDL HEADER END
20*3941Svenki  */
21*3941Svenki /*
22*3941Svenki  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*3941Svenki  * Use is subject to license terms.
24*3941Svenki  */
25*3941Svenki 
26*3941Svenki #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*3941Svenki 
28*3941Svenki /*
29*3941Svenki  * sun4v domain services SNMP driver
30*3941Svenki  */
31*3941Svenki 
32*3941Svenki #include <sys/types.h>
33*3941Svenki #include <sys/file.h>
34*3941Svenki #include <sys/errno.h>
35*3941Svenki #include <sys/open.h>
36*3941Svenki #include <sys/cred.h>
37*3941Svenki #include <sys/uio.h>
38*3941Svenki #include <sys/stat.h>
39*3941Svenki #include <sys/ksynch.h>
40*3941Svenki #include <sys/modctl.h>
41*3941Svenki #include <sys/conf.h>
42*3941Svenki #include <sys/devops.h>
43*3941Svenki #include <sys/debug.h>
44*3941Svenki #include <sys/cmn_err.h>
45*3941Svenki #include <sys/ddi.h>
46*3941Svenki #include <sys/sunddi.h>
47*3941Svenki #include <sys/ds.h>
48*3941Svenki #include <sys/ds_snmp.h>
49*3941Svenki 
50*3941Svenki #define	DS_SNMP_NAME		"ds_snmp"
51*3941Svenki #define	DS_SNMP_MAX_OPENS	256
52*3941Svenki #define	DS_BITS_IN_UINT64	64
53*3941Svenki #define	DS_MINOR_POOL_SZ	(DS_SNMP_MAX_OPENS / DS_BITS_IN_UINT64)
54*3941Svenki #define	DS_SNMP_MINOR_SHIFT	56
55*3941Svenki #define	DS_SNMP_DBG		if (ds_snmp_debug) printf
56*3941Svenki 
57*3941Svenki typedef	struct {
58*3941Svenki 	uint64_t	seq_num;
59*3941Svenki 	uint64_t	type;
60*3941Svenki } ds_snmp_msg_t;
61*3941Svenki 
62*3941Svenki typedef	enum {
63*3941Svenki 	DS_SNMP_REQUEST	= 0,
64*3941Svenki 	DS_SNMP_REPLY	= 1,
65*3941Svenki 	DS_SNMP_ERROR = 2
66*3941Svenki } ds_snmp_msg_type_t;
67*3941Svenki 
68*3941Svenki typedef enum {
69*3941Svenki 	DS_SNMP_READY = 0x0,
70*3941Svenki 	DS_SNMP_REQUESTED = 0x1,
71*3941Svenki 	DS_SNMP_DATA_AVL = 0x2,
72*3941Svenki 	DS_SNMP_DATA_ERR = 0x3
73*3941Svenki } ds_snmp_flags_t;
74*3941Svenki 
75*3941Svenki /*
76*3941Svenki  * The single mutex 'lock' protects all the SNMP/DS variables in the state
77*3941Svenki  * structure.
78*3941Svenki  *
79*3941Svenki  * The condition variable 'state_cv' helps serialize write() calls for a
80*3941Svenki  * single descriptor. When write() is called, it sets a flag to indicate
81*3941Svenki  * that an SNMP request has been made to the agent. No more write()'s on
82*3941Svenki  * the same open descriptor will be allowed until this flag is cleared via
83*3941Svenki  * a matching read(), where the requested packet is consumed on arrival.
84*3941Svenki  * Read() then wakes up any waiters blocked in write() for sending the next
85*3941Svenki  * SNMP request to the agent.
86*3941Svenki  */
87*3941Svenki typedef struct ds_snmp_state {
88*3941Svenki 	dev_info_t	*dip;
89*3941Svenki 	int		instance;
90*3941Svenki 	dev_t		dev;
91*3941Svenki 
92*3941Svenki 	/* SNMP/DS */
93*3941Svenki 	kmutex_t	lock;
94*3941Svenki 	kcondvar_t	state_cv;
95*3941Svenki 	ds_snmp_flags_t	state;
96*3941Svenki 	void		*data;
97*3941Svenki 	size_t		data_len;
98*3941Svenki 	uint64_t	req_id;
99*3941Svenki 	uint64_t	last_req_id;
100*3941Svenki 	uint64_t	gencount;
101*3941Svenki 	boolean_t	sc_reset;
102*3941Svenki } ds_snmp_state_t;
103*3941Svenki 
104*3941Svenki 
105*3941Svenki static uint_t		ds_snmp_debug = 0;
106*3941Svenki static void		*ds_snmp_statep = NULL;
107*3941Svenki static int		ds_snmp_instance = -1;
108*3941Svenki static dev_info_t	*ds_snmp_devi = NULL;
109*3941Svenki 
110*3941Svenki /*
111*3941Svenki  * The ds_snmp_lock mutex protects the following data global to the
112*3941Svenki  * driver.
113*3941Svenki  *
114*3941Svenki  * The ds_snmp_service_cv condition variable is used to resolve the
115*3941Svenki  * potential race between the registration of snmp service via a
116*3941Svenki  * ds_cap_init() in attach(), the acknowledgement of this registration
117*3941Svenki  * at a later time in ds_snmp_reg_handler(), and a possible open() at
118*3941Svenki  * a time inbetween. The ds_snmp_has_service and ds_snmp_handle are
119*3941Svenki  * used to indicate whether the registration acknowledgement has happened
120*3941Svenki  * or not.
121*3941Svenki  *
122*3941Svenki  * The ds_snmp_minor_pool[] is a bitmask to allocate and keep track of
123*3941Svenki  * minor numbers dynamically.
124*3941Svenki  */
125*3941Svenki static kmutex_t		ds_snmp_lock;
126*3941Svenki static kcondvar_t	ds_snmp_service_cv;
127*3941Svenki static int		ds_snmp_has_service = B_FALSE;
128*3941Svenki static ds_svc_hdl_t	ds_snmp_handle = DS_INVALID_HDL;
129*3941Svenki static uint64_t		ds_snmp_minor_pool[DS_MINOR_POOL_SZ];	/* bitmask */
130*3941Svenki static int		ds_snmp_num_opens = 0;
131*3941Svenki 
132*3941Svenki static int ds_snmp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
133*3941Svenki static int ds_snmp_attach(dev_info_t *, ddi_attach_cmd_t);
134*3941Svenki static int ds_snmp_detach(dev_info_t *, ddi_detach_cmd_t);
135*3941Svenki static int ds_snmp_open(dev_t *, int, int, cred_t *);
136*3941Svenki static int ds_snmp_close(dev_t, int, int, cred_t *);
137*3941Svenki static int ds_snmp_read(dev_t, struct uio *, cred_t *);
138*3941Svenki static int ds_snmp_write(dev_t, struct uio *, cred_t *);
139*3941Svenki static int ds_snmp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
140*3941Svenki 
141*3941Svenki /*
142*3941Svenki  * DS Callbacks
143*3941Svenki  */
144*3941Svenki static void ds_snmp_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
145*3941Svenki static void ds_snmp_unreg_handler(ds_cb_arg_t arg);
146*3941Svenki static void ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
147*3941Svenki 
148*3941Svenki /*
149*3941Svenki  * SNMP DS capability registration
150*3941Svenki  */
151*3941Svenki static ds_ver_t ds_snmp_ver_1_0 = { 1, 0 };
152*3941Svenki static ds_capability_t ds_snmp_cap = {
153*3941Svenki 	"snmp",
154*3941Svenki 	&ds_snmp_ver_1_0,
155*3941Svenki 	1
156*3941Svenki };
157*3941Svenki 
158*3941Svenki /*
159*3941Svenki  * SNMP DS Client callback vector
160*3941Svenki  */
161*3941Svenki static ds_clnt_ops_t ds_snmp_ops = {
162*3941Svenki 	ds_snmp_reg_handler,	/* ds_reg_cb */
163*3941Svenki 	ds_snmp_unreg_handler,	/* ds_unreg_cb */
164*3941Svenki 	ds_snmp_data_handler,	/* ds_data_cb */
165*3941Svenki 	NULL			/* cb_arg */
166*3941Svenki };
167*3941Svenki 
168*3941Svenki /*
169*3941Svenki  * DS SNMP driver Ops Vector
170*3941Svenki  */
171*3941Svenki static struct cb_ops ds_snmp_cb_ops = {
172*3941Svenki 	ds_snmp_open,		/* cb_open */
173*3941Svenki 	ds_snmp_close,		/* cb_close */
174*3941Svenki 	nodev,			/* cb_strategy */
175*3941Svenki 	nodev,			/* cb_print */
176*3941Svenki 	nodev,			/* cb_dump */
177*3941Svenki 	ds_snmp_read,		/* cb_read */
178*3941Svenki 	ds_snmp_write,		/* cb_write */
179*3941Svenki 	ds_snmp_ioctl,		/* cb_ioctl */
180*3941Svenki 	nodev,			/* cb_devmap */
181*3941Svenki 	nodev,			/* cb_mmap */
182*3941Svenki 	nodev,			/* cb_segmap */
183*3941Svenki 	nochpoll,		/* cb_chpoll */
184*3941Svenki 	ddi_prop_op,		/* cb_prop_op */
185*3941Svenki 	(struct streamtab *)NULL, /* cb_str */
186*3941Svenki 	D_MP | D_64BIT,		/* cb_flag */
187*3941Svenki 	CB_REV,			/* cb_rev */
188*3941Svenki 	nodev,			/* cb_aread */
189*3941Svenki 	nodev			/* cb_awrite */
190*3941Svenki };
191*3941Svenki 
192*3941Svenki static struct dev_ops ds_snmp_dev_ops = {
193*3941Svenki 	DEVO_REV,		/* devo_rev */
194*3941Svenki 	0,			/* devo_refcnt */
195*3941Svenki 	ds_snmp_getinfo,	/* devo_getinfo */
196*3941Svenki 	nulldev,		/* devo_identify */
197*3941Svenki 	nulldev,		/* devo_probe */
198*3941Svenki 	ds_snmp_attach,		/* devo_attach */
199*3941Svenki 	ds_snmp_detach,		/* devo_detach */
200*3941Svenki 	nodev,			/* devo_reset */
201*3941Svenki 	&ds_snmp_cb_ops,	/* devo_cb_ops */
202*3941Svenki 	(struct bus_ops *)NULL,	/* devo_bus_ops */
203*3941Svenki 	nulldev			/* devo_power */
204*3941Svenki };
205*3941Svenki 
206*3941Svenki static struct modldrv modldrv = {
207*3941Svenki 	&mod_driverops,
208*3941Svenki 	"Domain Services SNMP Driver 1.0",
209*3941Svenki 	&ds_snmp_dev_ops
210*3941Svenki };
211*3941Svenki 
212*3941Svenki static struct modlinkage modlinkage = {
213*3941Svenki 	MODREV_1,
214*3941Svenki 	(void *)&modldrv,
215*3941Svenki 	NULL
216*3941Svenki };
217*3941Svenki 
218*3941Svenki int
219*3941Svenki _init(void)
220*3941Svenki {
221*3941Svenki 	int retval;
222*3941Svenki 
223*3941Svenki 	mutex_init(&ds_snmp_lock, NULL, MUTEX_DRIVER, NULL);
224*3941Svenki 	cv_init(&ds_snmp_service_cv, NULL, CV_DRIVER, NULL);
225*3941Svenki 
226*3941Svenki 	retval = ddi_soft_state_init(&ds_snmp_statep,
227*3941Svenki 	    sizeof (ds_snmp_state_t), DS_SNMP_MAX_OPENS);
228*3941Svenki 	if (retval != 0) {
229*3941Svenki 		cv_destroy(&ds_snmp_service_cv);
230*3941Svenki 		mutex_destroy(&ds_snmp_lock);
231*3941Svenki 		return (retval);
232*3941Svenki 	}
233*3941Svenki 
234*3941Svenki 	retval = mod_install(&modlinkage);
235*3941Svenki 	if (retval != 0) {
236*3941Svenki 		ddi_soft_state_fini(&ds_snmp_statep);
237*3941Svenki 		cv_destroy(&ds_snmp_service_cv);
238*3941Svenki 		mutex_destroy(&ds_snmp_lock);
239*3941Svenki 	}
240*3941Svenki 
241*3941Svenki 	return (retval);
242*3941Svenki }
243*3941Svenki 
244*3941Svenki int
245*3941Svenki _info(struct modinfo *modinfop)
246*3941Svenki {
247*3941Svenki 	return (mod_info(&modlinkage, modinfop));
248*3941Svenki }
249*3941Svenki 
250*3941Svenki int
251*3941Svenki _fini(void)
252*3941Svenki {
253*3941Svenki 	int retval;
254*3941Svenki 
255*3941Svenki 	if ((retval = mod_remove(&modlinkage)) != 0)
256*3941Svenki 		return (retval);
257*3941Svenki 
258*3941Svenki 	ddi_soft_state_fini(&ds_snmp_statep);
259*3941Svenki 
260*3941Svenki 	cv_destroy(&ds_snmp_service_cv);
261*3941Svenki 	mutex_destroy(&ds_snmp_lock);
262*3941Svenki 
263*3941Svenki 	return (retval);
264*3941Svenki }
265*3941Svenki 
266*3941Svenki /*ARGSUSED*/
267*3941Svenki static int
268*3941Svenki ds_snmp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
269*3941Svenki {
270*3941Svenki 	ds_snmp_state_t *sp;
271*3941Svenki 	int retval = DDI_FAILURE;
272*3941Svenki 
273*3941Svenki 	ASSERT(resultp != NULL);
274*3941Svenki 
275*3941Svenki 	switch (cmd) {
276*3941Svenki 	case DDI_INFO_DEVT2DEVINFO:
277*3941Svenki 		sp = ddi_get_soft_state(ds_snmp_statep, getminor((dev_t)arg));
278*3941Svenki 		if (sp != NULL) {
279*3941Svenki 			*resultp = sp->dip;
280*3941Svenki 			retval = DDI_SUCCESS;
281*3941Svenki 		} else
282*3941Svenki 			*resultp = NULL;
283*3941Svenki 		break;
284*3941Svenki 
285*3941Svenki 	case DDI_INFO_DEVT2INSTANCE:
286*3941Svenki 		*resultp = (void *)(uintptr_t)getminor((dev_t)arg);
287*3941Svenki 		retval = DDI_SUCCESS;
288*3941Svenki 		break;
289*3941Svenki 	}
290*3941Svenki 
291*3941Svenki 	return (retval);
292*3941Svenki }
293*3941Svenki 
294*3941Svenki static int
295*3941Svenki ds_snmp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
296*3941Svenki {
297*3941Svenki 	int	rv;
298*3941Svenki 
299*3941Svenki 	switch (cmd) {
300*3941Svenki 	case DDI_ATTACH:
301*3941Svenki 		if (ds_snmp_instance != -1)
302*3941Svenki 			return (DDI_FAILURE);
303*3941Svenki 		break;
304*3941Svenki 
305*3941Svenki 	case DDI_RESUME:
306*3941Svenki 		return (DDI_SUCCESS);
307*3941Svenki 
308*3941Svenki 	default:
309*3941Svenki 		return (DDI_FAILURE);
310*3941Svenki 	}
311*3941Svenki 
312*3941Svenki 	ds_snmp_instance = ddi_get_instance(dip);
313*3941Svenki 	if (ddi_create_minor_node(dip, DS_SNMP_NAME, S_IFCHR, ds_snmp_instance,
314*3941Svenki 		DDI_PSEUDO, 0) != DDI_SUCCESS) {
315*3941Svenki 		cmn_err(CE_WARN, "%s@%d: Unable to create minor node",
316*3941Svenki 		    DS_SNMP_NAME, ds_snmp_instance);
317*3941Svenki 		return (DDI_FAILURE);
318*3941Svenki 	}
319*3941Svenki 
320*3941Svenki 	bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t));
321*3941Svenki 
322*3941Svenki 	ds_snmp_ops.cb_arg = dip;
323*3941Svenki 	if ((rv = ds_cap_init(&ds_snmp_cap, &ds_snmp_ops)) != 0) {
324*3941Svenki 		cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
325*3941Svenki 		ddi_remove_minor_node(dip, NULL);
326*3941Svenki 		ds_snmp_instance = -1;
327*3941Svenki 		return (DDI_FAILURE);
328*3941Svenki 	}
329*3941Svenki 
330*3941Svenki 	ds_snmp_devi = dip;
331*3941Svenki 	ddi_report_dev(dip);
332*3941Svenki 
333*3941Svenki 	return (DDI_SUCCESS);
334*3941Svenki }
335*3941Svenki 
336*3941Svenki /*ARGSUSED*/
337*3941Svenki static int
338*3941Svenki ds_snmp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
339*3941Svenki {
340*3941Svenki 	switch (cmd) {
341*3941Svenki 	case DDI_DETACH:
342*3941Svenki 		if (ds_snmp_instance == -1)
343*3941Svenki 			return (DDI_FAILURE);
344*3941Svenki 		break;
345*3941Svenki 
346*3941Svenki 	case DDI_SUSPEND:
347*3941Svenki 		return (DDI_SUCCESS);
348*3941Svenki 
349*3941Svenki 	default:
350*3941Svenki 		return (DDI_FAILURE);
351*3941Svenki 	}
352*3941Svenki 
353*3941Svenki 	(void) ds_cap_fini(&ds_snmp_cap);
354*3941Svenki 
355*3941Svenki 	ddi_remove_minor_node(ds_snmp_devi, NULL);
356*3941Svenki 	bzero(ds_snmp_minor_pool, DS_MINOR_POOL_SZ * sizeof (uint64_t));
357*3941Svenki 
358*3941Svenki 	ds_snmp_instance = -1;
359*3941Svenki 	ds_snmp_devi = NULL;
360*3941Svenki 
361*3941Svenki 	return (DDI_SUCCESS);
362*3941Svenki }
363*3941Svenki 
364*3941Svenki static minor_t
365*3941Svenki ds_snmp_get_minor(void)
366*3941Svenki {
367*3941Svenki 	uint64_t	val;
368*3941Svenki 	int		i, ndx;
369*3941Svenki 	minor_t		minor;
370*3941Svenki 
371*3941Svenki 	mutex_enter(&ds_snmp_lock);
372*3941Svenki 	for (ndx = 0; ndx < DS_MINOR_POOL_SZ; ndx++) {
373*3941Svenki 		val = ds_snmp_minor_pool[ndx];
374*3941Svenki 		for (i = 0; i < DS_BITS_IN_UINT64; i++) {
375*3941Svenki 			if ((val & 0x1) == 0) {
376*3941Svenki 				ds_snmp_minor_pool[ndx] |= ((uint64_t)1 << i);
377*3941Svenki 				ds_snmp_num_opens++;
378*3941Svenki 				mutex_exit(&ds_snmp_lock);
379*3941Svenki 
380*3941Svenki 				minor = ndx * DS_BITS_IN_UINT64 + i + 1;
381*3941Svenki 
382*3941Svenki 				return (minor);
383*3941Svenki 			}
384*3941Svenki 			val >>= 1;
385*3941Svenki 		}
386*3941Svenki 	}
387*3941Svenki 	mutex_exit(&ds_snmp_lock);
388*3941Svenki 
389*3941Svenki 	return (0);
390*3941Svenki }
391*3941Svenki 
392*3941Svenki static void
393*3941Svenki ds_snmp_rel_minor(minor_t minor)
394*3941Svenki {
395*3941Svenki 	int	i, ndx;
396*3941Svenki 
397*3941Svenki 	ndx = (minor - 1) / DS_BITS_IN_UINT64;
398*3941Svenki 	i = (minor - 1) % DS_BITS_IN_UINT64;
399*3941Svenki 
400*3941Svenki 	ASSERT(ndx < DS_MINOR_POOL_SZ);
401*3941Svenki 
402*3941Svenki 	mutex_enter(&ds_snmp_lock);
403*3941Svenki 
404*3941Svenki 	ds_snmp_num_opens--;
405*3941Svenki 	ds_snmp_minor_pool[ndx] &= ~((uint64_t)1 << i);
406*3941Svenki 
407*3941Svenki 	mutex_exit(&ds_snmp_lock);
408*3941Svenki }
409*3941Svenki 
410*3941Svenki static boolean_t
411*3941Svenki ds_snmp_is_open(minor_t minor)
412*3941Svenki {
413*3941Svenki 	uint64_t	val;
414*3941Svenki 	int		i, ndx;
415*3941Svenki 
416*3941Svenki 	ndx = (minor - 1) / DS_BITS_IN_UINT64;
417*3941Svenki 	i = (minor - 1) % DS_BITS_IN_UINT64;
418*3941Svenki 
419*3941Svenki 	val = ((uint64_t)1 << i);
420*3941Svenki 	if (ds_snmp_minor_pool[ndx] & val)
421*3941Svenki 		return (B_TRUE);
422*3941Svenki 	else
423*3941Svenki 		return (B_FALSE);
424*3941Svenki }
425*3941Svenki 
426*3941Svenki static int
427*3941Svenki ds_snmp_create_state(dev_t *devp)
428*3941Svenki {
429*3941Svenki 	major_t	major;
430*3941Svenki 	minor_t	minor;
431*3941Svenki 	ds_snmp_state_t	*sp;
432*3941Svenki 
433*3941Svenki 	if ((minor = ds_snmp_get_minor()) == 0)
434*3941Svenki 		return (EMFILE);
435*3941Svenki 
436*3941Svenki 	if (ddi_soft_state_zalloc(ds_snmp_statep, minor) != DDI_SUCCESS) {
437*3941Svenki 		cmn_err(CE_WARN, "%s@%d: Unable to allocate state",
438*3941Svenki 		    DS_SNMP_NAME, minor);
439*3941Svenki 		ds_snmp_rel_minor(minor);
440*3941Svenki 		return (ENOMEM);
441*3941Svenki 	}
442*3941Svenki 
443*3941Svenki 	sp = ddi_get_soft_state(ds_snmp_statep, minor);
444*3941Svenki 	if (devp != NULL)
445*3941Svenki 		major = getemajor(*devp);
446*3941Svenki 	else
447*3941Svenki 		major = ddi_driver_major(ds_snmp_devi);
448*3941Svenki 
449*3941Svenki 	sp->dev = makedevice(major, minor);
450*3941Svenki 	if (devp != NULL)
451*3941Svenki 		*devp = sp->dev;
452*3941Svenki 
453*3941Svenki 	sp->instance = minor;
454*3941Svenki 	sp->data = NULL;
455*3941Svenki 	sp->data_len = 0;
456*3941Svenki 	sp->req_id = 0;
457*3941Svenki 	sp->last_req_id = 0;
458*3941Svenki 	sp->state = DS_SNMP_READY;
459*3941Svenki 	sp->sc_reset = B_FALSE;
460*3941Svenki 
461*3941Svenki 	mutex_init(&sp->lock, NULL, MUTEX_DRIVER, NULL);
462*3941Svenki 	cv_init(&sp->state_cv, NULL, CV_DRIVER, NULL);
463*3941Svenki 
464*3941Svenki 	return (0);
465*3941Svenki }
466*3941Svenki 
467*3941Svenki static int
468*3941Svenki ds_snmp_destroy_state(dev_t dev)
469*3941Svenki {
470*3941Svenki 	ds_snmp_state_t	*sp;
471*3941Svenki 	minor_t	minor;
472*3941Svenki 
473*3941Svenki 	minor = getminor(dev);
474*3941Svenki 
475*3941Svenki 	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
476*3941Svenki 		return (ENXIO);
477*3941Svenki 
478*3941Svenki 	ASSERT(sp->instance == minor);
479*3941Svenki 
480*3941Svenki 	/*
481*3941Svenki 	 * If the app has not exited cleanly, the data may not have been
482*3941Svenki 	 * read/memory freed, hence take care of that here
483*3941Svenki 	 */
484*3941Svenki 	if (sp->data) {
485*3941Svenki 		kmem_free(sp->data, sp->data_len);
486*3941Svenki 	}
487*3941Svenki 	cv_destroy(&sp->state_cv);
488*3941Svenki 	mutex_destroy(&sp->lock);
489*3941Svenki 
490*3941Svenki 	ddi_soft_state_free(ds_snmp_statep, minor);
491*3941Svenki 	ds_snmp_rel_minor(minor);
492*3941Svenki 
493*3941Svenki 	return (0);
494*3941Svenki }
495*3941Svenki 
496*3941Svenki /*ARGSUSED*/
497*3941Svenki static int
498*3941Svenki ds_snmp_open(dev_t *devp, int flag, int otyp, cred_t *credp)
499*3941Svenki {
500*3941Svenki 
501*3941Svenki 	if (otyp != OTYP_CHR)
502*3941Svenki 		return (EINVAL);
503*3941Svenki 
504*3941Svenki 	if (ds_snmp_instance == -1)
505*3941Svenki 		return (ENXIO);
506*3941Svenki 
507*3941Svenki 	/*
508*3941Svenki 	 * Avoid possible race condition - ds service may not be there yet
509*3941Svenki 	 */
510*3941Svenki 	mutex_enter(&ds_snmp_lock);
511*3941Svenki 	while (ds_snmp_has_service == B_FALSE) {
512*3941Svenki 		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
513*3941Svenki 			mutex_exit(&ds_snmp_lock);
514*3941Svenki 			return (EINTR);
515*3941Svenki 		}
516*3941Svenki 	}
517*3941Svenki 	mutex_exit(&ds_snmp_lock);
518*3941Svenki 
519*3941Svenki 	return (ds_snmp_create_state(devp));
520*3941Svenki }
521*3941Svenki 
522*3941Svenki 
523*3941Svenki /*ARGSUSED*/
524*3941Svenki static int
525*3941Svenki ds_snmp_close(dev_t dev, int flag, int otyp, cred_t *credp)
526*3941Svenki {
527*3941Svenki 	if (otyp != OTYP_CHR)
528*3941Svenki 		return (EINVAL);
529*3941Svenki 
530*3941Svenki 	if (ds_snmp_instance == -1)
531*3941Svenki 		return (ENXIO);
532*3941Svenki 
533*3941Svenki 	if (ds_snmp_handle == DS_INVALID_HDL)
534*3941Svenki 		return (EIO);
535*3941Svenki 
536*3941Svenki 	return (ds_snmp_destroy_state(dev));
537*3941Svenki }
538*3941Svenki 
539*3941Svenki /*ARGSUSED*/
540*3941Svenki static int
541*3941Svenki ds_snmp_read(dev_t dev, struct uio *uiop, cred_t *credp)
542*3941Svenki {
543*3941Svenki 	ds_snmp_state_t *sp;
544*3941Svenki 	minor_t	minor;
545*3941Svenki 	size_t len;
546*3941Svenki 	int retval;
547*3941Svenki 	caddr_t tmpbufp = (caddr_t)NULL;
548*3941Svenki 
549*3941Svenki 	/*
550*3941Svenki 	 * Given that now we can have sc resets happening at any
551*3941Svenki 	 * time, it is possible that it happened since the last time
552*3941Svenki 	 * we issued a read, write or ioctl.  If so, we need to wait
553*3941Svenki 	 * for the unreg-reg pair to complete before we can do
554*3941Svenki 	 * anything.
555*3941Svenki 	 */
556*3941Svenki 	mutex_enter(&ds_snmp_lock);
557*3941Svenki 	while (ds_snmp_has_service == B_FALSE) {
558*3941Svenki 		DS_SNMP_DBG("ds_snmp_read: waiting for service\n");
559*3941Svenki 		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
560*3941Svenki 			mutex_exit(&ds_snmp_lock);
561*3941Svenki 			return (EINTR);
562*3941Svenki 		}
563*3941Svenki 	}
564*3941Svenki 	mutex_exit(&ds_snmp_lock);
565*3941Svenki 
566*3941Svenki 	if ((len = uiop->uio_resid) == 0)
567*3941Svenki 		return (0);
568*3941Svenki 
569*3941Svenki 	minor = getminor(dev);
570*3941Svenki 	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
571*3941Svenki 		return (ENXIO);
572*3941Svenki 
573*3941Svenki 	mutex_enter(&sp->lock);
574*3941Svenki 
575*3941Svenki 	if (sp->sc_reset == B_TRUE) {
576*3941Svenki 		mutex_exit(&sp->lock);
577*3941Svenki 		return (ECANCELED);
578*3941Svenki 	}
579*3941Svenki 
580*3941Svenki 	/*
581*3941Svenki 	 * Block or bail if there is no SNMP data
582*3941Svenki 	 */
583*3941Svenki 	if (sp->state != DS_SNMP_DATA_AVL && sp->state != DS_SNMP_DATA_ERR) {
584*3941Svenki 		DS_SNMP_DBG("ds_snmp_read: no SNMP data\n");
585*3941Svenki 		if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
586*3941Svenki 			mutex_exit(&sp->lock);
587*3941Svenki 			return (EAGAIN);
588*3941Svenki 		}
589*3941Svenki 		while (sp->state != DS_SNMP_DATA_AVL &&
590*3941Svenki 			sp->state != DS_SNMP_DATA_ERR) {
591*3941Svenki 			if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
592*3941Svenki 				mutex_exit(&sp->lock);
593*3941Svenki 				return (EINTR);
594*3941Svenki 			}
595*3941Svenki 		}
596*3941Svenki 	}
597*3941Svenki 
598*3941Svenki 	/*
599*3941Svenki 	 * If there has been an error, it could be because the agent
600*3941Svenki 	 * returned failure and there is no data to read, or an ldc-reset
601*3941Svenki 	 * has happened.  Figure out which and return appropriate
602*3941Svenki 	 * error to the caller.
603*3941Svenki 	 */
604*3941Svenki 	if (sp->state == DS_SNMP_DATA_ERR) {
605*3941Svenki 		if (sp->sc_reset == B_TRUE) {
606*3941Svenki 			mutex_exit(&sp->lock);
607*3941Svenki 			DS_SNMP_DBG("ds_snmp_read: sc got reset, "
608*3941Svenki 			    "returning ECANCELED\n");
609*3941Svenki 			return (ECANCELED);
610*3941Svenki 		} else {
611*3941Svenki 			sp->state = DS_SNMP_READY;
612*3941Svenki 			cv_broadcast(&sp->state_cv);
613*3941Svenki 			mutex_exit(&sp->lock);
614*3941Svenki 			DS_SNMP_DBG("ds_snmp_read: data error, "
615*3941Svenki 			    "returning EIO\n");
616*3941Svenki 			return (EIO);
617*3941Svenki 		}
618*3941Svenki 	}
619*3941Svenki 
620*3941Svenki 	if (len > sp->data_len)
621*3941Svenki 		len = sp->data_len;
622*3941Svenki 
623*3941Svenki 	tmpbufp = kmem_alloc(len, KM_SLEEP);
624*3941Svenki 
625*3941Svenki 	bcopy(sp->data, (void *)tmpbufp, len);
626*3941Svenki 	kmem_free(sp->data, sp->data_len);
627*3941Svenki 	sp->data = (caddr_t)NULL;
628*3941Svenki 	sp->data_len = 0;
629*3941Svenki 
630*3941Svenki 	/*
631*3941Svenki 	 * SNMP data has been consumed, wake up anyone waiting to send
632*3941Svenki 	 */
633*3941Svenki 	sp->state = DS_SNMP_READY;
634*3941Svenki 	cv_broadcast(&sp->state_cv);
635*3941Svenki 
636*3941Svenki 	mutex_exit(&sp->lock);
637*3941Svenki 
638*3941Svenki 	retval = uiomove(tmpbufp, len, UIO_READ, uiop);
639*3941Svenki 	kmem_free(tmpbufp, len);
640*3941Svenki 
641*3941Svenki 	return (retval);
642*3941Svenki }
643*3941Svenki 
644*3941Svenki /*ARGSUSED*/
645*3941Svenki static int
646*3941Svenki ds_snmp_write(dev_t dev, struct uio *uiop, cred_t *credp)
647*3941Svenki {
648*3941Svenki 	ds_snmp_state_t *sp;
649*3941Svenki 	ds_snmp_msg_t hdr;
650*3941Svenki 	minor_t minor;
651*3941Svenki 	size_t len;
652*3941Svenki 	caddr_t tmpbufp;
653*3941Svenki 
654*3941Svenki 	/*
655*3941Svenki 	 * Check if there was an sc reset; if yes, wait until we have the
656*3941Svenki 	 * service back again.
657*3941Svenki 	 */
658*3941Svenki 	mutex_enter(&ds_snmp_lock);
659*3941Svenki 	while (ds_snmp_has_service == B_FALSE) {
660*3941Svenki 		DS_SNMP_DBG("ds_snmp_write: waiting for service\n");
661*3941Svenki 		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
662*3941Svenki 			mutex_exit(&ds_snmp_lock);
663*3941Svenki 			return (EINTR);
664*3941Svenki 		}
665*3941Svenki 	}
666*3941Svenki 	mutex_exit(&ds_snmp_lock);
667*3941Svenki 
668*3941Svenki 	minor = getminor(dev);
669*3941Svenki 	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
670*3941Svenki 		return (ENXIO);
671*3941Svenki 
672*3941Svenki 	len = uiop->uio_resid + sizeof (ds_snmp_msg_t);
673*3941Svenki 	tmpbufp = kmem_alloc(len, KM_SLEEP);
674*3941Svenki 
675*3941Svenki 	if (uiomove(tmpbufp + sizeof (ds_snmp_msg_t),
676*3941Svenki 	    len - sizeof (ds_snmp_msg_t), UIO_WRITE, uiop) != 0) {
677*3941Svenki 		kmem_free(tmpbufp, len);
678*3941Svenki 		return (EIO);
679*3941Svenki 	}
680*3941Svenki 
681*3941Svenki 	mutex_enter(&sp->lock);
682*3941Svenki 
683*3941Svenki 	if (sp->sc_reset == B_TRUE) {
684*3941Svenki 		mutex_exit(&sp->lock);
685*3941Svenki 		kmem_free(tmpbufp, len);
686*3941Svenki 		DS_SNMP_DBG("ds_snmp_write: sc_reset is TRUE, "
687*3941Svenki 		    "returning ECANCELD\n");
688*3941Svenki 		return (ECANCELED);
689*3941Svenki 	}
690*3941Svenki 
691*3941Svenki 	/*
692*3941Svenki 	 * wait if earlier transaction is not yet completed
693*3941Svenki 	 */
694*3941Svenki 	while (sp->state != DS_SNMP_READY) {
695*3941Svenki 		if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
696*3941Svenki 			mutex_exit(&sp->lock);
697*3941Svenki 			kmem_free(tmpbufp, len);
698*3941Svenki 			return (EINTR);
699*3941Svenki 		}
700*3941Svenki 		/*
701*3941Svenki 		 * Normally, only a reader would ever wake us up. But if we
702*3941Svenki 		 * did get signalled with an ERROR, it could only mean there
703*3941Svenki 		 * was an sc reset and there's no point waiting; we need to
704*3941Svenki 		 * fail this write().
705*3941Svenki 		 */
706*3941Svenki 		if (sp->state == DS_SNMP_DATA_ERR && sp->sc_reset == B_TRUE) {
707*3941Svenki 			DS_SNMP_DBG("ds_snmp_write: woke up with an sc_reset, "
708*3941Svenki 			    "returning ECANCELED\n");
709*3941Svenki 			mutex_exit(&sp->lock);
710*3941Svenki 			kmem_free(tmpbufp, len);
711*3941Svenki 			return (ECANCELED);
712*3941Svenki 		}
713*3941Svenki 	}
714*3941Svenki 
715*3941Svenki 	if (sp->req_id == (((uint64_t)1 << DS_SNMP_MINOR_SHIFT) - 1))
716*3941Svenki 		sp->req_id = 0; /* Reset */
717*3941Svenki 
718*3941Svenki 	hdr.seq_num = ((uint64_t)minor << DS_SNMP_MINOR_SHIFT) | sp->req_id;
719*3941Svenki 	sp->last_req_id = hdr.seq_num;
720*3941Svenki 	(sp->req_id)++;
721*3941Svenki 
722*3941Svenki 	/*
723*3941Svenki 	 * Set state to SNMP_REQUESTED, but don't wakeup anyone yet
724*3941Svenki 	 */
725*3941Svenki 	sp->state = DS_SNMP_REQUESTED;
726*3941Svenki 
727*3941Svenki 	mutex_exit(&sp->lock);
728*3941Svenki 
729*3941Svenki 	hdr.type = DS_SNMP_REQUEST;
730*3941Svenki 	bcopy((void *)&hdr, (void *)tmpbufp, sizeof (hdr));
731*3941Svenki 
732*3941Svenki 	/*
733*3941Svenki 	 * If the service went away since the time we entered this
734*3941Svenki 	 * routine and now, tough luck. Just ignore the current
735*3941Svenki 	 * write() and return.
736*3941Svenki 	 */
737*3941Svenki 	mutex_enter(&ds_snmp_lock);
738*3941Svenki 	if (ds_snmp_has_service == B_FALSE) {
739*3941Svenki 		DS_SNMP_DBG("ds_snmp_write: service went away, aborting "
740*3941Svenki 		    "write, returning ECANCELED\n");
741*3941Svenki 		mutex_exit(&ds_snmp_lock);
742*3941Svenki 		kmem_free(tmpbufp, len);
743*3941Svenki 		return (ECANCELED);
744*3941Svenki 	}
745*3941Svenki 	DS_SNMP_DBG("ds_snmp_write: ds_cap_send(0x%lx, %lu) called.\n",
746*3941Svenki 	    ds_snmp_handle, len);
747*3941Svenki 	(void) ds_cap_send(ds_snmp_handle, tmpbufp, len);
748*3941Svenki 	mutex_exit(&ds_snmp_lock);
749*3941Svenki 
750*3941Svenki 	kmem_free(tmpbufp, len);
751*3941Svenki 
752*3941Svenki 	return (0);
753*3941Svenki }
754*3941Svenki 
755*3941Svenki /*ARGSUSED*/
756*3941Svenki static int
757*3941Svenki ds_snmp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
758*3941Svenki     int *rvalp)
759*3941Svenki {
760*3941Svenki 	ds_snmp_state_t *sp;
761*3941Svenki 	struct dssnmp_info info;
762*3941Svenki 	minor_t	minor;
763*3941Svenki 
764*3941Svenki 	/*
765*3941Svenki 	 * Check if there was an sc reset; if yes, wait until we have the
766*3941Svenki 	 * service back again.
767*3941Svenki 	 */
768*3941Svenki 	mutex_enter(&ds_snmp_lock);
769*3941Svenki 	while (ds_snmp_has_service == B_FALSE) {
770*3941Svenki 		DS_SNMP_DBG("ds_snmp_ioctl: waiting for service\n");
771*3941Svenki 		if (cv_wait_sig(&ds_snmp_service_cv, &ds_snmp_lock) == 0) {
772*3941Svenki 			mutex_exit(&ds_snmp_lock);
773*3941Svenki 			return (EINTR);
774*3941Svenki 		}
775*3941Svenki 	}
776*3941Svenki 	mutex_exit(&ds_snmp_lock);
777*3941Svenki 
778*3941Svenki 	DS_SNMP_DBG("ds_snmp_ioctl: hdl=0x%lx\n", ds_snmp_handle);
779*3941Svenki 
780*3941Svenki 	minor = getminor(dev);
781*3941Svenki 	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
782*3941Svenki 		return (ENXIO);
783*3941Svenki 
784*3941Svenki 	if (!(mode & FREAD))
785*3941Svenki 		return (EACCES);
786*3941Svenki 
787*3941Svenki 	switch (cmd) {
788*3941Svenki 	case DSSNMP_GETINFO:
789*3941Svenki 		mutex_enter(&sp->lock);
790*3941Svenki 
791*3941Svenki 		if (sp->sc_reset == B_TRUE) {
792*3941Svenki 			mutex_exit(&sp->lock);
793*3941Svenki 			DS_SNMP_DBG("ds_snmp_ioctl: returning ECANCELED\n");
794*3941Svenki 			return (ECANCELED);
795*3941Svenki 		}
796*3941Svenki 
797*3941Svenki 		while (sp->state != DS_SNMP_DATA_AVL &&
798*3941Svenki 		    sp->state != DS_SNMP_DATA_ERR) {
799*3941Svenki 			DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, "
800*3941Svenki 			    "waiting for data\n", sp->state, sp->sc_reset);
801*3941Svenki 			if (cv_wait_sig(&sp->state_cv, &sp->lock) == 0) {
802*3941Svenki 				mutex_exit(&sp->lock);
803*3941Svenki 				return (EINTR);
804*3941Svenki 			}
805*3941Svenki 		}
806*3941Svenki 		DS_SNMP_DBG("ds_snmp_ioctl: state=%d, sc_reset=%d, "
807*3941Svenki 		    "out of wait!\n", sp->state, sp->sc_reset);
808*3941Svenki 
809*3941Svenki 		/*
810*3941Svenki 		 * If there has been an error, it could be because the
811*3941Svenki 		 * agent returned failure and there is no data to read,
812*3941Svenki 		 * or an ldc-reset has happened.  Figure out which and
813*3941Svenki 		 * return appropriate error to the caller.
814*3941Svenki 		 */
815*3941Svenki 		if (sp->state == DS_SNMP_DATA_ERR) {
816*3941Svenki 			if (sp->sc_reset == B_TRUE) {
817*3941Svenki 				mutex_exit(&sp->lock);
818*3941Svenki 				DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=TRUE "
819*3941Svenki 				    "returning ECANCELED\n");
820*3941Svenki 				return (ECANCELED);
821*3941Svenki 			} else {
822*3941Svenki 				sp->state = DS_SNMP_READY;
823*3941Svenki 				cv_broadcast(&sp->state_cv);
824*3941Svenki 				mutex_exit(&sp->lock);
825*3941Svenki 				DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=FALSE "
826*3941Svenki 				    "returning EIO\n");
827*3941Svenki 				return (EIO);
828*3941Svenki 			}
829*3941Svenki 		}
830*3941Svenki 
831*3941Svenki 		info.size = sp->data_len;
832*3941Svenki 		info.token = sp->gencount;
833*3941Svenki 
834*3941Svenki 		mutex_exit(&sp->lock);
835*3941Svenki 
836*3941Svenki 		if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
837*3941Svenki 			return (EFAULT);
838*3941Svenki 		break;
839*3941Svenki 
840*3941Svenki 	case DSSNMP_CLRLNKRESET:
841*3941Svenki 		mutex_enter(&sp->lock);
842*3941Svenki 
843*3941Svenki 		DS_SNMP_DBG("ds_snmp_ioctl: DSSNMP_CLRLNKRESET\n");
844*3941Svenki 		DS_SNMP_DBG("ds_snmp_ioctl: sc_reset=%d\n", sp->sc_reset);
845*3941Svenki 
846*3941Svenki 		if (sp->sc_reset == B_TRUE) {
847*3941Svenki 			if (sp->data) {
848*3941Svenki 				DS_SNMP_DBG("ds_snmp_ioctl: data=%p, len=%lu\n",
849*3941Svenki 				    sp->data, sp->data_len);
850*3941Svenki 				kmem_free(sp->data, sp->data_len);
851*3941Svenki 			}
852*3941Svenki 			sp->data = NULL;
853*3941Svenki 			sp->data_len = 0;
854*3941Svenki 			sp->state = DS_SNMP_READY;
855*3941Svenki 			sp->req_id = 0;
856*3941Svenki 			sp->last_req_id = 0;
857*3941Svenki 			sp->sc_reset = B_FALSE;
858*3941Svenki 		}
859*3941Svenki 		mutex_exit(&sp->lock);
860*3941Svenki 		break;
861*3941Svenki 
862*3941Svenki 	default:
863*3941Svenki 		return (ENOTTY);
864*3941Svenki 	}
865*3941Svenki 
866*3941Svenki 	return (0);
867*3941Svenki }
868*3941Svenki 
869*3941Svenki /*
870*3941Svenki  * DS Callbacks
871*3941Svenki  */
872*3941Svenki /*ARGSUSED*/
873*3941Svenki static void
874*3941Svenki ds_snmp_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
875*3941Svenki {
876*3941Svenki 	DS_SNMP_DBG("ds_snmp_reg_handler: registering handle 0x%lx for version "
877*3941Svenki 	    "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
878*3941Svenki 
879*3941Svenki 	mutex_enter(&ds_snmp_lock);
880*3941Svenki 
881*3941Svenki 	ASSERT(ds_snmp_handle == DS_INVALID_HDL);
882*3941Svenki 
883*3941Svenki 	ds_snmp_handle = hdl;
884*3941Svenki 	ds_snmp_has_service = B_TRUE;
885*3941Svenki 
886*3941Svenki 	cv_broadcast(&ds_snmp_service_cv);
887*3941Svenki 
888*3941Svenki 	mutex_exit(&ds_snmp_lock);
889*3941Svenki 
890*3941Svenki }
891*3941Svenki 
892*3941Svenki /*ARGSUSED*/
893*3941Svenki static void
894*3941Svenki ds_snmp_unreg_handler(ds_cb_arg_t arg)
895*3941Svenki {
896*3941Svenki 	minor_t minor;
897*3941Svenki 	ds_snmp_state_t *sp;
898*3941Svenki 
899*3941Svenki 	DS_SNMP_DBG("ds_snmp_unreg_handler: un-registering ds_snmp service\n");
900*3941Svenki 
901*3941Svenki 	mutex_enter(&ds_snmp_lock);
902*3941Svenki 
903*3941Svenki 	if (ds_snmp_num_opens) {
904*3941Svenki 		DS_SNMP_DBG("ds_snmp_unreg_handler: %d opens, sc reset!\n",
905*3941Svenki 		    ds_snmp_num_opens);
906*3941Svenki 		for (minor = 1; minor <= DS_SNMP_MAX_OPENS; minor++) {
907*3941Svenki 			if (ds_snmp_is_open(minor)) {
908*3941Svenki 				DS_SNMP_DBG("ds_snmp_unreg_handler: minor %d "
909*3941Svenki 				    "open\n", minor);
910*3941Svenki 				sp = ddi_get_soft_state(ds_snmp_statep, minor);
911*3941Svenki 				if (sp == NULL)
912*3941Svenki 					continue;
913*3941Svenki 
914*3941Svenki 				/*
915*3941Svenki 				 * Set the sc_reset flag and break any waiters
916*3941Svenki 				 * out of their existing reads/writes/ioctls.
917*3941Svenki 				 */
918*3941Svenki 				DS_SNMP_DBG("ds_snmp_unreg_hdlr: about to "
919*3941Svenki 				    "signal waiters\n");
920*3941Svenki 				mutex_enter(&sp->lock);
921*3941Svenki 				sp->sc_reset = B_TRUE;
922*3941Svenki 				sp->state = DS_SNMP_DATA_ERR;
923*3941Svenki 				cv_broadcast(&sp->state_cv);
924*3941Svenki 				mutex_exit(&sp->lock);
925*3941Svenki 			}
926*3941Svenki 		}
927*3941Svenki 	}
928*3941Svenki 
929*3941Svenki 	ds_snmp_handle = DS_INVALID_HDL;
930*3941Svenki 	ds_snmp_has_service = B_FALSE;
931*3941Svenki 
932*3941Svenki 	DS_SNMP_DBG("ds_snmp_unreg_handler: handle invalidated\n");
933*3941Svenki 
934*3941Svenki 	mutex_exit(&ds_snmp_lock);
935*3941Svenki }
936*3941Svenki 
937*3941Svenki /*ARGSUSED*/
938*3941Svenki static void
939*3941Svenki ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
940*3941Svenki {
941*3941Svenki 	ds_snmp_state_t *sp;
942*3941Svenki 	ds_snmp_msg_t   hdr;
943*3941Svenki 	size_t  	snmp_size;
944*3941Svenki 	minor_t 	minor;
945*3941Svenki 
946*3941Svenki 	/*
947*3941Svenki 	 * Make sure the header is at least valid
948*3941Svenki 	 */
949*3941Svenki 	if (buflen < sizeof (hdr)) {
950*3941Svenki 		cmn_err(CE_WARN,
951*3941Svenki 		"ds_snmp_data_handler: buflen <%lu> too small", buflen);
952*3941Svenki 		return;
953*3941Svenki 	}
954*3941Svenki 
955*3941Svenki 	ASSERT(buf != NULL);
956*3941Svenki 	bcopy(buf, (void *)&hdr, sizeof (hdr));
957*3941Svenki 
958*3941Svenki 	DS_SNMP_DBG("ds_snmp_data_handler: msg buf len 0x%lx : type 0x%lx, "
959*3941Svenki 	    "seqn 0x%lx\n", buflen, hdr.type, hdr.seq_num);
960*3941Svenki 
961*3941Svenki 	minor = (int)(hdr.seq_num >> DS_SNMP_MINOR_SHIFT);
962*3941Svenki 	if ((sp = ddi_get_soft_state(ds_snmp_statep, minor)) == NULL)
963*3941Svenki 		return;
964*3941Svenki 
965*3941Svenki 	mutex_enter(&sp->lock);
966*3941Svenki 
967*3941Svenki 	/*
968*3941Svenki 	 * If there is no pending SNMP request, then we've received
969*3941Svenki 	 * bogus data or an SNMP trap. Since we don't yet support SNMP
970*3941Svenki 	 * traps, ignore it.
971*3941Svenki 	 */
972*3941Svenki 	if (sp->state != DS_SNMP_REQUESTED) {
973*3941Svenki 		cmn_err(CE_WARN, "Received SNMP data without request");
974*3941Svenki 		mutex_exit(&sp->lock);
975*3941Svenki 		return;
976*3941Svenki 	}
977*3941Svenki 
978*3941Svenki 	/*
979*3941Svenki 	 * Response to a request therefore old SNMP must've been consumed
980*3941Svenki 	 */
981*3941Svenki 	ASSERT(sp->data_len == 0);
982*3941Svenki 	ASSERT(sp->data == NULL);
983*3941Svenki 
984*3941Svenki 	/*
985*3941Svenki 	 * Response seq_num should match our request seq_num
986*3941Svenki 	 */
987*3941Svenki 	if (hdr.seq_num != sp->last_req_id) {
988*3941Svenki 		cmn_err(CE_WARN, "Received DS snmp data out of sequence with "
989*3941Svenki 		    "request");
990*3941Svenki 		mutex_exit(&sp->lock);
991*3941Svenki 		return;
992*3941Svenki 	}
993*3941Svenki 
994*3941Svenki 	if (hdr.type == DS_SNMP_ERROR) {
995*3941Svenki 		sp->state = DS_SNMP_DATA_ERR;
996*3941Svenki 		DS_SNMP_DBG("ds_snmp_data_handler: hdr.type = DS_SNMP_ERROR\n");
997*3941Svenki 	} else {
998*3941Svenki 		snmp_size = buflen - sizeof (ds_snmp_msg_t);
999*3941Svenki 		sp->data = kmem_alloc(snmp_size, KM_SLEEP);
1000*3941Svenki 		sp->data_len = snmp_size;
1001*3941Svenki 		sp->state = DS_SNMP_DATA_AVL;
1002*3941Svenki 
1003*3941Svenki 		bcopy((caddr_t)buf + sizeof (ds_snmp_msg_t),
1004*3941Svenki 		    sp->data, sp->data_len);
1005*3941Svenki 	}
1006*3941Svenki 
1007*3941Svenki 	sp->gencount++;
1008*3941Svenki 
1009*3941Svenki 	/*
1010*3941Svenki 	 * Wake up any readers waiting for data
1011*3941Svenki 	 */
1012*3941Svenki 	cv_broadcast(&sp->state_cv);
1013*3941Svenki 	mutex_exit(&sp->lock);
1014*3941Svenki }
1015