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