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