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