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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * sun4v domain services SNMP driver 30 */ 31 32 #include <sys/types.h> 33 #include <sys/file.h> 34 #include <sys/errno.h> 35 #include <sys/open.h> 36 #include <sys/cred.h> 37 #include <sys/uio.h> 38 #include <sys/stat.h> 39 #include <sys/ksynch.h> 40 #include <sys/modctl.h> 41 #include <sys/conf.h> 42 #include <sys/devops.h> 43 #include <sys/debug.h> 44 #include <sys/cmn_err.h> 45 #include <sys/ddi.h> 46 #include <sys/sunddi.h> 47 #include <sys/ds.h> 48 #include <sys/ds_snmp.h> 49 50 #define DS_SNMP_NAME "ds_snmp" 51 #define DS_SNMP_MAX_OPENS 256 52 #define DS_BITS_IN_UINT64 64 53 #define DS_MINOR_POOL_SZ (DS_SNMP_MAX_OPENS / DS_BITS_IN_UINT64) 54 #define DS_SNMP_MINOR_SHIFT 56 55 #define DS_SNMP_DBG if (ds_snmp_debug) printf 56 57 typedef struct { 58 uint64_t seq_num; 59 uint64_t type; 60 } ds_snmp_msg_t; 61 62 typedef enum { 63 DS_SNMP_REQUEST = 0, 64 DS_SNMP_REPLY = 1, 65 DS_SNMP_ERROR = 2 66 } ds_snmp_msg_type_t; 67 68 typedef enum { 69 DS_SNMP_READY = 0x0, 70 DS_SNMP_REQUESTED = 0x1, 71 DS_SNMP_DATA_AVL = 0x2, 72 DS_SNMP_DATA_ERR = 0x3 73 } ds_snmp_flags_t; 74 75 /* 76 * The single mutex 'lock' protects all the SNMP/DS variables in the state 77 * structure. 78 * 79 * The condition variable 'state_cv' helps serialize write() calls for a 80 * single descriptor. When write() is called, it sets a flag to indicate 81 * that an SNMP request has been made to the agent. No more write()'s on 82 * the same open descriptor will be allowed until this flag is cleared via 83 * a matching read(), where the requested packet is consumed on arrival. 84 * Read() then wakes up any waiters blocked in write() for sending the next 85 * SNMP request to the agent. 86 */ 87 typedef struct ds_snmp_state { 88 dev_info_t *dip; 89 int instance; 90 dev_t dev; 91 92 /* SNMP/DS */ 93 kmutex_t lock; 94 kcondvar_t state_cv; 95 ds_snmp_flags_t state; 96 void *data; 97 size_t data_len; 98 uint64_t req_id; 99 uint64_t last_req_id; 100 uint64_t gencount; 101 boolean_t sc_reset; 102 } ds_snmp_state_t; 103 104 105 static uint_t ds_snmp_debug = 0; 106 static void *ds_snmp_statep = NULL; 107 static int ds_snmp_instance = -1; 108 static dev_info_t *ds_snmp_devi = NULL; 109 110 /* 111 * The ds_snmp_lock mutex protects the following data global to the 112 * driver. 113 * 114 * The ds_snmp_service_cv condition variable is used to resolve the 115 * potential race between the registration of snmp service via a 116 * ds_cap_init() in attach(), the acknowledgement of this registration 117 * at a later time in ds_snmp_reg_handler(), and a possible open() at 118 * a time inbetween. The ds_snmp_has_service and ds_snmp_handle are 119 * used to indicate whether the registration acknowledgement has happened 120 * or not. 121 * 122 * The ds_snmp_minor_pool[] is a bitmask to allocate and keep track of 123 * minor numbers dynamically. 124 */ 125 static kmutex_t ds_snmp_lock; 126 static kcondvar_t ds_snmp_service_cv; 127 static int ds_snmp_has_service = B_FALSE; 128 static ds_svc_hdl_t ds_snmp_handle = DS_INVALID_HDL; 129 static uint64_t ds_snmp_minor_pool[DS_MINOR_POOL_SZ]; /* bitmask */ 130 static int ds_snmp_num_opens = 0; 131 132 static int ds_snmp_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 133 static int ds_snmp_attach(dev_info_t *, ddi_attach_cmd_t); 134 static int ds_snmp_detach(dev_info_t *, ddi_detach_cmd_t); 135 static int ds_snmp_open(dev_t *, int, int, cred_t *); 136 static int ds_snmp_close(dev_t, int, int, cred_t *); 137 static int ds_snmp_read(dev_t, struct uio *, cred_t *); 138 static int ds_snmp_write(dev_t, struct uio *, cred_t *); 139 static int ds_snmp_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 140 141 /* 142 * DS Callbacks 143 */ 144 static void ds_snmp_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t); 145 static void ds_snmp_unreg_handler(ds_cb_arg_t arg); 146 static void ds_snmp_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen); 147 148 /* 149 * SNMP DS capability registration 150 */ 151 static ds_ver_t ds_snmp_ver_1_0 = { 1, 0 }; 152 static ds_capability_t ds_snmp_cap = { 153 "snmp", 154 &ds_snmp_ver_1_0, 155 1 156 }; 157 158 /* 159 * SNMP DS Client callback vector 160 */ 161 static ds_clnt_ops_t ds_snmp_ops = { 162 ds_snmp_reg_handler, /* ds_reg_cb */ 163 ds_snmp_unreg_handler, /* ds_unreg_cb */ 164 ds_snmp_data_handler, /* ds_data_cb */ 165 NULL /* cb_arg */ 166 }; 167 168 /* 169 * DS SNMP driver Ops Vector 170 */ 171 static struct cb_ops ds_snmp_cb_ops = { 172 ds_snmp_open, /* cb_open */ 173 ds_snmp_close, /* cb_close */ 174 nodev, /* cb_strategy */ 175 nodev, /* cb_print */ 176 nodev, /* cb_dump */ 177 ds_snmp_read, /* cb_read */ 178 ds_snmp_write, /* cb_write */ 179 ds_snmp_ioctl, /* cb_ioctl */ 180 nodev, /* cb_devmap */ 181 nodev, /* cb_mmap */ 182 nodev, /* cb_segmap */ 183 nochpoll, /* cb_chpoll */ 184 ddi_prop_op, /* cb_prop_op */ 185 (struct streamtab *)NULL, /* cb_str */ 186 D_MP | D_64BIT, /* cb_flag */ 187 CB_REV, /* cb_rev */ 188 nodev, /* cb_aread */ 189 nodev /* cb_awrite */ 190 }; 191 192 static struct dev_ops ds_snmp_dev_ops = { 193 DEVO_REV, /* devo_rev */ 194 0, /* devo_refcnt */ 195 ds_snmp_getinfo, /* devo_getinfo */ 196 nulldev, /* devo_identify */ 197 nulldev, /* devo_probe */ 198 ds_snmp_attach, /* devo_attach */ 199 ds_snmp_detach, /* devo_detach */ 200 nodev, /* devo_reset */ 201 &ds_snmp_cb_ops, /* devo_cb_ops */ 202 (struct bus_ops *)NULL, /* devo_bus_ops */ 203 nulldev /* devo_power */ 204 }; 205 206 static struct modldrv modldrv = { 207 &mod_driverops, 208 "Domain Services SNMP Driver 1.0", 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