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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * The SNMP picl plugin connects to the agent on the SP and creates 29 * and populates the /physical-platform subtree in picl tree for use 30 * by picl consumers. 31 */ 32 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <syslog.h> 37 #include <stdarg.h> 38 #include <libgen.h> 39 #include <libintl.h> 40 #include <thread.h> 41 #include <synch.h> 42 #include <errno.h> 43 #include <time.h> 44 #include <signal.h> 45 46 #include <picldefs.h> 47 #include <picl.h> 48 #include <picltree.h> 49 50 #include "picloids.h" 51 #include "libpiclsnmp.h" 52 #include "snmpplugin.h" 53 54 #pragma init(snmpplugin_register) /* place in .init section */ 55 56 picld_plugin_reg_t snmpplugin_reg = { 57 PICLD_PLUGIN_VERSION_1, 58 PICLD_PLUGIN_NON_CRITICAL, 59 "snmp_plugin", 60 snmpplugin_init, 61 snmpplugin_fini 62 }; 63 64 static picl_snmphdl_t hdl; 65 66 /* 67 * The stale_tree_rwlp protects the stale_xxx vars. The 'stale_tree' flag 68 * and the 'rebuild_tree' flag below are both initialized to B_TRUE to 69 * let the tree_builder() thread build the initial tree without blocking. 70 */ 71 static rwlock_t stale_tree_rwlp; 72 static boolean_t stale_tree = B_TRUE; 73 74 /* 75 * vol_props, volprop_ndx and n_vol_props are protected by the stale_tree 76 * flag. They are read only when the stale_tree flag is B_FALSE and written 77 * to only when the flag is B_TRUE. 78 * 79 * The change_time (last changed time) is read by only one thread at a 80 * time when stale_tree is B_FALSE (protected by stale_tree_rwlp). It is 81 * written by only one thread (the tree builder) when stale_tree is B_TRUE. 82 * 83 * Note that strictly speaking, change_time should be uint_t (timeticks32). 84 * But keeping it as int is fine, since we don't do any arithmetic on it 85 * except equality check. 86 */ 87 static vol_prophdl_t *vol_props = NULL; 88 static int volprop_ndx = 0, n_vol_props = 0; 89 static int change_time = 0; 90 static time_t change_time_check; 91 92 /* 93 * The rebuild_tree_lock and cv are used by the tree builder thread. 94 * rebuild_tree has to be initialized to B_TRUE to let the tree_builder 95 * do the first build without blocking. 96 */ 97 static mutex_t rebuild_tree_lock; 98 static cond_t rebuild_tree_cv; 99 static boolean_t rebuild_tree = B_TRUE; 100 static boolean_t tree_builder_thr_exit = B_FALSE; 101 static thread_t tree_builder_thr_id; 102 103 /* 104 * The cache_refresh thread periodically queries the snmp cache refresh work 105 * queue and processes jobs from it to keep cache entries from expiring. It 106 * attempts to run in cycles of CACHE_REFRESH_CYCLE seconds each, first 107 * processing cache refresh jobs and then sleeping for the remainder of the 108 * cycle once the next refresh job expiration is at least 109 * CACHE_REFRESH_MIN_WINDOW seconds in the future. 110 * 111 * NOTE: By using a thread to keep the SNMP cache refreshed in the background, 112 * we are both adding load to the system and reducing the system's ability to 113 * operate in power-saving mode when there is minimal load. While these 114 * tradeoffs are acceptable at this time in light of customer concerns about 115 * performance, it may be desirable in the future to move this work into the 116 * firmware. Also, while the current cycle times performed well on the largest 117 * sun4v config currently available (Batoka), they may need to be revisited for 118 * future systems if the number of sensors increases significantly. 119 */ 120 #define CACHE_REFRESH_CYCLE 60 121 #define CACHE_REFRESH_MIN_WINDOW 75 122 static mutex_t cache_refresh_lock; 123 static cond_t cache_refresh_cv; 124 static boolean_t cache_refresh_thr_exit = B_FALSE; 125 static thread_t cache_refresh_thr_id; 126 127 /* 128 * These two should really not be global 129 */ 130 static picl_nodehdl_t *physplat_nodes = NULL; 131 static int n_physplat_nodes = 0; 132 133 static char *group1[] = { 134 OID_entPhysicalDescr, 135 OID_entPhysicalContainedIn, 136 OID_entPhysicalClass, 137 OID_entPhysicalName, 138 OID_entPhysicalHardwareRev, 139 OID_entPhysicalFirmwareRev, 140 OID_entPhysicalSerialNum, 141 OID_entPhysicalMfgName, 142 OID_entPhysicalModelName, 143 OID_entPhysicalIsFRU, 144 0 145 }; 146 147 static char *group2[] = { 148 OID_sunPlatEquipmentHolderAcceptableTypes, 149 OID_sunPlatCircuitPackReplaceable, 150 OID_sunPlatCircuitPackHotSwappable, 151 OID_sunPlatPhysicalClass, 152 OID_sunPlatSensorClass, 153 OID_sunPlatSensorType, 154 OID_sunPlatAlarmType, 155 OID_sunPlatPowerSupplyClass, 156 0 157 }; 158 159 static char *group3[] = { 160 OID_sunPlatNumericSensorEnabledThresholds, 161 OID_sunPlatNumericSensorBaseUnits, 162 OID_sunPlatNumericSensorRateUnits, 163 0 164 }; 165 166 static char *group4[] = { 167 OID_sunPlatBinarySensorInterpretTrue, 168 OID_sunPlatBinarySensorInterpretFalse, 169 0 170 }; 171 172 static char *volgroup1[] = { 173 OID_sunPlatBinarySensorCurrent, 174 OID_sunPlatBinarySensorExpected, 175 0 176 }; 177 178 static char *volgroup2[] = { 179 OID_sunPlatNumericSensorExponent, 180 OID_sunPlatNumericSensorCurrent, 181 OID_sunPlatNumericSensorLowerThresholdFatal, 182 OID_sunPlatNumericSensorLowerThresholdCritical, 183 OID_sunPlatNumericSensorLowerThresholdNonCritical, 184 OID_sunPlatNumericSensorUpperThresholdNonCritical, 185 OID_sunPlatNumericSensorUpperThresholdCritical, 186 OID_sunPlatNumericSensorUpperThresholdFatal, 187 0 188 }; 189 190 static char *volgroup3[] = { 191 OID_sunPlatEquipmentOperationalState, 192 0 193 }; 194 195 static char *volgroup4[] = { 196 OID_sunPlatAlarmState, 197 0 198 }; 199 200 static char *volgroup5[] = { 201 OID_sunPlatBatteryStatus, 202 0 203 }; 204 205 /* 206 * The following two items must match the Sun Platform MIB specification 207 * in their indices and values. 208 */ 209 static char *sensor_baseunits[] = { 210 "", "other", "unknown", "degC", "degF", "degK", "volts", "amps", 211 "watts", "joules", "coulombs", "va", "nits", "lumens", "lux", 212 "candelas", "kPa", "psi", "newtons", "cfm", "rpm", "hertz", 213 "seconds", "minutes", "hours", "days", "weeks", "mils", "inches", 214 "feet", "cubicInches", "cubicFeet", "meters", "cubicCentimeters", 215 "cubicMeters", "liters", "fluidOunces", "radians", "steradians", 216 "revolutions", "cycles", "gravities", "ounces", "pounds", "footPounds", 217 "ounceInches", "gauss", "gilberts", "henries", "farads", "ohms", 218 "siemens", "moles", "becquerels", "ppm", "decibels", "dBA", "dbC", 219 "grays", "sieverts", "colorTemperatureDegK", "bits", "bytes", "words", 220 "doubleWords", "quadWords", "percentage" 221 }; 222 static const int n_baseunits = sizeof (sensor_baseunits) / sizeof (char *); 223 224 static char *sensor_rateunits[] = { 225 "", 226 "none", 227 "perMicroSecond", 228 "perMilliSecond", 229 "perSecond", 230 "perMinute", 231 "perHour", 232 "perDay", 233 "perWeek", 234 "perMonth", 235 "perYear" 236 }; 237 static const int n_rateunits = sizeof (sensor_rateunits) / sizeof (char *); 238 239 /* 240 * Local declarations 241 */ 242 static void snmpplugin_register(void); 243 static void register_group(char **g, int is_volatile); 244 static void *tree_builder(void *arg); 245 static int build_physplat(picl_nodehdl_t *subtree_rootp); 246 static void free_resources(picl_nodehdl_t subtree_root); 247 248 static picl_nodehdl_t make_node(picl_nodehdl_t subtree_root, int row, 249 int *snmp_syserr_p); 250 static void save_nodeh(picl_nodehdl_t nodeh, int row); 251 static picl_nodehdl_t lookup_nodeh(int row); 252 253 static void save_volprop(picl_prophdl_t prop, char *oidstr, int row, 254 int proptype); 255 static void check_for_stale_data(boolean_t nocache); 256 static int read_volprop(ptree_rarg_t *parg, void *buf); 257 258 static void threshold(picl_nodehdl_t node, char *oidstr, int row, 259 char *propname, int *snmp_syserr_p); 260 static void add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p); 261 262 static char *get_slot_type(int row, int *snmp_syserr_p); 263 static int add_volatile_prop(picl_nodehdl_t nodeh, char *name, 264 int type, int access, int size, int (*rdfunc)(ptree_rarg_t *, void *), 265 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp); 266 static int add_string_prop(picl_nodehdl_t node, char *propname, char *propval); 267 static int add_void_prop(picl_nodehdl_t node, char *propname); 268 static void add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 269 int row, sp_propid_t pp, int *snmp_syserr_p); 270 271 static void *cache_refresher(void *arg); 272 static void cache_refresher_fini(void); 273 274 static void log_msg(int pri, const char *fmt, ...); 275 276 #ifdef SNMPPLUGIN_DEBUG 277 static mutex_t snmpplugin_dbuf_lock; 278 static char *snmpplugin_dbuf = NULL; 279 static char *snmpplugin_dbuf_curp = NULL; 280 static int snmpplugin_dbuf_sz = 0; 281 static int snmpplugin_dbuf_overflow = 0; 282 static char snmpplugin_lbuf[SNMPPLUGIN_DMAX_LINE]; 283 284 static void snmpplugin_log_init(void); 285 static void snmpplugin_log(const char *fmt, ...); 286 static void snmpplugin_log_append(void); 287 static void snmpplugin_dbuf_realloc(void); 288 #endif 289 290 static void 291 snmpplugin_register(void) 292 { 293 (void) picld_plugin_register(&snmpplugin_reg); 294 } 295 296 static void 297 register_group(char **g, int is_volatile) 298 { 299 int i, len = 0; 300 int n_oids; 301 char *p, *oidstrs; 302 303 for (i = 0; g[i]; i++) 304 len += strlen(g[i]) + 1; 305 n_oids = i; 306 307 if ((oidstrs = (char *)calloc(1, len)) == NULL) 308 return; 309 310 for (p = oidstrs, i = 0; g[i]; i++) { 311 (void) strcpy(p, g[i]); 312 p += strlen(g[i]) + 1; 313 } 314 315 snmp_register_group(hdl, oidstrs, n_oids, is_volatile); 316 free(oidstrs); 317 } 318 319 void 320 snmpplugin_init(void) 321 { 322 int ret; 323 324 (void) mutex_init(&rebuild_tree_lock, USYNC_THREAD, NULL); 325 (void) cond_init(&rebuild_tree_cv, USYNC_THREAD, NULL); 326 (void) rwlock_init(&stale_tree_rwlp, USYNC_THREAD, NULL); 327 tree_builder_thr_exit = B_FALSE; 328 329 LOGINIT(); 330 331 /* 332 * Create the tree-builder thread and let it take over 333 */ 334 LOGPRINTF("Tree-builder thread being created.\n"); 335 if ((ret = thr_create(NULL, 0, tree_builder, NULL, 336 THR_BOUND, &tree_builder_thr_id)) < 0) { 337 log_msg(LOG_ERR, SNMPP_CANT_CREATE_TREE_BUILDER, ret); 338 snmp_fini(hdl); 339 hdl = NULL; 340 (void) rwlock_destroy(&stale_tree_rwlp); 341 (void) cond_destroy(&rebuild_tree_cv); 342 (void) mutex_destroy(&rebuild_tree_lock); 343 tree_builder_thr_exit = B_TRUE; 344 345 return; 346 } 347 348 /* 349 * While the cache refresher thread does improve performance, it is not 350 * integral to the proper function of the plugin. If we fail to create 351 * the thread for some reason, we will simply continue without 352 * refreshing. 353 */ 354 (void) mutex_init(&cache_refresh_lock, USYNC_THREAD, NULL); 355 (void) cond_init(&cache_refresh_cv, USYNC_THREAD, NULL); 356 cache_refresh_thr_exit = B_FALSE; 357 358 LOGPRINTF("Cache refresher thread being created.\n"); 359 if (thr_create(NULL, 0, cache_refresher, NULL, THR_BOUND, 360 &cache_refresh_thr_id) < 0) { 361 (void) cond_destroy(&cache_refresh_cv); 362 (void) mutex_destroy(&cache_refresh_lock); 363 cache_refresh_thr_exit = B_TRUE; 364 } 365 } 366 367 void 368 snmpplugin_fini(void) 369 { 370 371 if (tree_builder_thr_exit == B_TRUE) 372 return; 373 374 /* 375 * Make reads of volatile properties return PICL_PROPUNAVAILABLE 376 * since we're about to recycle the plug-in. No need to worry 377 * about removing /physical-platform since tree_builder() will 378 * take care of recycling it for us. 379 */ 380 (void) rw_wrlock(&stale_tree_rwlp); 381 stale_tree = B_TRUE; 382 if (vol_props) { 383 free(vol_props); 384 } 385 vol_props = NULL; 386 volprop_ndx = 0; 387 n_vol_props = 0; 388 (void) rw_unlock(&stale_tree_rwlp); 389 390 /* clean up the cache_refresher thread and structures */ 391 cache_refresher_fini(); 392 393 /* wake up the tree_builder thread, tell it to exit */ 394 (void) mutex_lock(&rebuild_tree_lock); 395 rebuild_tree = B_TRUE; 396 tree_builder_thr_exit = B_TRUE; 397 (void) cond_signal(&rebuild_tree_cv); 398 (void) mutex_unlock(&rebuild_tree_lock); 399 400 /* send SIGUSR1 to get tree_builder out of a blocked system call */ 401 (void) thr_kill(tree_builder_thr_id, SIGUSR1); 402 403 /* reap the thread */ 404 (void) thr_join(tree_builder_thr_id, NULL, NULL); 405 406 /* close the channel */ 407 if (hdl != NULL) { 408 snmp_fini(hdl); 409 hdl = NULL; 410 } 411 412 /* finish cleanup... */ 413 (void) rwlock_destroy(&stale_tree_rwlp); 414 (void) cond_destroy(&rebuild_tree_cv); 415 (void) mutex_destroy(&rebuild_tree_lock); 416 } 417 418 /*ARGSUSED*/ 419 static void 420 usr1_handler(int sig, siginfo_t *siginfo, void *sigctx) 421 { 422 /* 423 * Nothing to do here. 424 * The act of catching the signal causes any cond_wait() or blocked 425 * system call to return EINTR. This is used to trigger early exit from 426 * the tree builder thread which may be blocked in snmp_init. More work 427 * would be required to allow early exit if the tree builder thread is 428 * already in its main processing loop and not blocked in cond_wait. 429 */ 430 } 431 432 /*ARGSUSED*/ 433 static void * 434 tree_builder(void *arg) 435 { 436 int ret, rv; 437 picl_nodehdl_t root_node; 438 picl_nodehdl_t physplat_root; 439 picl_nodehdl_t old_physplat_root; 440 struct sigaction act; 441 442 /* 443 * catch SIGUSR1 to allow early exit from snmp_init which may block 444 * indefinitely in a guest domain. 445 */ 446 act.sa_sigaction = usr1_handler; 447 (void) sigemptyset(&act.sa_mask); 448 act.sa_flags = 0; 449 if (sigaction(SIGUSR1, &act, NULL) == -1) { 450 syslog(LOG_ERR, SIGACT_FAILED, strsignal(SIGUSR1), 451 strerror(errno)); 452 } 453 454 /* 455 * Initialize SNMP service 456 */ 457 LOGPRINTF("Initializing SNMP service.\n"); 458 if ((hdl = snmp_init()) == NULL) { 459 log_msg(LOG_ERR, SNMPP_CANT_INIT); 460 return ((void *)-1); 461 } 462 463 /* 464 * Register OID groupings for BULKGET optimizations 465 */ 466 LOGPRINTF("Registering OID groups.\n"); 467 register_group(group1, 0); 468 register_group(group2, 0); 469 register_group(group3, 0); 470 register_group(group4, 0); 471 register_group(volgroup1, 1); 472 register_group(volgroup2, 1); 473 register_group(volgroup3, 1); 474 register_group(volgroup4, 1); 475 register_group(volgroup5, 1); 476 477 (void) mutex_lock(&rebuild_tree_lock); 478 479 for (;;) { 480 LOGPRINTF("tree_builder: check whether to rebuild subtree\n"); 481 while (rebuild_tree == B_FALSE) 482 (void) cond_wait(&rebuild_tree_cv, &rebuild_tree_lock); 483 484 LOGPRINTF("tree_builder: woke up\n"); 485 486 if (tree_builder_thr_exit == B_TRUE) { 487 (void) mutex_unlock(&rebuild_tree_lock); 488 LOGPRINTF("tree_builder: time to exit\n"); 489 return (NULL); 490 } 491 492 old_physplat_root = 0; 493 physplat_root = 0; 494 495 LOGPRINTF("tree_builder: getting root node\n"); 496 if ((ret = ptree_get_root(&root_node)) != PICL_SUCCESS) { 497 (void) mutex_unlock(&rebuild_tree_lock); 498 log_msg(LOG_ERR, SNMPP_NO_ROOT, ret); 499 return ((void *)-2); 500 } 501 502 LOGPRINTF("tree_builder: getting existing physplat node\n"); 503 rv = ptree_find_node(root_node, PICL_PROP_NAME, 504 PICL_PTYPE_CHARSTRING, PICL_NODE_PHYSPLAT, 505 sizeof (PICL_NODE_PHYSPLAT), &old_physplat_root); 506 507 LOGPRINTF("tree_builder: building physical-platform\n"); 508 if ((ret = build_physplat(&physplat_root)) < 0) { 509 (void) mutex_unlock(&rebuild_tree_lock); 510 log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); 511 cache_refresher_fini(); 512 snmp_fini(hdl); 513 hdl = NULL; 514 return ((void *)-3); 515 } 516 517 if (rv == PICL_SUCCESS && old_physplat_root != 0) { 518 LOGPRINTF("tree_builder: destroying existing nodes\n"); 519 ptree_delete_node(old_physplat_root); 520 ptree_destroy_node(old_physplat_root); 521 } 522 523 LOGPRINTF("tree_builder: attaching new subtree\n"); 524 if ((ret = ptree_add_node(root_node, physplat_root)) < 0) { 525 (void) mutex_unlock(&rebuild_tree_lock); 526 free_resources(physplat_root); 527 log_msg(LOG_ERR, SNMPP_CANT_CREATE_PHYSPLAT, ret); 528 cache_refresher_fini(); 529 snmp_fini(hdl); 530 hdl = NULL; 531 return ((void *)-4); 532 } 533 534 LOGPRINTF("tree_builder: setting stale_tree to FALSE\n"); 535 (void) rw_wrlock(&stale_tree_rwlp); 536 stale_tree = B_FALSE; 537 (void) rw_unlock(&stale_tree_rwlp); 538 539 LOGPRINTF("tree_builder: setting rebuild_tree to FALSE\n"); 540 rebuild_tree = B_FALSE; 541 } 542 543 /*NOTREACHED*/ 544 return (NULL); 545 } 546 547 static int 548 build_physplat(picl_nodehdl_t *subtree_rootp) 549 { 550 int change_time1; 551 int row, nxtrow; 552 int clr_linkreset = 0; 553 int ret = 0; 554 int snmp_syserr = 0; 555 556 retry: 557 (void) snmp_reinit(hdl, clr_linkreset); 558 clr_linkreset = 0; 559 560 /* 561 * Record LastChangeTime before we start building the tree 562 */ 563 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 564 &change_time1, &snmp_syserr); 565 if (ret < 0) { 566 if (snmp_syserr == ECANCELED) { 567 LOGPRINTF(SNMPP_LINK_RESET); 568 clr_linkreset = 1; 569 goto retry; 570 } 571 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 572 snmp_syserr ? snmp_syserr : ret, OID_entLastChangeTime, 0); 573 } 574 575 /* 576 * Create the physical-platform node 577 */ 578 ret = ptree_create_node(PICL_NODE_PHYSPLAT, PICL_CLASS_PICL, 579 subtree_rootp); 580 if (ret != PICL_SUCCESS) 581 return (-1); 582 583 /* 584 * Scan entPhysicalTable and build the "physical-platform" subtree 585 */ 586 ret = 0; 587 for (row = -1; ret == 0; row = nxtrow) { 588 ret = snmp_get_nextrow(hdl, OID_entPhysicalDescr, 589 row, &nxtrow, &snmp_syserr); 590 if (ret == 0) 591 (void) make_node(*subtree_rootp, nxtrow, &snmp_syserr); 592 switch (snmp_syserr) { 593 case ECANCELED: 594 /* 595 * If we get this error, a link reset must've 596 * happened and we need to throw away everything 597 * we have now and rebuild the tree again. 598 */ 599 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 600 free_resources(*subtree_rootp); 601 clr_linkreset = 1; 602 goto retry; 603 /*NOTREACHED*/ 604 break; 605 case ENOSPC: /* end of MIB */ 606 LOGPRINTF("build_physplat: end of MIB\n"); 607 break; 608 case ENOENT: /* end of table */ 609 LOGPRINTF("build_physplat: end of table\n"); 610 break; 611 default: 612 /* 613 * make_node() will print messages so don't 614 * repeat that exercise here. 615 */ 616 if (ret == -1) { 617 log_msg(LOG_WARNING, 618 SNMPP_CANT_FETCH_OBJECT_VAL, 619 snmp_syserr ? snmp_syserr : ret, 620 OID_entPhysicalDescr, row); 621 } 622 } 623 } 624 625 /* 626 * Record LastChangeTime after we're done building the tree 627 */ 628 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 629 &change_time, &snmp_syserr); 630 if (ret < 0) { 631 if (snmp_syserr == ECANCELED) { 632 log_msg(LOG_WARNING, SNMPP_LINK_RESET); 633 free_resources(*subtree_rootp); 634 clr_linkreset = 1; 635 goto retry; 636 } else 637 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 638 snmp_syserr ? snmp_syserr : ret, 639 OID_entLastChangeTime, row); 640 } 641 642 /* 643 * If they don't match, some hotplugging must've happened, 644 * free resources we've created and still holding, then go 645 * back and retry 646 */ 647 if (change_time != change_time1) { 648 LOGPRINTF("build_physplat: entLastChangeTime has changed!\n"); 649 free_resources(*subtree_rootp); 650 change_time1 = change_time; 651 goto retry; 652 } 653 654 /* 655 * The physplat_nodes table is no longer needed, free it 656 */ 657 if (physplat_nodes) { 658 free(physplat_nodes); 659 physplat_nodes = NULL; 660 n_physplat_nodes = 0; 661 } 662 663 return (0); 664 } 665 666 /* 667 * Destroy all resources that were created during the building 668 * of the subtree 669 */ 670 static void 671 free_resources(picl_nodehdl_t subtree_root) 672 { 673 if (physplat_nodes) { 674 free(physplat_nodes); 675 physplat_nodes = NULL; 676 n_physplat_nodes = 0; 677 } 678 679 if (subtree_root) { 680 (void) ptree_delete_node(subtree_root); 681 (void) ptree_destroy_node(subtree_root); 682 } 683 684 if (vol_props) { 685 free(vol_props); 686 vol_props = NULL; 687 n_vol_props = 0; 688 volprop_ndx = 0; 689 } 690 } 691 692 static picl_nodehdl_t 693 make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p) 694 { 695 picl_nodehdl_t nodeh, parenth; 696 picl_prophdl_t proph; 697 char *phys_name, *node_name; 698 int parent_row; 699 int ent_physclass, sunplat_physclass; 700 int sensor_class, sensor_type; 701 int alarm_type; 702 int ps_class; 703 int ret; 704 705 /* 706 * If we've already created this picl node, just return it 707 */ 708 if ((nodeh = lookup_nodeh(row)) != 0) 709 return (nodeh); 710 711 /* 712 * If we are creating it only now, make sure we have the parent 713 * created first; if there's no parent, then parent it to the 714 * subtree's root node 715 */ 716 ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row, 717 &parent_row, snmp_syserr_p); 718 CHECK_LINKRESET(snmp_syserr_p, 0) 719 if (ret < 0 || parent_row <= 0) 720 parenth = subtree_root; 721 else { 722 parenth = make_node(subtree_root, parent_row, snmp_syserr_p); 723 CHECK_LINKRESET(snmp_syserr_p, 0) 724 if (parenth == 0) 725 parenth = subtree_root; 726 } 727 728 /* 729 * Figure out the physical-platform node name from entPhysicalName; 730 * all rows in the MIB that have a valid entPhysicalIndex should 731 * have a physical name. 732 */ 733 ret = snmp_get_str(hdl, OID_entPhysicalName, row, 734 &phys_name, snmp_syserr_p); 735 CHECK_LINKRESET(snmp_syserr_p, 0) 736 if (ret < 0 || phys_name == NULL) { 737 log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row); 738 return (0); 739 } 740 741 node_name = basename(phys_name); 742 743 ret = snmp_get_int(hdl, OID_entPhysicalClass, row, 744 &ent_physclass, snmp_syserr_p); 745 CHECK_LINKRESET(snmp_syserr_p, 0) 746 if (ret < 0) { 747 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 748 *snmp_syserr_p ? *snmp_syserr_p : ret, 749 OID_entPhysicalClass, row); 750 free(phys_name); 751 return (0); 752 } 753 754 switch (ent_physclass) { 755 case SPC_OTHER: 756 ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row, 757 &sunplat_physclass, snmp_syserr_p); 758 CHECK_LINKRESET(snmp_syserr_p, 0) 759 if (ret < 0) { 760 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 761 *snmp_syserr_p ? *snmp_syserr_p : ret, 762 OID_sunPlatPhysicalClass, row); 763 free(phys_name); 764 return (0); 765 } 766 767 if (sunplat_physclass == SSPC_ALARM) { 768 ret = snmp_get_int(hdl, OID_sunPlatAlarmType, 769 row, &alarm_type, snmp_syserr_p); 770 CHECK_LINKRESET(snmp_syserr_p, 0) 771 if (ret < 0) { 772 log_msg(LOG_WARNING, 773 SNMPP_CANT_FETCH_OBJECT_VAL, 774 *snmp_syserr_p ? *snmp_syserr_p : ret, 775 OID_sunPlatAlarmType, row); 776 free(phys_name); 777 return (0); 778 } 779 780 if (alarm_type == SSAT_VISIBLE) { 781 ADD_NODE(PICL_CLASS_LED) 782 } else { 783 ADD_NODE(PICL_CLASS_ALARM) 784 } 785 786 add_prop(nodeh, &proph, node_name, row, PP_STATE, 787 snmp_syserr_p); 788 CHECK_LINKRESET(snmp_syserr_p, 0) 789 } else { 790 ADD_NODE(PICL_CLASS_OTHER) 791 } 792 793 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 794 snmp_syserr_p); 795 CHECK_LINKRESET(snmp_syserr_p, 0) 796 break; 797 798 case SPC_UNKNOWN: 799 ADD_NODE(PICL_CLASS_UNKNOWN) 800 break; 801 802 case SPC_CHASSIS: 803 ADD_NODE(PICL_CLASS_CHASSIS) 804 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 805 snmp_syserr_p); 806 CHECK_LINKRESET(snmp_syserr_p, 0) 807 break; 808 809 case SPC_BACKPLANE: 810 ADD_NODE(PICL_CLASS_BACKPLANE) 811 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 812 snmp_syserr_p); 813 CHECK_LINKRESET(snmp_syserr_p, 0) 814 break; 815 816 case SPC_CONTAINER: 817 ADD_NODE(PICL_CLASS_CONTAINER) 818 819 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 820 snmp_syserr_p); 821 CHECK_LINKRESET(snmp_syserr_p, 0) 822 823 add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE, 824 snmp_syserr_p); 825 CHECK_LINKRESET(snmp_syserr_p, 0) 826 break; 827 828 case SPC_POWERSUPPLY: 829 ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass, 830 row, &ps_class, snmp_syserr_p); 831 CHECK_LINKRESET(snmp_syserr_p, 0) 832 if (ret < 0) { 833 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 834 *snmp_syserr_p ? *snmp_syserr_p : ret, 835 OID_sunPlatPowerSupplyClass, row); 836 free(phys_name); 837 return (0); 838 } 839 840 if (ps_class == SSPSC_BATTERY) { 841 ADD_NODE(PICL_CLASS_BATTERY) 842 add_prop(nodeh, &proph, node_name, row, 843 PP_BATT_STATUS, snmp_syserr_p); 844 CHECK_LINKRESET(snmp_syserr_p, 0) 845 } else { 846 ADD_NODE(PICL_CLASS_POWERSUPPLY) 847 } 848 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 849 snmp_syserr_p); 850 CHECK_LINKRESET(snmp_syserr_p, 0) 851 break; 852 853 case SPC_FAN: 854 ADD_NODE(PICL_CLASS_FAN) 855 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 856 snmp_syserr_p); 857 CHECK_LINKRESET(snmp_syserr_p, 0) 858 break; 859 860 case SPC_SENSOR: 861 ret = snmp_get_int(hdl, OID_sunPlatSensorClass, 862 row, &sensor_class, snmp_syserr_p); 863 CHECK_LINKRESET(snmp_syserr_p, 0) 864 if (ret < 0) { 865 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 866 *snmp_syserr_p ? *snmp_syserr_p : ret, 867 OID_sunPlatSensorClass, row); 868 free(phys_name); 869 return (0); 870 } 871 872 ret = snmp_get_int(hdl, OID_sunPlatSensorType, 873 row, &sensor_type, snmp_syserr_p); 874 CHECK_LINKRESET(snmp_syserr_p, 0) 875 if (ret < 0) { 876 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 877 *snmp_syserr_p ? *snmp_syserr_p : ret, 878 OID_sunPlatSensorType, row); 879 free(phys_name); 880 return (0); 881 } 882 883 if (sensor_class == SSSC_NUMERIC) { 884 if (sensor_type == SSST_TEMPERATURE) { 885 ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR) 886 add_prop(nodeh, &proph, node_name, row, 887 PP_TEMPERATURE, snmp_syserr_p); 888 } else if (sensor_type == SSST_VOLTAGE) { 889 ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR) 890 add_prop(nodeh, &proph, node_name, row, 891 PP_VOLTAGE, snmp_syserr_p); 892 } else if (sensor_type == SSST_CURRENT) { 893 ADD_NODE(PICL_CLASS_CURRENT_SENSOR) 894 add_prop(nodeh, &proph, node_name, row, 895 PP_CURRENT, snmp_syserr_p); 896 } else if (sensor_type == SSST_TACHOMETER) { 897 ADD_NODE(PICL_CLASS_RPM_SENSOR) 898 add_prop(nodeh, &proph, node_name, row, 899 PP_SPEED, snmp_syserr_p); 900 } else { 901 ADD_NODE(PICL_CLASS_SENSOR) 902 add_prop(nodeh, &proph, node_name, row, 903 PP_SENSOR_VALUE, snmp_syserr_p); 904 } 905 CHECK_LINKRESET(snmp_syserr_p, 0) 906 907 add_prop(nodeh, &proph, node_name, row, 908 PP_OPSTATUS, snmp_syserr_p); 909 CHECK_LINKRESET(snmp_syserr_p, 0) 910 911 add_prop(nodeh, &proph, node_name, row, 912 PP_BASE_UNITS, snmp_syserr_p); 913 CHECK_LINKRESET(snmp_syserr_p, 0) 914 915 add_prop(nodeh, &proph, node_name, row, 916 PP_EXPONENT, snmp_syserr_p); 917 CHECK_LINKRESET(snmp_syserr_p, 0) 918 919 add_prop(nodeh, &proph, node_name, row, 920 PP_RATE_UNITS, snmp_syserr_p); 921 CHECK_LINKRESET(snmp_syserr_p, 0) 922 923 add_thresholds(nodeh, row, snmp_syserr_p); 924 CHECK_LINKRESET(snmp_syserr_p, 0) 925 926 } else if (sensor_class == SSSC_BINARY) { 927 if (sensor_type == SSST_TEMPERATURE) { 928 ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR) 929 } else if (sensor_type == SSST_VOLTAGE) { 930 ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR) 931 } else if (sensor_type == SSST_CURRENT) { 932 ADD_NODE(PICL_CLASS_CURRENT_INDICATOR) 933 } else if (sensor_type == SSST_TACHOMETER) { 934 ADD_NODE(PICL_CLASS_RPM_INDICATOR) 935 } else if (sensor_type == SSST_PRESENCE) { 936 ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR) 937 } else { 938 ADD_NODE(PICL_CLASS_INDICATOR) 939 } 940 941 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 942 snmp_syserr_p); 943 CHECK_LINKRESET(snmp_syserr_p, 0) 944 945 add_prop(nodeh, &proph, node_name, row, PP_CONDITION, 946 snmp_syserr_p); 947 CHECK_LINKRESET(snmp_syserr_p, 0) 948 949 add_prop(nodeh, &proph, node_name, row, PP_EXPECTED, 950 snmp_syserr_p); 951 CHECK_LINKRESET(snmp_syserr_p, 0) 952 } else { 953 log_msg(LOG_ERR, 954 SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row); 955 return (0); 956 } 957 break; 958 959 case SPC_MODULE: 960 ADD_NODE(PICL_CLASS_MODULE) 961 962 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 963 snmp_syserr_p); 964 CHECK_LINKRESET(snmp_syserr_p, 0) 965 966 add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE, 967 snmp_syserr_p); 968 CHECK_LINKRESET(snmp_syserr_p, 0) 969 970 add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE, 971 snmp_syserr_p); 972 CHECK_LINKRESET(snmp_syserr_p, 0) 973 break; 974 975 case SPC_PORT: 976 ADD_NODE(PICL_CLASS_PORT) 977 break; 978 979 case SPC_STACK: 980 ADD_NODE(PICL_CLASS_STACK) 981 break; 982 983 default: 984 log_msg(LOG_WARNING, 985 SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row); 986 free(phys_name); 987 return (0); 988 } 989 990 add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p); 991 CHECK_LINKRESET(snmp_syserr_p, 0) 992 993 add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p); 994 CHECK_LINKRESET(snmp_syserr_p, 0) 995 996 add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p); 997 CHECK_LINKRESET(snmp_syserr_p, 0) 998 999 add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p); 1000 CHECK_LINKRESET(snmp_syserr_p, 0) 1001 1002 add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p); 1003 CHECK_LINKRESET(snmp_syserr_p, 0) 1004 1005 add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p); 1006 CHECK_LINKRESET(snmp_syserr_p, 0) 1007 1008 add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p); 1009 CHECK_LINKRESET(snmp_syserr_p, 0) 1010 1011 add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p); 1012 CHECK_LINKRESET(snmp_syserr_p, 0) 1013 1014 free(phys_name); 1015 save_nodeh(nodeh, row); 1016 1017 return (nodeh); 1018 } 1019 1020 /* 1021 * Saves the node handle and the row id into physplat_nodes[]. If we're 1022 * doing this in response to a hotplug event, we should've freed the 1023 * old physplat_nodes before entering here to save the first node of the 1024 * new physplat subtree. 1025 */ 1026 static void 1027 save_nodeh(picl_nodehdl_t nodeh, int row) 1028 { 1029 size_t sz, count; 1030 picl_nodehdl_t *p; 1031 1032 if (row >= n_physplat_nodes) { 1033 count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) * 1034 N_ELEMS_IN_NODE_BLOCK; 1035 sz = count * sizeof (picl_nodehdl_t); 1036 1037 p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t)); 1038 if (p == NULL) { 1039 log_msg(LOG_ERR, SNMPP_NO_MEM, sz); 1040 return; 1041 } 1042 1043 if (physplat_nodes) { 1044 (void) memcpy((void *) p, (void *) physplat_nodes, 1045 n_physplat_nodes * sizeof (picl_nodehdl_t)); 1046 free((void *) physplat_nodes); 1047 } 1048 1049 physplat_nodes = p; 1050 n_physplat_nodes = count; 1051 } 1052 1053 physplat_nodes[row] = nodeh; 1054 } 1055 1056 static picl_nodehdl_t 1057 lookup_nodeh(int row) 1058 { 1059 if (row >= n_physplat_nodes) 1060 return (0); 1061 1062 return (physplat_nodes[row]); 1063 } 1064 1065 /* 1066 * We enter this routine only when we are building the physical-platform 1067 * subtree, whether for the first time or in response to a hotplug event. 1068 * If we're here for rebuilding the tree, we have already set stale_tree 1069 * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props 1070 * or volprop_ndx. If we're here to build the tree for the first time, 1071 * picld hasn't yet created doors and is running single-threaded, so no 1072 * one else would be accessing them anyway. 1073 */ 1074 static void 1075 save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype) 1076 { 1077 vol_prophdl_t *p; 1078 int count; 1079 1080 if (volprop_ndx == n_vol_props) { 1081 count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK; 1082 p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t)); 1083 if (p == NULL) { 1084 log_msg(LOG_ERR, SNMPP_NO_MEM, 1085 count * sizeof (vol_prophdl_t)); 1086 return; 1087 } 1088 1089 if (vol_props) { 1090 (void) memcpy((void *) p, (void *) vol_props, 1091 n_vol_props * sizeof (vol_prophdl_t)); 1092 free((void *) vol_props); 1093 } 1094 1095 vol_props = p; 1096 n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK; 1097 } 1098 1099 vol_props[volprop_ndx].prop = prop; 1100 vol_props[volprop_ndx].oidstr = oidstr; 1101 vol_props[volprop_ndx].row = row; 1102 vol_props[volprop_ndx].proptype = proptype; 1103 1104 volprop_ndx++; 1105 } 1106 1107 static void 1108 check_for_stale_data(boolean_t nocache) 1109 { 1110 int cur_change_time; 1111 int ret; 1112 int snmp_syserr; 1113 1114 (void) rw_wrlock(&stale_tree_rwlp); 1115 1116 /* 1117 * Check if some other thread beat us to it 1118 */ 1119 if (stale_tree == B_TRUE) { 1120 (void) rw_unlock(&stale_tree_rwlp); 1121 return; 1122 } 1123 1124 /* 1125 * Cache OID_entLastChangeTime for up to 10 seconds before 1126 * fetching it from ILOM again. This prevents us from fetching 1127 * this value from ILOM when the we're filling or refreshing a 1128 * whole bunch of items in the cache around the same time. 1129 */ 1130 if (nocache == B_FALSE && time(NULL) - change_time_check <= 10) { 1131 (void) rw_unlock(&stale_tree_rwlp); 1132 return; 1133 } 1134 1135 /* 1136 * Check if mib data has changed (hotplug? link-reset?) 1137 */ 1138 do { 1139 snmp_syserr = 0; 1140 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 1141 &cur_change_time, &snmp_syserr); 1142 (void) time(&change_time_check); 1143 if ((ret == 0) && (cur_change_time == change_time)) { 1144 (void) rw_unlock(&stale_tree_rwlp); 1145 return; 1146 } 1147 } while (ret != 0 && snmp_syserr == EINTR); 1148 1149 /* 1150 * If we can't read entLastChangeTime we assume we need to rebuild 1151 * the tree. This will also cover the case when we need to rebuild 1152 * the tree because a link reset had happened. 1153 */ 1154 LOGPRINTF2("check_for_stale_data: LastChange times have changed, " 1155 "(%#x != %#x)\n", change_time, cur_change_time); 1156 1157 /* 1158 * If the mib data has changed, we need to rebuild the physical-platform 1159 * subtree. To do this, we set a flag to mark the tree stale, 1160 * so that any future reads to get value of volatile properties will 1161 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag 1162 * is reset by the tree builder thread. 1163 */ 1164 stale_tree = B_TRUE; 1165 if (vol_props) { 1166 free(vol_props); 1167 } 1168 vol_props = NULL; 1169 volprop_ndx = 0; 1170 n_vol_props = 0; 1171 1172 (void) rw_unlock(&stale_tree_rwlp); 1173 1174 (void) mutex_lock(&rebuild_tree_lock); 1175 rebuild_tree = B_TRUE; 1176 (void) cond_signal(&rebuild_tree_cv); 1177 LOGPRINTF("check_for_stale_data: signalled tree builder\n"); 1178 (void) mutex_unlock(&rebuild_tree_lock); 1179 } 1180 1181 /* 1182 * This is the critical routine. This callback is invoked by picl whenever 1183 * it needs to fetch the value of a volatile property. The first thing we 1184 * must do, however, is to see if there has been a hotplug or a link-reset 1185 * event since the last time we built the tree and whether we need to 1186 * rebuild the tree. If so, we do whatever is necessary to make that happen, 1187 * but return PICL_PROPVALUNAVAILABLE for now, without making any further 1188 * snmp requests or accessing any globals. 1189 */ 1190 static int 1191 read_volprop(ptree_rarg_t *parg, void *buf) 1192 { 1193 char *pstr; 1194 int propval; 1195 int i, ndx; 1196 int ret; 1197 int snmp_syserr = 0; 1198 1199 /* 1200 * First check for any event that would make us throw away 1201 * the existing /physical-platform subtree and rebuild 1202 * another one. If we are rebuilding the subtree, we just 1203 * return the stale value until the tree is fully built. 1204 */ 1205 check_for_stale_data(B_FALSE); 1206 1207 (void) rw_rdlock(&stale_tree_rwlp); 1208 1209 if (stale_tree == B_TRUE) { 1210 (void) rw_unlock(&stale_tree_rwlp); 1211 return (PICL_PROPVALUNAVAILABLE); 1212 } 1213 1214 for (i = 0; i < volprop_ndx; i++) { 1215 if (vol_props[i].prop == parg->proph) { 1216 ndx = i; 1217 break; 1218 } 1219 } 1220 if (i == volprop_ndx) { 1221 (void) rw_unlock(&stale_tree_rwlp); 1222 log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph); 1223 return (PICL_FAILURE); 1224 } 1225 1226 /* 1227 * If we can't read the value, return failure. Even if this was 1228 * due to a link reset, between the check for stale data and now, 1229 * the next volatile callback by picl will initiate a tree-rebuild. 1230 */ 1231 ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row, 1232 &propval, &snmp_syserr); 1233 if (ret < 0) { 1234 (void) rw_unlock(&stale_tree_rwlp); 1235 check_for_stale_data(B_TRUE); 1236 if (stale_tree == B_TRUE) { 1237 return (PICL_PROPVALUNAVAILABLE); 1238 } 1239 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1240 snmp_syserr ? snmp_syserr : ret, 1241 vol_props[ndx].oidstr, vol_props[ndx].row); 1242 return (PICL_FAILURE); 1243 } 1244 1245 switch (vol_props[ndx].proptype) { 1246 case VPT_PLATOPSTATE: 1247 if (propval == SSOS_DISABLED) { 1248 (void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN); 1249 } else if (propval == SSOS_ENABLED) { 1250 (void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN); 1251 } else { 1252 (void) rw_unlock(&stale_tree_rwlp); 1253 log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE, 1254 propval, vol_props[ndx].row); 1255 return (PICL_FAILURE); 1256 } 1257 break; 1258 1259 case VPT_NUMSENSOR: 1260 (void) memcpy(buf, &propval, sizeof (propval)); 1261 break; 1262 1263 case VPT_BINSENSOR: 1264 if (propval == ST_TRUE) { 1265 ret = snmp_get_str(hdl, 1266 OID_sunPlatBinarySensorInterpretTrue, 1267 vol_props[ndx].row, &pstr, &snmp_syserr); 1268 if (snmp_syserr == ECANCELED) { 1269 (void) rw_unlock(&stale_tree_rwlp); 1270 if (pstr) 1271 free(pstr); 1272 return (PICL_FAILURE); 1273 } 1274 if (ret < 0 || pstr == NULL) { 1275 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1276 snmp_syserr ? snmp_syserr : ret, 1277 OID_sunPlatBinarySensorInterpretTrue, 1278 vol_props[ndx].row); 1279 (void) strlcpy(buf, STR_ST_TRUE, 1280 MAX_TRUTHVAL_LEN); 1281 } else { 1282 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1283 } 1284 if (pstr) 1285 free(pstr); 1286 } else if (propval == ST_FALSE) { 1287 ret = snmp_get_str(hdl, 1288 OID_sunPlatBinarySensorInterpretFalse, 1289 vol_props[ndx].row, &pstr, &snmp_syserr); 1290 if (snmp_syserr == ECANCELED) { 1291 (void) rw_unlock(&stale_tree_rwlp); 1292 if (pstr) 1293 free(pstr); 1294 return (PICL_FAILURE); 1295 } 1296 if (ret < 0 || pstr == NULL) { 1297 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1298 snmp_syserr ? snmp_syserr : ret, 1299 OID_sunPlatBinarySensorInterpretFalse, 1300 vol_props[ndx].row); 1301 (void) strlcpy(buf, STR_ST_FALSE, 1302 MAX_TRUTHVAL_LEN); 1303 } else { 1304 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1305 } 1306 if (pstr) 1307 free(pstr); 1308 } else { 1309 (void) rw_unlock(&stale_tree_rwlp); 1310 log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT, 1311 propval, vol_props[ndx].row); 1312 return (PICL_FAILURE); 1313 } 1314 break; 1315 1316 case VPT_ALARMSTATE: 1317 if (propval == SSAS_OFF) { 1318 (void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN); 1319 } else if (propval == SSAS_STEADY) { 1320 (void) strlcpy(buf, STR_SSAS_STEADY, 1321 MAX_ALARMSTATE_LEN); 1322 } else if (propval == SSAS_ALTERNATING) { 1323 (void) strlcpy(buf, STR_SSAS_ALTERNATING, 1324 MAX_ALARMSTATE_LEN); 1325 } else { 1326 (void) strlcpy(buf, STR_SSAS_UNKNOWN, 1327 MAX_ALARMSTATE_LEN); 1328 } 1329 break; 1330 1331 case VPT_BATTERYSTATUS: 1332 switch (propval) { 1333 case SSBS_OTHER: 1334 (void) strlcpy(buf, STR_SSBS_OTHER, 1335 MAX_BATTERYSTATUS_LEN); 1336 break; 1337 case SSBS_FULLYCHARGED: 1338 (void) strlcpy(buf, STR_SSBS_FULLYCHARGED, 1339 MAX_BATTERYSTATUS_LEN); 1340 break; 1341 case SSBS_LOW: 1342 (void) strlcpy(buf, STR_SSBS_LOW, 1343 MAX_BATTERYSTATUS_LEN); 1344 break; 1345 case SSBS_CRITICAL: 1346 (void) strlcpy(buf, STR_SSBS_CRITICAL, 1347 MAX_BATTERYSTATUS_LEN); 1348 break; 1349 case SSBS_CHARGING: 1350 (void) strlcpy(buf, STR_SSBS_CHARGING, 1351 MAX_BATTERYSTATUS_LEN); 1352 break; 1353 case SSBS_CHARGING_AND_LOW: 1354 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW, 1355 MAX_BATTERYSTATUS_LEN); 1356 break; 1357 case SSBS_CHARGING_AND_HIGH: 1358 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH, 1359 MAX_BATTERYSTATUS_LEN); 1360 break; 1361 case SSBS_CHARGING_AND_CRITICAL: 1362 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL, 1363 MAX_BATTERYSTATUS_LEN); 1364 break; 1365 case SSBS_UNDEFINED: 1366 (void) strlcpy(buf, STR_SSBS_UNDEFINED, 1367 MAX_BATTERYSTATUS_LEN); 1368 break; 1369 case SSBS_PARTIALLY_CHARGED: 1370 (void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED, 1371 MAX_BATTERYSTATUS_LEN); 1372 break; 1373 case SSBS_UNKNOWN: 1374 default: 1375 (void) strlcpy(buf, STR_SSBS_UNKNOWN, 1376 MAX_BATTERYSTATUS_LEN); 1377 break; 1378 } 1379 break; 1380 } 1381 1382 (void) rw_unlock(&stale_tree_rwlp); 1383 1384 return (PICL_SUCCESS); 1385 } 1386 1387 static void 1388 threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname, 1389 int *snmp_syserr_p) 1390 { 1391 picl_prophdl_t prop; 1392 int err; 1393 int val; 1394 1395 if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) { 1396 err = add_volatile_prop(node, propname, PICL_PTYPE_INT, 1397 PICL_READ, sizeof (int), read_volprop, NULL, &prop); 1398 if (err == PICL_SUCCESS) 1399 save_volprop(prop, oidstr, row, VPT_NUMSENSOR); 1400 } else 1401 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1402 *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row); 1403 } 1404 1405 static void 1406 add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p) 1407 { 1408 uchar_t *bitstr = NULL; 1409 uchar_t enabled; 1410 uint_t nbytes; 1411 int ret; 1412 1413 ret = snmp_get_str(hdl, 1414 OID_sunPlatNumericSensorEnabledThresholds, 1415 row, (char **)&bitstr, snmp_syserr_p); 1416 if (ret == -1) { 1417 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1418 *snmp_syserr_p ? *snmp_syserr_p : ret, 1419 OID_sunPlatNumericSensorEnabledThresholds, row); 1420 } else { 1421 nbytes = strlen((const char *)bitstr); 1422 } 1423 1424 CHECK_LINKRESET_VOID(snmp_syserr_p); 1425 1426 /* 1427 * No bit string of threshold masks was returned, so we can't 1428 * assume that any thresholds exist. 1429 * 1430 * This mask prevents us from attempting to fetch thresholds 1431 * which don't apply to the sensor or that aren't there anyway, 1432 * That speeds up the plug-in significantly since otherwise it 1433 * takes several seconds to time out. 1434 */ 1435 if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) { 1436 if (bitstr) 1437 free(bitstr); 1438 return; 1439 } else if (nbytes == 1) { 1440 /* 1441 * The ALOM snmp agent doesn't adhere to the BER rules for 1442 * encoding bit strings. While the BER states that bitstrings 1443 * must begin from the second octet after length, and the 1444 * first octet after length must indicate the number of unused 1445 * bits in the last octet, the snmp agent simply sends the 1446 * bitstring data as if it were octet string -- that is, the 1447 * "unused bits" octet is missing. 1448 */ 1449 enabled = bitstr[0]; 1450 } else if (nbytes == 2) 1451 enabled = bitstr[1]; 1452 1453 if (bitstr) { 1454 free(bitstr); 1455 } 1456 1457 if (enabled & LOWER_FATAL) { 1458 threshold(node, 1459 OID_sunPlatNumericSensorLowerThresholdFatal, row, 1460 PICL_PROP_LOW_POWER_OFF, snmp_syserr_p); 1461 CHECK_LINKRESET_VOID(snmp_syserr_p) 1462 } 1463 if (enabled & LOWER_CRITICAL) { 1464 threshold(node, 1465 OID_sunPlatNumericSensorLowerThresholdCritical, row, 1466 PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p); 1467 CHECK_LINKRESET_VOID(snmp_syserr_p) 1468 } 1469 if (enabled & LOWER_NON_CRITICAL) { 1470 threshold(node, 1471 OID_sunPlatNumericSensorLowerThresholdNonCritical, row, 1472 PICL_PROP_LOW_WARNING, snmp_syserr_p); 1473 CHECK_LINKRESET_VOID(snmp_syserr_p) 1474 } 1475 if (enabled & UPPER_NON_CRITICAL) { 1476 threshold(node, 1477 OID_sunPlatNumericSensorUpperThresholdNonCritical, row, 1478 PICL_PROP_HIGH_WARNING, snmp_syserr_p); 1479 CHECK_LINKRESET_VOID(snmp_syserr_p) 1480 } 1481 if (enabled & UPPER_CRITICAL) { 1482 threshold(node, 1483 OID_sunPlatNumericSensorUpperThresholdCritical, row, 1484 PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p); 1485 CHECK_LINKRESET_VOID(snmp_syserr_p) 1486 } 1487 if (enabled & UPPER_FATAL) { 1488 threshold(node, 1489 OID_sunPlatNumericSensorUpperThresholdFatal, row, 1490 PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p); 1491 CHECK_LINKRESET_VOID(snmp_syserr_p) 1492 } 1493 } 1494 1495 static char * 1496 get_slot_type(int row, int *snmp_syserr_p) 1497 { 1498 char *p; 1499 char *slott = NULL; 1500 int ret; 1501 1502 ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes, 1503 row, &p, snmp_syserr_p); 1504 CHECK_LINKRESET(snmp_syserr_p, NULL) 1505 1506 if ((ret == 0) && p && *p) { 1507 slott = p; 1508 if ((p = strchr(slott, '\n')) != NULL) 1509 *p = 0; 1510 } else { 1511 log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row); 1512 if (p) { 1513 free(p); 1514 } 1515 } 1516 1517 return (slott); 1518 } 1519 1520 /* 1521 * Create and add the specified volatile property 1522 */ 1523 static int 1524 add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access, 1525 int size, int (*rdfunc)(ptree_rarg_t *, void *), 1526 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp) 1527 { 1528 ptree_propinfo_t propinfo; 1529 picl_prophdl_t prop; 1530 int err; 1531 1532 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1533 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc); 1534 if (err != PICL_SUCCESS) { 1535 log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err); 1536 return (err); 1537 } 1538 1539 err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop); 1540 if (err != PICL_SUCCESS) { 1541 log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node); 1542 return (err); 1543 } 1544 1545 if (propp) 1546 *propp = prop; 1547 1548 return (PICL_SUCCESS); 1549 } 1550 1551 /* 1552 * Add the specified string property to the node 1553 */ 1554 static int 1555 add_string_prop(picl_nodehdl_t node, char *propname, char *propval) 1556 { 1557 ptree_propinfo_t propinfo; 1558 int err; 1559 1560 if (*propval == '\0') 1561 return (PICL_SUCCESS); 1562 1563 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1564 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1, 1565 propname, NULL, NULL); 1566 if (err != PICL_SUCCESS) { 1567 log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err); 1568 return (err); 1569 } 1570 1571 err = ptree_create_and_add_prop(node, &propinfo, propval, NULL); 1572 if (err != PICL_SUCCESS) { 1573 log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node); 1574 return (err); 1575 } 1576 1577 return (PICL_SUCCESS); 1578 } 1579 1580 /* 1581 * Add the specified void property to the node 1582 */ 1583 static int 1584 add_void_prop(picl_nodehdl_t node, char *propname) 1585 { 1586 ptree_propinfo_t propinfo; 1587 int err; 1588 1589 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1590 PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL); 1591 if (err != PICL_SUCCESS) { 1592 log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err); 1593 return (err); 1594 } 1595 1596 err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL); 1597 if (err != PICL_SUCCESS) { 1598 log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node); 1599 return (err); 1600 } 1601 1602 return (PICL_SUCCESS); 1603 } 1604 1605 static void 1606 add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 1607 int row, sp_propid_t pp, int *snmp_syserr_p) 1608 { 1609 char *serial_num; 1610 char *slot_type; 1611 char *fw_revision, *hw_revision; 1612 char *mfg_name, *model_name; 1613 char *phys_descr; 1614 int val; 1615 int ret; 1616 1617 switch (pp) { 1618 case PP_SERIAL_NUM: 1619 ret = snmp_get_str(hdl, OID_entPhysicalSerialNum, 1620 row, &serial_num, snmp_syserr_p); 1621 CHECK_LINKRESET_VOID(snmp_syserr_p) 1622 if ((ret == 0) && serial_num) { 1623 (void) add_string_prop(nodeh, 1624 PICL_PROP_SERIAL_NUMBER, serial_num); 1625 free((void *) serial_num); 1626 } 1627 if (ret == -1) 1628 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1629 *snmp_syserr_p ? *snmp_syserr_p : ret, 1630 OID_entPhysicalSerialNum, row); 1631 break; 1632 1633 case PP_SLOT_TYPE: 1634 if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) { 1635 CHECK_LINKRESET_VOID(snmp_syserr_p) 1636 (void) add_string_prop(nodeh, 1637 PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE); 1638 } else { 1639 (void) add_string_prop(nodeh, 1640 PICL_PROP_SLOT_TYPE, slot_type); 1641 free((void *) slot_type); 1642 } 1643 break; 1644 1645 case PP_STATE: 1646 ret = add_volatile_prop(nodeh, PICL_PROP_STATE, 1647 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN, 1648 read_volprop, NULL, php); 1649 if (ret == PICL_SUCCESS) { 1650 save_volprop(*php, OID_sunPlatAlarmState, row, 1651 VPT_ALARMSTATE); 1652 } 1653 break; 1654 1655 case PP_OPSTATUS: 1656 ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS, 1657 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN, 1658 read_volprop, NULL, php); 1659 if (ret == PICL_SUCCESS) { 1660 save_volprop(*php, 1661 OID_sunPlatEquipmentOperationalState, row, 1662 VPT_PLATOPSTATE); 1663 } 1664 break; 1665 1666 case PP_BATT_STATUS: 1667 ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS, 1668 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN, 1669 read_volprop, NULL, php); 1670 if (ret == PICL_SUCCESS) { 1671 save_volprop(*php, OID_sunPlatBatteryStatus, row, 1672 VPT_BATTERYSTATUS); 1673 } 1674 break; 1675 1676 case PP_TEMPERATURE: 1677 ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE, 1678 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1679 NULL, php); 1680 if (ret == PICL_SUCCESS) { 1681 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1682 row, VPT_NUMSENSOR); 1683 } 1684 break; 1685 1686 case PP_VOLTAGE: 1687 ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE, 1688 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1689 NULL, php); 1690 if (ret == PICL_SUCCESS) { 1691 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1692 row, VPT_NUMSENSOR); 1693 } 1694 break; 1695 1696 case PP_CURRENT: 1697 ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT, 1698 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1699 NULL, php); 1700 if (ret == PICL_SUCCESS) { 1701 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1702 row, VPT_NUMSENSOR); 1703 } 1704 break; 1705 1706 case PP_SPEED: 1707 ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT, 1708 PICL_READ, sizeof (int), read_volprop, NULL, php); 1709 if (ret == PICL_SUCCESS) { 1710 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1711 row, VPT_NUMSENSOR); 1712 } 1713 break; 1714 1715 case PP_SENSOR_VALUE: 1716 ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE, 1717 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1718 NULL, php); 1719 if (ret == PICL_SUCCESS) { 1720 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1721 row, VPT_NUMSENSOR); 1722 } 1723 break; 1724 1725 case PP_CONDITION: 1726 ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION, 1727 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1728 read_volprop, NULL, php); 1729 if (ret == PICL_SUCCESS) { 1730 save_volprop(*php, OID_sunPlatBinarySensorCurrent, 1731 row, VPT_BINSENSOR); 1732 } 1733 break; 1734 1735 case PP_EXPECTED: 1736 ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED, 1737 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1738 read_volprop, NULL, php); 1739 if (ret == PICL_SUCCESS) { 1740 save_volprop(*php, OID_sunPlatBinarySensorExpected, 1741 row, VPT_BINSENSOR); 1742 } 1743 break; 1744 1745 case PP_EXPONENT: 1746 ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT, 1747 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1748 NULL, php); 1749 if (ret == PICL_SUCCESS) { 1750 save_volprop(*php, OID_sunPlatNumericSensorExponent, 1751 row, VPT_NUMSENSOR); 1752 } 1753 break; 1754 1755 case PP_REPLACEABLE: 1756 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable, 1757 row, &val, snmp_syserr_p); 1758 CHECK_LINKRESET_VOID(snmp_syserr_p) 1759 if ((ret == 0) && (val == ST_TRUE)) 1760 (void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE); 1761 if (ret == -1) 1762 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1763 *snmp_syserr_p ? *snmp_syserr_p : ret, 1764 OID_sunPlatCircuitPackReplaceable, row); 1765 break; 1766 1767 case PP_HOTSWAPPABLE: 1768 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable, 1769 row, &val, snmp_syserr_p); 1770 CHECK_LINKRESET_VOID(snmp_syserr_p) 1771 if ((ret == 0) && (val == ST_TRUE)) 1772 (void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE); 1773 if (ret == -1) 1774 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1775 *snmp_syserr_p ? *snmp_syserr_p : ret, 1776 OID_sunPlatCircuitPackHotSwappable, row); 1777 break; 1778 1779 case PP_IS_FRU: 1780 ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row, 1781 &val, snmp_syserr_p); 1782 CHECK_LINKRESET_VOID(snmp_syserr_p) 1783 if ((ret == 0) && (val == ST_TRUE)) 1784 (void) add_void_prop(nodeh, PICL_PROP_IS_FRU); 1785 if (ret == -1) 1786 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1787 *snmp_syserr_p ? *snmp_syserr_p : ret, 1788 OID_entPhysicalIsFRU, row); 1789 break; 1790 1791 case PP_HW_REVISION: 1792 ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev, 1793 row, &hw_revision, snmp_syserr_p); 1794 CHECK_LINKRESET_VOID(snmp_syserr_p) 1795 if ((ret == 0) && hw_revision) { 1796 (void) add_string_prop(nodeh, 1797 PICL_PROP_HW_REVISION, hw_revision); 1798 free((void *) hw_revision); 1799 } 1800 if (ret == -1) 1801 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1802 *snmp_syserr_p ? *snmp_syserr_p : ret, 1803 OID_entPhysicalHardwareRev, row); 1804 break; 1805 1806 case PP_FW_REVISION: 1807 ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev, 1808 row, &fw_revision, snmp_syserr_p); 1809 CHECK_LINKRESET_VOID(snmp_syserr_p) 1810 if ((ret == 0) && fw_revision) { 1811 (void) add_string_prop(nodeh, 1812 PICL_PROP_FW_REVISION, fw_revision); 1813 free((void *) fw_revision); 1814 } 1815 if (ret == -1) 1816 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1817 *snmp_syserr_p ? *snmp_syserr_p : ret, 1818 OID_entPhysicalFirmwareRev, row); 1819 break; 1820 1821 case PP_MFG_NAME: 1822 ret = snmp_get_str(hdl, OID_entPhysicalMfgName, 1823 row, &mfg_name, snmp_syserr_p); 1824 CHECK_LINKRESET_VOID(snmp_syserr_p) 1825 if ((ret == 0) && mfg_name) { 1826 (void) add_string_prop(nodeh, 1827 PICL_PROP_MFG_NAME, mfg_name); 1828 free((void *) mfg_name); 1829 } 1830 if (ret == -1) 1831 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1832 *snmp_syserr_p ? *snmp_syserr_p : ret, 1833 OID_entPhysicalMfgName, row); 1834 break; 1835 1836 case PP_MODEL_NAME: 1837 ret = snmp_get_str(hdl, OID_entPhysicalModelName, 1838 row, &model_name, snmp_syserr_p); 1839 CHECK_LINKRESET_VOID(snmp_syserr_p) 1840 if ((ret == 0) && model_name) { 1841 (void) add_string_prop(nodeh, 1842 PICL_PROP_MODEL_NAME, model_name); 1843 free((void *) model_name); 1844 } 1845 if (ret == -1) 1846 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1847 *snmp_syserr_p ? *snmp_syserr_p : ret, 1848 OID_entPhysicalModelName, row); 1849 break; 1850 1851 case PP_DESCRIPTION: 1852 ret = snmp_get_str(hdl, OID_entPhysicalDescr, 1853 row, &phys_descr, snmp_syserr_p); 1854 CHECK_LINKRESET_VOID(snmp_syserr_p) 1855 if ((ret == 0) && phys_descr) { 1856 (void) add_string_prop(nodeh, 1857 PICL_PROP_PHYS_DESCRIPTION, phys_descr); 1858 free((void *) phys_descr); 1859 } 1860 if (ret == -1) 1861 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1862 *snmp_syserr_p ? *snmp_syserr_p : ret, 1863 OID_entPhysicalDescr, row); 1864 break; 1865 1866 case PP_LABEL: 1867 if (label && *label) 1868 (void) add_string_prop(nodeh, PICL_PROP_LABEL, label); 1869 break; 1870 1871 case PP_BASE_UNITS: 1872 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits, 1873 row, &val, snmp_syserr_p); 1874 CHECK_LINKRESET_VOID(snmp_syserr_p) 1875 if ((ret == 0) && (val > 0) && (val < n_baseunits)) { 1876 (void) add_string_prop(nodeh, 1877 PICL_PROP_BASE_UNITS, sensor_baseunits[val]); 1878 } 1879 if (ret == -1) 1880 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1881 *snmp_syserr_p ? *snmp_syserr_p : ret, 1882 OID_sunPlatNumericSensorBaseUnits, row); 1883 break; 1884 1885 case PP_RATE_UNITS: 1886 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits, 1887 row, &val, snmp_syserr_p); 1888 CHECK_LINKRESET_VOID(snmp_syserr_p) 1889 if ((ret == 0) && (val > 0) && (val < n_rateunits)) { 1890 (void) add_string_prop(nodeh, 1891 PICL_PROP_RATE_UNITS, sensor_rateunits[val]); 1892 } 1893 if (ret == -1) 1894 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1895 *snmp_syserr_p ? *snmp_syserr_p : ret, 1896 OID_sunPlatNumericSensorRateUnits, row); 1897 break; 1898 } 1899 } 1900 1901 /* 1902 * Initialize the SNMP library's cache refresh subsystem, then periodically 1903 * process refresh job to prevent cache entries from expiring. 1904 */ 1905 /*ARGSUSED*/ 1906 static void * 1907 cache_refresher(void *arg) 1908 { 1909 int jobs; 1910 int next_expiration; 1911 timestruc_t to; 1912 hrtime_t cycle_start, cycle_elapsed; 1913 1914 /* 1915 * Initialize refresh subsystem 1916 */ 1917 LOGPRINTF("Initializing SNMP refresh subsystem.\n"); 1918 if (snmp_refresh_init() < 0) { 1919 return ((void *)-1); 1920 } 1921 1922 (void) mutex_lock(&cache_refresh_lock); 1923 1924 1925 for (;;) { 1926 cycle_start = gethrtime(); 1927 1928 /* 1929 * Process jobs from the snmp cache refresh work queue until one 1930 * of the following conditions is true: 1931 * 1) we are told to exit, or 1932 * 2) we have processed at least as many jobs as recommended by 1933 * the library, and the next job expiration is at least 1934 * CACHE_REFRESH_MIN_WINDOW * seconds away. 1935 */ 1936 jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE); 1937 while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) { 1938 (void) snmp_refresh_process_job(); 1939 jobs--; 1940 } 1941 1942 next_expiration = snmp_refresh_get_next_expiration(); 1943 while ((cache_refresh_thr_exit == B_FALSE) && 1944 ((next_expiration >= 0) && 1945 (next_expiration < CACHE_REFRESH_MIN_WINDOW))) { 1946 (void) snmp_refresh_process_job(); 1947 next_expiration = snmp_refresh_get_next_expiration(); 1948 } 1949 1950 /* 1951 * As long as we haven't been told to exit, sleep for 1952 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has 1953 * elapsed since this cycle started. If the elapsed time is 1954 * equal to or greater than 60 seconds, skip sleeping entirely. 1955 */ 1956 cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC; 1957 if ((cache_refresh_thr_exit == B_FALSE) && 1958 (cycle_elapsed < CACHE_REFRESH_CYCLE)) { 1959 to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed; 1960 to.tv_nsec = 0; 1961 (void) cond_reltimedwait(&cache_refresh_cv, 1962 &cache_refresh_lock, &to); 1963 } 1964 1965 /* 1966 * If we have been told to exit, clean up and bail out. 1967 */ 1968 if (cache_refresh_thr_exit == B_TRUE) { 1969 snmp_refresh_fini(); 1970 (void) mutex_unlock(&cache_refresh_lock); 1971 LOGPRINTF("cache_refresher: time to exit\n"); 1972 return (NULL); 1973 } 1974 1975 } 1976 1977 /*NOTREACHED*/ 1978 return (NULL); 1979 } 1980 1981 /* 1982 * Check to see if the cache_refresher thread is running. If it is, signal it 1983 * to terminate and clean up associated data structures. 1984 */ 1985 void 1986 cache_refresher_fini(void) 1987 { 1988 /* if the thread isn't running, there is nothing to do */ 1989 if (cache_refresh_thr_exit == B_TRUE) 1990 return; 1991 1992 /* wake up the cache_refresher thread, tell it to exit */ 1993 (void) mutex_lock(&cache_refresh_lock); 1994 cache_refresh_thr_exit = B_TRUE; 1995 (void) cond_signal(&cache_refresh_cv); 1996 (void) mutex_unlock(&cache_refresh_lock); 1997 1998 /* reap the thread */ 1999 (void) thr_join(cache_refresh_thr_id, NULL, NULL); 2000 2001 /* finish cleanup... */ 2002 (void) cond_destroy(&cache_refresh_cv); 2003 (void) mutex_destroy(&cache_refresh_lock); 2004 } 2005 2006 /*VARARGS2*/ 2007 static void 2008 log_msg(int pri, const char *fmt, ...) 2009 { 2010 va_list ap; 2011 2012 va_start(ap, fmt); 2013 vsyslog(pri, fmt, ap); 2014 va_end(ap); 2015 } 2016 2017 #ifdef SNMPPLUGIN_DEBUG 2018 2019 static void 2020 snmpplugin_log_init(void) 2021 { 2022 (void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL); 2023 } 2024 2025 static void 2026 snmpplugin_log(const char *fmt, ...) 2027 { 2028 va_list ap; 2029 2030 (void) mutex_lock(&snmpplugin_dbuf_lock); 2031 2032 va_start(ap, fmt); 2033 (void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap); 2034 snmpplugin_log_append(); 2035 va_end(ap); 2036 2037 (void) mutex_unlock(&snmpplugin_dbuf_lock); 2038 } 2039 2040 static void 2041 snmpplugin_log_append(void) 2042 { 2043 int len; 2044 2045 len = strlen(snmpplugin_lbuf); 2046 2047 if ((snmpplugin_dbuf_curp + len) >= 2048 (snmpplugin_dbuf + snmpplugin_dbuf_sz)) { 2049 snmpplugin_dbuf_realloc(); 2050 if (snmpplugin_dbuf == NULL) { 2051 return; 2052 } 2053 } 2054 2055 (void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf); 2056 snmpplugin_dbuf_curp += len; 2057 } 2058 2059 static void 2060 snmpplugin_dbuf_realloc(void) 2061 { 2062 char *p; 2063 size_t offset = 0; 2064 size_t count; 2065 2066 count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ; 2067 if ((p = (char *)calloc(count, 1)) == NULL) { 2068 snmpplugin_dbuf_overflow++; 2069 snmpplugin_dbuf_curp = snmpplugin_dbuf; 2070 return; 2071 } 2072 2073 if (snmpplugin_dbuf) { 2074 offset = snmpplugin_dbuf_curp - snmpplugin_dbuf; 2075 (void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz); 2076 free(snmpplugin_dbuf); 2077 } 2078 2079 snmpplugin_dbuf = p; 2080 snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ; 2081 2082 snmpplugin_dbuf_curp = snmpplugin_dbuf + offset; 2083 } 2084 #endif 2085