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