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 n_vol_props = 0; 656 volprop_ndx = 0; 657 } 658 } 659 660 static picl_nodehdl_t 661 make_node(picl_nodehdl_t subtree_root, int row, int *snmp_syserr_p) 662 { 663 picl_nodehdl_t nodeh, parenth; 664 picl_prophdl_t proph; 665 char *phys_name, *node_name; 666 int parent_row; 667 int ent_physclass, sunplat_physclass; 668 int sensor_class, sensor_type; 669 int alarm_type; 670 int ps_class; 671 int ret; 672 673 /* 674 * If we've already created this picl node, just return it 675 */ 676 if ((nodeh = lookup_nodeh(row)) != NULL) 677 return (nodeh); 678 679 /* 680 * If we are creating it only now, make sure we have the parent 681 * created first; if there's no parent, then parent it to the 682 * subtree's root node 683 */ 684 ret = snmp_get_int(hdl, OID_entPhysicalContainedIn, row, 685 &parent_row, snmp_syserr_p); 686 CHECK_LINKRESET(snmp_syserr_p, NULL) 687 if (ret < 0 || parent_row <= 0) 688 parenth = subtree_root; 689 else { 690 parenth = make_node(subtree_root, parent_row, snmp_syserr_p); 691 CHECK_LINKRESET(snmp_syserr_p, NULL) 692 if (parenth == NULL) 693 parenth = subtree_root; 694 } 695 696 /* 697 * Figure out the physical-platform node name from entPhysicalName; 698 * all rows in the MIB that have a valid entPhysicalIndex should 699 * have a physical name. 700 */ 701 ret = snmp_get_str(hdl, OID_entPhysicalName, row, 702 &phys_name, snmp_syserr_p); 703 CHECK_LINKRESET(snmp_syserr_p, NULL) 704 if (ret < 0 || phys_name == NULL) { 705 log_msg(LOG_WARNING, SNMPP_NO_ENTPHYSNAME, row); 706 return (NULL); 707 } 708 709 node_name = basename(phys_name); 710 711 ret = snmp_get_int(hdl, OID_entPhysicalClass, row, 712 &ent_physclass, snmp_syserr_p); 713 CHECK_LINKRESET(snmp_syserr_p, NULL) 714 if (ret < 0) { 715 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 716 *snmp_syserr_p ? *snmp_syserr_p : ret, 717 OID_entPhysicalClass, row); 718 free(phys_name); 719 return (NULL); 720 } 721 722 switch (ent_physclass) { 723 case SPC_OTHER: 724 ret = snmp_get_int(hdl, OID_sunPlatPhysicalClass, row, 725 &sunplat_physclass, snmp_syserr_p); 726 CHECK_LINKRESET(snmp_syserr_p, NULL) 727 if (ret < 0) { 728 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 729 *snmp_syserr_p ? *snmp_syserr_p : ret, 730 OID_sunPlatPhysicalClass, row); 731 free(phys_name); 732 return (NULL); 733 } 734 735 if (sunplat_physclass == SSPC_ALARM) { 736 ret = snmp_get_int(hdl, OID_sunPlatAlarmType, 737 row, &alarm_type, snmp_syserr_p); 738 CHECK_LINKRESET(snmp_syserr_p, NULL) 739 if (ret < 0) { 740 log_msg(LOG_WARNING, 741 SNMPP_CANT_FETCH_OBJECT_VAL, 742 *snmp_syserr_p ? *snmp_syserr_p : ret, 743 OID_sunPlatAlarmType, row); 744 free(phys_name); 745 return (NULL); 746 } 747 748 if (alarm_type == SSAT_VISIBLE) { 749 ADD_NODE(PICL_CLASS_LED) 750 } else { 751 ADD_NODE(PICL_CLASS_ALARM) 752 } 753 754 add_prop(nodeh, &proph, node_name, row, PP_STATE, 755 snmp_syserr_p); 756 CHECK_LINKRESET(snmp_syserr_p, NULL) 757 } else { 758 ADD_NODE(PICL_CLASS_OTHER) 759 } 760 761 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 762 snmp_syserr_p); 763 CHECK_LINKRESET(snmp_syserr_p, NULL) 764 break; 765 766 case SPC_UNKNOWN: 767 ADD_NODE(PICL_CLASS_UNKNOWN) 768 break; 769 770 case SPC_CHASSIS: 771 ADD_NODE(PICL_CLASS_CHASSIS) 772 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 773 snmp_syserr_p); 774 CHECK_LINKRESET(snmp_syserr_p, NULL) 775 break; 776 777 case SPC_BACKPLANE: 778 ADD_NODE(PICL_CLASS_BACKPLANE) 779 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 780 snmp_syserr_p); 781 CHECK_LINKRESET(snmp_syserr_p, NULL) 782 break; 783 784 case SPC_CONTAINER: 785 ADD_NODE(PICL_CLASS_CONTAINER) 786 787 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 788 snmp_syserr_p); 789 CHECK_LINKRESET(snmp_syserr_p, NULL) 790 791 add_prop(nodeh, &proph, node_name, row, PP_SLOT_TYPE, 792 snmp_syserr_p); 793 CHECK_LINKRESET(snmp_syserr_p, NULL) 794 break; 795 796 case SPC_POWERSUPPLY: 797 ret = snmp_get_int(hdl, OID_sunPlatPowerSupplyClass, 798 row, &ps_class, snmp_syserr_p); 799 CHECK_LINKRESET(snmp_syserr_p, NULL) 800 if (ret < 0) { 801 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 802 *snmp_syserr_p ? *snmp_syserr_p : ret, 803 OID_sunPlatPowerSupplyClass, row); 804 free(phys_name); 805 return (NULL); 806 } 807 808 if (ps_class == SSPSC_BATTERY) { 809 ADD_NODE(PICL_CLASS_BATTERY) 810 add_prop(nodeh, &proph, node_name, row, 811 PP_BATT_STATUS, snmp_syserr_p); 812 CHECK_LINKRESET(snmp_syserr_p, NULL) 813 } else { 814 ADD_NODE(PICL_CLASS_POWERSUPPLY) 815 } 816 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 817 snmp_syserr_p); 818 CHECK_LINKRESET(snmp_syserr_p, NULL) 819 break; 820 821 case SPC_FAN: 822 ADD_NODE(PICL_CLASS_FAN) 823 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 824 snmp_syserr_p); 825 CHECK_LINKRESET(snmp_syserr_p, NULL) 826 break; 827 828 case SPC_SENSOR: 829 ret = snmp_get_int(hdl, OID_sunPlatSensorClass, 830 row, &sensor_class, snmp_syserr_p); 831 CHECK_LINKRESET(snmp_syserr_p, NULL) 832 if (ret < 0) { 833 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 834 *snmp_syserr_p ? *snmp_syserr_p : ret, 835 OID_sunPlatSensorClass, row); 836 free(phys_name); 837 return (NULL); 838 } 839 840 ret = snmp_get_int(hdl, OID_sunPlatSensorType, 841 row, &sensor_type, snmp_syserr_p); 842 CHECK_LINKRESET(snmp_syserr_p, NULL) 843 if (ret < 0) { 844 log_msg(LOG_WARNING, SNMPP_CANT_FETCH_OBJECT_VAL, 845 *snmp_syserr_p ? *snmp_syserr_p : ret, 846 OID_sunPlatSensorType, row); 847 free(phys_name); 848 return (NULL); 849 } 850 851 if (sensor_class == SSSC_NUMERIC) { 852 if (sensor_type == SSST_TEMPERATURE) { 853 ADD_NODE(PICL_CLASS_TEMPERATURE_SENSOR) 854 add_prop(nodeh, &proph, node_name, row, 855 PP_TEMPERATURE, snmp_syserr_p); 856 } else if (sensor_type == SSST_VOLTAGE) { 857 ADD_NODE(PICL_CLASS_VOLTAGE_SENSOR) 858 add_prop(nodeh, &proph, node_name, row, 859 PP_VOLTAGE, snmp_syserr_p); 860 } else if (sensor_type == SSST_CURRENT) { 861 ADD_NODE(PICL_CLASS_CURRENT_SENSOR) 862 add_prop(nodeh, &proph, node_name, row, 863 PP_CURRENT, snmp_syserr_p); 864 } else if (sensor_type == SSST_TACHOMETER) { 865 ADD_NODE(PICL_CLASS_RPM_SENSOR) 866 add_prop(nodeh, &proph, node_name, row, 867 PP_SPEED, snmp_syserr_p); 868 } else if (sensor_type == SSST_HUMIDITY) { 869 ADD_NODE(PICL_CLASS_HUMIDITY_SENSOR) 870 add_prop(nodeh, &proph, node_name, row, 871 PP_HUMIDITY, snmp_syserr_p); 872 } else { 873 ADD_NODE(PICL_CLASS_SENSOR) 874 add_prop(nodeh, &proph, node_name, row, 875 PP_SENSOR_VALUE, snmp_syserr_p); 876 } 877 CHECK_LINKRESET(snmp_syserr_p, NULL) 878 879 add_prop(nodeh, &proph, node_name, row, 880 PP_OPSTATUS, snmp_syserr_p); 881 CHECK_LINKRESET(snmp_syserr_p, NULL) 882 883 add_prop(nodeh, &proph, node_name, row, 884 PP_BASE_UNITS, snmp_syserr_p); 885 CHECK_LINKRESET(snmp_syserr_p, NULL) 886 887 add_prop(nodeh, &proph, node_name, row, 888 PP_EXPONENT, snmp_syserr_p); 889 CHECK_LINKRESET(snmp_syserr_p, NULL) 890 891 add_prop(nodeh, &proph, node_name, row, 892 PP_RATE_UNITS, snmp_syserr_p); 893 CHECK_LINKRESET(snmp_syserr_p, NULL) 894 895 add_thresholds(nodeh, row, snmp_syserr_p); 896 CHECK_LINKRESET(snmp_syserr_p, NULL) 897 898 } else if (sensor_class == SSSC_BINARY) { 899 if (sensor_type == SSST_TEMPERATURE) { 900 ADD_NODE(PICL_CLASS_TEMPERATURE_INDICATOR) 901 } else if (sensor_type == SSST_VOLTAGE) { 902 ADD_NODE(PICL_CLASS_VOLTAGE_INDICATOR) 903 } else if (sensor_type == SSST_CURRENT) { 904 ADD_NODE(PICL_CLASS_CURRENT_INDICATOR) 905 } else if (sensor_type == SSST_TACHOMETER) { 906 ADD_NODE(PICL_CLASS_RPM_INDICATOR) 907 } else if (sensor_type == SSST_PRESENCE) { 908 ADD_NODE(PICL_CLASS_PRESENCE_INDICATOR) 909 } else if (sensor_type == SSST_HUMIDITY) { 910 ADD_NODE(PICL_CLASS_HUMIDITY_INDICATOR) 911 } else { 912 ADD_NODE(PICL_CLASS_INDICATOR) 913 } 914 915 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 916 snmp_syserr_p); 917 CHECK_LINKRESET(snmp_syserr_p, NULL) 918 919 add_prop(nodeh, &proph, node_name, row, PP_CONDITION, 920 snmp_syserr_p); 921 CHECK_LINKRESET(snmp_syserr_p, NULL) 922 923 add_prop(nodeh, &proph, node_name, row, PP_EXPECTED, 924 snmp_syserr_p); 925 CHECK_LINKRESET(snmp_syserr_p, NULL) 926 } else { 927 log_msg(LOG_ERR, 928 SNMPP_UNSUPP_SENSOR_CLASS, sensor_class, row); 929 return (NULL); 930 } 931 break; 932 933 case SPC_MODULE: 934 ADD_NODE(PICL_CLASS_MODULE) 935 936 add_prop(nodeh, &proph, node_name, row, PP_OPSTATUS, 937 snmp_syserr_p); 938 CHECK_LINKRESET(snmp_syserr_p, NULL) 939 940 add_prop(nodeh, &proph, node_name, row, PP_REPLACEABLE, 941 snmp_syserr_p); 942 CHECK_LINKRESET(snmp_syserr_p, NULL) 943 944 add_prop(nodeh, &proph, node_name, row, PP_HOTSWAPPABLE, 945 snmp_syserr_p); 946 CHECK_LINKRESET(snmp_syserr_p, NULL) 947 break; 948 949 case SPC_PORT: 950 ADD_NODE(PICL_CLASS_PORT) 951 break; 952 953 case SPC_STACK: 954 ADD_NODE(PICL_CLASS_STACK) 955 break; 956 957 default: 958 log_msg(LOG_WARNING, 959 SNMPP_UNKNOWN_ENTPHYSCLASS, ent_physclass, row); 960 free(phys_name); 961 return (NULL); 962 } 963 964 add_prop(nodeh, &proph, node_name, row, PP_DESCRIPTION, snmp_syserr_p); 965 CHECK_LINKRESET(snmp_syserr_p, NULL) 966 967 add_prop(nodeh, &proph, node_name, row, PP_LABEL, snmp_syserr_p); 968 CHECK_LINKRESET(snmp_syserr_p, NULL) 969 970 add_prop(nodeh, &proph, node_name, row, PP_HW_REVISION, snmp_syserr_p); 971 CHECK_LINKRESET(snmp_syserr_p, NULL) 972 973 add_prop(nodeh, &proph, node_name, row, PP_FW_REVISION, snmp_syserr_p); 974 CHECK_LINKRESET(snmp_syserr_p, NULL) 975 976 add_prop(nodeh, &proph, node_name, row, PP_SERIAL_NUM, snmp_syserr_p); 977 CHECK_LINKRESET(snmp_syserr_p, NULL) 978 979 add_prop(nodeh, &proph, node_name, row, PP_MFG_NAME, snmp_syserr_p); 980 CHECK_LINKRESET(snmp_syserr_p, NULL) 981 982 add_prop(nodeh, &proph, node_name, row, PP_MODEL_NAME, snmp_syserr_p); 983 CHECK_LINKRESET(snmp_syserr_p, NULL) 984 985 add_prop(nodeh, &proph, node_name, row, PP_IS_FRU, snmp_syserr_p); 986 CHECK_LINKRESET(snmp_syserr_p, NULL) 987 988 free(phys_name); 989 save_nodeh(nodeh, row); 990 991 return (nodeh); 992 } 993 994 /* 995 * Saves the node handle and the row id into physplat_nodes[]. If we're 996 * doing this in response to a hotplug event, we should've freed the 997 * old physplat_nodes before entering here to save the first node of the 998 * new physplat subtree. 999 */ 1000 static void 1001 save_nodeh(picl_nodehdl_t nodeh, int row) 1002 { 1003 size_t sz, count; 1004 picl_nodehdl_t *p; 1005 1006 if (row >= n_physplat_nodes) { 1007 count = (((size_t)row >> NODE_BLOCK_SHIFT) + 1) * 1008 N_ELEMS_IN_NODE_BLOCK; 1009 sz = count * sizeof (picl_nodehdl_t); 1010 1011 p = (picl_nodehdl_t *)calloc(count, sizeof (picl_nodehdl_t)); 1012 if (p == NULL) { 1013 log_msg(LOG_ERR, SNMPP_NO_MEM, sz); 1014 return; 1015 } 1016 1017 if (physplat_nodes) { 1018 (void) memcpy((void *) p, (void *) physplat_nodes, 1019 n_physplat_nodes * sizeof (picl_nodehdl_t)); 1020 free((void *) physplat_nodes); 1021 } 1022 1023 physplat_nodes = p; 1024 n_physplat_nodes = count; 1025 } 1026 1027 physplat_nodes[row] = nodeh; 1028 } 1029 1030 static picl_nodehdl_t 1031 lookup_nodeh(int row) 1032 { 1033 if (row >= n_physplat_nodes) 1034 return (NULL); 1035 1036 return (physplat_nodes[row]); 1037 } 1038 1039 /* 1040 * We enter this routine only when we are building the physical-platform 1041 * subtree, whether for the first time or in response to a hotplug event. 1042 * If we're here for rebuilding the tree, we have already set stale_tree 1043 * to be B_TRUE, so no one else would be accessing vol_props, n_vol_props 1044 * or volprop_ndx. If we're here to build the tree for the first time, 1045 * picld hasn't yet created doors and is running single-threaded, so no 1046 * one else would be accessing them anyway. 1047 */ 1048 static void 1049 save_volprop(picl_prophdl_t prop, char *oidstr, int row, int proptype) 1050 { 1051 vol_prophdl_t *p; 1052 int count; 1053 1054 if (volprop_ndx == n_vol_props) { 1055 count = n_vol_props + N_ELEMS_IN_VOLPROP_BLOCK; 1056 p = (vol_prophdl_t *)calloc(count, sizeof (vol_prophdl_t)); 1057 if (p == NULL) { 1058 log_msg(LOG_ERR, SNMPP_NO_MEM, 1059 count * sizeof (vol_prophdl_t)); 1060 return; 1061 } 1062 1063 if (vol_props) { 1064 (void) memcpy((void *) p, (void *) vol_props, 1065 n_vol_props * sizeof (vol_prophdl_t)); 1066 free((void *) vol_props); 1067 } 1068 1069 vol_props = p; 1070 n_vol_props += N_ELEMS_IN_VOLPROP_BLOCK; 1071 } 1072 1073 vol_props[volprop_ndx].prop = prop; 1074 vol_props[volprop_ndx].oidstr = oidstr; 1075 vol_props[volprop_ndx].row = row; 1076 vol_props[volprop_ndx].proptype = proptype; 1077 1078 volprop_ndx++; 1079 } 1080 1081 static void 1082 check_for_stale_data(boolean_t nocache) 1083 { 1084 int cur_change_time; 1085 int ret; 1086 int snmp_syserr; 1087 1088 (void) rw_wrlock(&stale_tree_rwlp); 1089 1090 /* 1091 * Check if some other thread beat us to it 1092 */ 1093 if (stale_tree == B_TRUE) { 1094 (void) rw_unlock(&stale_tree_rwlp); 1095 return; 1096 } 1097 1098 /* 1099 * Cache OID_entLastChangeTime for up to 10 seconds before 1100 * fetching it from ILOM again. This prevents us from fetching 1101 * this value from ILOM when the we're filling or refreshing a 1102 * whole bunch of items in the cache around the same time. 1103 */ 1104 if (nocache == B_FALSE && time(NULL) - change_time_check <= 10) { 1105 (void) rw_unlock(&stale_tree_rwlp); 1106 return; 1107 } 1108 1109 /* 1110 * Check if mib data has changed (hotplug? link-reset?) 1111 */ 1112 do { 1113 snmp_syserr = 0; 1114 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 1115 &cur_change_time, &snmp_syserr); 1116 (void) time(&change_time_check); 1117 if ((ret == 0) && (cur_change_time == change_time)) { 1118 (void) rw_unlock(&stale_tree_rwlp); 1119 return; 1120 } 1121 } while (ret != 0 && snmp_syserr == EINTR); 1122 1123 /* 1124 * If we can't read entLastChangeTime we assume we need to rebuild 1125 * the tree. This will also cover the case when we need to rebuild 1126 * the tree because a link reset had happened. 1127 */ 1128 LOGPRINTF2("check_for_stale_data: LastChange times have changed, " 1129 "(%#x != %#x)\n", change_time, cur_change_time); 1130 1131 /* 1132 * If the mib data has changed, we need to rebuild the physical-platform 1133 * subtree. To do this, we set a flag to mark the tree stale, 1134 * so that any future reads to get value of volatile properties will 1135 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag 1136 * is reset by the tree builder thread. 1137 */ 1138 stale_tree = B_TRUE; 1139 if (vol_props) { 1140 free(vol_props); 1141 } 1142 vol_props = NULL; 1143 volprop_ndx = 0; 1144 n_vol_props = 0; 1145 1146 (void) rw_unlock(&stale_tree_rwlp); 1147 1148 (void) mutex_lock(&rebuild_tree_lock); 1149 rebuild_tree = B_TRUE; 1150 (void) cond_signal(&rebuild_tree_cv); 1151 LOGPRINTF("check_for_stale_data: signalled tree builder\n"); 1152 (void) mutex_unlock(&rebuild_tree_lock); 1153 } 1154 1155 /* 1156 * This is the critical routine. This callback is invoked by picl whenever 1157 * it needs to fetch the value of a volatile property. The first thing we 1158 * must do, however, is to see if there has been a hotplug or a link-reset 1159 * event since the last time we built the tree and whether we need to 1160 * rebuild the tree. If so, we do whatever is necessary to make that happen, 1161 * but return PICL_PROPVALUNAVAILABLE for now, without making any further 1162 * snmp requests or accessing any globals. 1163 */ 1164 static int 1165 read_volprop(ptree_rarg_t *parg, void *buf) 1166 { 1167 char *pstr; 1168 int propval; 1169 int i, ndx; 1170 int ret; 1171 int snmp_syserr = 0; 1172 1173 /* 1174 * First check for any event that would make us throw away 1175 * the existing /physical-platform subtree and rebuild 1176 * another one. If we are rebuilding the subtree, we just 1177 * return the stale value until the tree is fully built. 1178 */ 1179 check_for_stale_data(B_FALSE); 1180 1181 (void) rw_rdlock(&stale_tree_rwlp); 1182 1183 if (stale_tree == B_TRUE) { 1184 (void) rw_unlock(&stale_tree_rwlp); 1185 return (PICL_PROPVALUNAVAILABLE); 1186 } 1187 1188 for (i = 0; i < volprop_ndx; i++) { 1189 if (vol_props[i].prop == parg->proph) { 1190 ndx = i; 1191 break; 1192 } 1193 } 1194 if (i == volprop_ndx) { 1195 (void) rw_unlock(&stale_tree_rwlp); 1196 log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph); 1197 return (PICL_FAILURE); 1198 } 1199 1200 /* 1201 * If we can't read the value, return failure. Even if this was 1202 * due to a link reset, between the check for stale data and now, 1203 * the next volatile callback by picl will initiate a tree-rebuild. 1204 */ 1205 ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row, 1206 &propval, &snmp_syserr); 1207 if (ret < 0) { 1208 (void) rw_unlock(&stale_tree_rwlp); 1209 check_for_stale_data(B_TRUE); 1210 if (stale_tree == B_TRUE) { 1211 return (PICL_PROPVALUNAVAILABLE); 1212 } 1213 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1214 snmp_syserr ? snmp_syserr : ret, 1215 vol_props[ndx].oidstr, vol_props[ndx].row); 1216 return (PICL_FAILURE); 1217 } 1218 1219 switch (vol_props[ndx].proptype) { 1220 case VPT_PLATOPSTATE: 1221 if (propval == SSOS_DISABLED) { 1222 (void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN); 1223 } else if (propval == SSOS_ENABLED) { 1224 (void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN); 1225 } else { 1226 (void) rw_unlock(&stale_tree_rwlp); 1227 log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE, 1228 propval, vol_props[ndx].row); 1229 return (PICL_FAILURE); 1230 } 1231 break; 1232 1233 case VPT_NUMSENSOR: 1234 (void) memcpy(buf, &propval, sizeof (propval)); 1235 break; 1236 1237 case VPT_BINSENSOR: 1238 if (propval == ST_TRUE) { 1239 ret = snmp_get_str(hdl, 1240 OID_sunPlatBinarySensorInterpretTrue, 1241 vol_props[ndx].row, &pstr, &snmp_syserr); 1242 if (snmp_syserr == ECANCELED) { 1243 (void) rw_unlock(&stale_tree_rwlp); 1244 if (pstr) 1245 free(pstr); 1246 return (PICL_FAILURE); 1247 } 1248 if (ret < 0 || pstr == NULL) { 1249 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1250 snmp_syserr ? snmp_syserr : ret, 1251 OID_sunPlatBinarySensorInterpretTrue, 1252 vol_props[ndx].row); 1253 (void) strlcpy(buf, STR_ST_TRUE, 1254 MAX_TRUTHVAL_LEN); 1255 } else { 1256 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1257 } 1258 if (pstr) 1259 free(pstr); 1260 } else if (propval == ST_FALSE) { 1261 ret = snmp_get_str(hdl, 1262 OID_sunPlatBinarySensorInterpretFalse, 1263 vol_props[ndx].row, &pstr, &snmp_syserr); 1264 if (snmp_syserr == ECANCELED) { 1265 (void) rw_unlock(&stale_tree_rwlp); 1266 if (pstr) 1267 free(pstr); 1268 return (PICL_FAILURE); 1269 } 1270 if (ret < 0 || pstr == NULL) { 1271 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1272 snmp_syserr ? snmp_syserr : ret, 1273 OID_sunPlatBinarySensorInterpretFalse, 1274 vol_props[ndx].row); 1275 (void) strlcpy(buf, STR_ST_FALSE, 1276 MAX_TRUTHVAL_LEN); 1277 } else { 1278 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1279 } 1280 if (pstr) 1281 free(pstr); 1282 } else { 1283 (void) rw_unlock(&stale_tree_rwlp); 1284 log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT, 1285 propval, vol_props[ndx].row); 1286 return (PICL_FAILURE); 1287 } 1288 break; 1289 1290 case VPT_ALARMSTATE: 1291 if (propval == SSAS_OFF) { 1292 (void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN); 1293 } else if (propval == SSAS_STEADY) { 1294 (void) strlcpy(buf, STR_SSAS_STEADY, 1295 MAX_ALARMSTATE_LEN); 1296 } else if (propval == SSAS_ALTERNATING) { 1297 (void) strlcpy(buf, STR_SSAS_ALTERNATING, 1298 MAX_ALARMSTATE_LEN); 1299 } else { 1300 (void) strlcpy(buf, STR_SSAS_UNKNOWN, 1301 MAX_ALARMSTATE_LEN); 1302 } 1303 break; 1304 1305 case VPT_BATTERYSTATUS: 1306 switch (propval) { 1307 case SSBS_OTHER: 1308 (void) strlcpy(buf, STR_SSBS_OTHER, 1309 MAX_BATTERYSTATUS_LEN); 1310 break; 1311 case SSBS_FULLYCHARGED: 1312 (void) strlcpy(buf, STR_SSBS_FULLYCHARGED, 1313 MAX_BATTERYSTATUS_LEN); 1314 break; 1315 case SSBS_LOW: 1316 (void) strlcpy(buf, STR_SSBS_LOW, 1317 MAX_BATTERYSTATUS_LEN); 1318 break; 1319 case SSBS_CRITICAL: 1320 (void) strlcpy(buf, STR_SSBS_CRITICAL, 1321 MAX_BATTERYSTATUS_LEN); 1322 break; 1323 case SSBS_CHARGING: 1324 (void) strlcpy(buf, STR_SSBS_CHARGING, 1325 MAX_BATTERYSTATUS_LEN); 1326 break; 1327 case SSBS_CHARGING_AND_LOW: 1328 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW, 1329 MAX_BATTERYSTATUS_LEN); 1330 break; 1331 case SSBS_CHARGING_AND_HIGH: 1332 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH, 1333 MAX_BATTERYSTATUS_LEN); 1334 break; 1335 case SSBS_CHARGING_AND_CRITICAL: 1336 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL, 1337 MAX_BATTERYSTATUS_LEN); 1338 break; 1339 case SSBS_UNDEFINED: 1340 (void) strlcpy(buf, STR_SSBS_UNDEFINED, 1341 MAX_BATTERYSTATUS_LEN); 1342 break; 1343 case SSBS_PARTIALLY_CHARGED: 1344 (void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED, 1345 MAX_BATTERYSTATUS_LEN); 1346 break; 1347 case SSBS_UNKNOWN: 1348 default: 1349 (void) strlcpy(buf, STR_SSBS_UNKNOWN, 1350 MAX_BATTERYSTATUS_LEN); 1351 break; 1352 } 1353 break; 1354 } 1355 1356 (void) rw_unlock(&stale_tree_rwlp); 1357 1358 return (PICL_SUCCESS); 1359 } 1360 1361 static void 1362 threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname, 1363 int *snmp_syserr_p) 1364 { 1365 picl_prophdl_t prop; 1366 int err; 1367 int val; 1368 1369 if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) { 1370 err = add_volatile_prop(node, propname, PICL_PTYPE_INT, 1371 PICL_READ, sizeof (int), read_volprop, NULL, &prop); 1372 if (err == PICL_SUCCESS) 1373 save_volprop(prop, oidstr, row, VPT_NUMSENSOR); 1374 } else 1375 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1376 *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row); 1377 } 1378 1379 static void 1380 add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p) 1381 { 1382 uchar_t *bitstr = NULL; 1383 uchar_t enabled; 1384 uint_t nbytes; 1385 int ret; 1386 1387 ret = snmp_get_str(hdl, 1388 OID_sunPlatNumericSensorEnabledThresholds, 1389 row, (char **)&bitstr, snmp_syserr_p); 1390 if (ret == -1) { 1391 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1392 *snmp_syserr_p ? *snmp_syserr_p : ret, 1393 OID_sunPlatNumericSensorEnabledThresholds, row); 1394 } else { 1395 nbytes = strlen((const char *)bitstr); 1396 } 1397 1398 CHECK_LINKRESET_VOID(snmp_syserr_p); 1399 1400 /* 1401 * No bit string of threshold masks was returned, so we can't 1402 * assume that any thresholds exist. 1403 * 1404 * This mask prevents us from attempting to fetch thresholds 1405 * which don't apply to the sensor or that aren't there anyway, 1406 * That speeds up the plug-in significantly since otherwise it 1407 * takes several seconds to time out. 1408 */ 1409 if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) { 1410 if (bitstr) 1411 free(bitstr); 1412 return; 1413 } else if (nbytes == 1) { 1414 /* 1415 * The ALOM snmp agent doesn't adhere to the BER rules for 1416 * encoding bit strings. While the BER states that bitstrings 1417 * must begin from the second octet after length, and the 1418 * first octet after length must indicate the number of unused 1419 * bits in the last octet, the snmp agent simply sends the 1420 * bitstring data as if it were octet string -- that is, the 1421 * "unused bits" octet is missing. 1422 */ 1423 enabled = bitstr[0]; 1424 } else if (nbytes == 2) 1425 enabled = bitstr[1]; 1426 1427 if (bitstr) { 1428 free(bitstr); 1429 } 1430 1431 if (enabled & LOWER_FATAL) { 1432 threshold(node, 1433 OID_sunPlatNumericSensorLowerThresholdFatal, row, 1434 PICL_PROP_LOW_POWER_OFF, snmp_syserr_p); 1435 CHECK_LINKRESET_VOID(snmp_syserr_p) 1436 } 1437 if (enabled & LOWER_CRITICAL) { 1438 threshold(node, 1439 OID_sunPlatNumericSensorLowerThresholdCritical, row, 1440 PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p); 1441 CHECK_LINKRESET_VOID(snmp_syserr_p) 1442 } 1443 if (enabled & LOWER_NON_CRITICAL) { 1444 threshold(node, 1445 OID_sunPlatNumericSensorLowerThresholdNonCritical, row, 1446 PICL_PROP_LOW_WARNING, snmp_syserr_p); 1447 CHECK_LINKRESET_VOID(snmp_syserr_p) 1448 } 1449 if (enabled & UPPER_NON_CRITICAL) { 1450 threshold(node, 1451 OID_sunPlatNumericSensorUpperThresholdNonCritical, row, 1452 PICL_PROP_HIGH_WARNING, snmp_syserr_p); 1453 CHECK_LINKRESET_VOID(snmp_syserr_p) 1454 } 1455 if (enabled & UPPER_CRITICAL) { 1456 threshold(node, 1457 OID_sunPlatNumericSensorUpperThresholdCritical, row, 1458 PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p); 1459 CHECK_LINKRESET_VOID(snmp_syserr_p) 1460 } 1461 if (enabled & UPPER_FATAL) { 1462 threshold(node, 1463 OID_sunPlatNumericSensorUpperThresholdFatal, row, 1464 PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p); 1465 CHECK_LINKRESET_VOID(snmp_syserr_p) 1466 } 1467 } 1468 1469 static char * 1470 get_slot_type(int row, int *snmp_syserr_p) 1471 { 1472 char *p; 1473 char *slott = NULL; 1474 int ret; 1475 1476 ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes, 1477 row, &p, snmp_syserr_p); 1478 CHECK_LINKRESET(snmp_syserr_p, NULL) 1479 1480 if ((ret == 0) && p && *p) { 1481 slott = p; 1482 if ((p = strchr(slott, '\n')) != NULL) 1483 *p = 0; 1484 } else { 1485 log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row); 1486 if (p) { 1487 free(p); 1488 } 1489 } 1490 1491 return (slott); 1492 } 1493 1494 /* 1495 * Create and add the specified volatile property 1496 */ 1497 static int 1498 add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access, 1499 int size, int (*rdfunc)(ptree_rarg_t *, void *), 1500 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp) 1501 { 1502 ptree_propinfo_t propinfo; 1503 picl_prophdl_t prop; 1504 int err; 1505 1506 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1507 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc); 1508 if (err != PICL_SUCCESS) { 1509 log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err); 1510 return (err); 1511 } 1512 1513 err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop); 1514 if (err != PICL_SUCCESS) { 1515 log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node); 1516 return (err); 1517 } 1518 1519 if (propp) 1520 *propp = prop; 1521 1522 return (PICL_SUCCESS); 1523 } 1524 1525 /* 1526 * Add the specified string property to the node 1527 */ 1528 static int 1529 add_string_prop(picl_nodehdl_t node, char *propname, char *propval) 1530 { 1531 ptree_propinfo_t propinfo; 1532 int err; 1533 1534 if (*propval == '\0') 1535 return (PICL_SUCCESS); 1536 1537 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1538 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1, 1539 propname, NULL, NULL); 1540 if (err != PICL_SUCCESS) { 1541 log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err); 1542 return (err); 1543 } 1544 1545 err = ptree_create_and_add_prop(node, &propinfo, propval, NULL); 1546 if (err != PICL_SUCCESS) { 1547 log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node); 1548 return (err); 1549 } 1550 1551 return (PICL_SUCCESS); 1552 } 1553 1554 /* 1555 * Add the specified void property to the node 1556 */ 1557 static int 1558 add_void_prop(picl_nodehdl_t node, char *propname) 1559 { 1560 ptree_propinfo_t propinfo; 1561 int err; 1562 1563 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1564 PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL); 1565 if (err != PICL_SUCCESS) { 1566 log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err); 1567 return (err); 1568 } 1569 1570 err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL); 1571 if (err != PICL_SUCCESS) { 1572 log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node); 1573 return (err); 1574 } 1575 1576 return (PICL_SUCCESS); 1577 } 1578 1579 static void 1580 add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 1581 int row, sp_propid_t pp, int *snmp_syserr_p) 1582 { 1583 char *serial_num; 1584 char *slot_type; 1585 char *fw_revision, *hw_revision; 1586 char *mfg_name, *model_name; 1587 char *phys_descr; 1588 int val; 1589 int ret; 1590 1591 switch (pp) { 1592 case PP_SERIAL_NUM: 1593 ret = snmp_get_str(hdl, OID_entPhysicalSerialNum, 1594 row, &serial_num, snmp_syserr_p); 1595 CHECK_LINKRESET_VOID(snmp_syserr_p) 1596 if ((ret == 0) && serial_num) { 1597 (void) add_string_prop(nodeh, 1598 PICL_PROP_SERIAL_NUMBER, serial_num); 1599 free((void *) serial_num); 1600 } 1601 if (ret == -1) 1602 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1603 *snmp_syserr_p ? *snmp_syserr_p : ret, 1604 OID_entPhysicalSerialNum, row); 1605 break; 1606 1607 case PP_SLOT_TYPE: 1608 if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) { 1609 CHECK_LINKRESET_VOID(snmp_syserr_p) 1610 (void) add_string_prop(nodeh, 1611 PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE); 1612 } else { 1613 (void) add_string_prop(nodeh, 1614 PICL_PROP_SLOT_TYPE, slot_type); 1615 free((void *) slot_type); 1616 } 1617 break; 1618 1619 case PP_STATE: 1620 ret = add_volatile_prop(nodeh, PICL_PROP_STATE, 1621 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN, 1622 read_volprop, NULL, php); 1623 if (ret == PICL_SUCCESS) { 1624 save_volprop(*php, OID_sunPlatAlarmState, row, 1625 VPT_ALARMSTATE); 1626 } 1627 break; 1628 1629 case PP_OPSTATUS: 1630 ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS, 1631 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN, 1632 read_volprop, NULL, php); 1633 if (ret == PICL_SUCCESS) { 1634 save_volprop(*php, 1635 OID_sunPlatEquipmentOperationalState, row, 1636 VPT_PLATOPSTATE); 1637 } 1638 break; 1639 1640 case PP_BATT_STATUS: 1641 ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS, 1642 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN, 1643 read_volprop, NULL, php); 1644 if (ret == PICL_SUCCESS) { 1645 save_volprop(*php, OID_sunPlatBatteryStatus, row, 1646 VPT_BATTERYSTATUS); 1647 } 1648 break; 1649 1650 case PP_TEMPERATURE: 1651 ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE, 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_VOLTAGE: 1661 ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE, 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_CURRENT: 1671 ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT, 1672 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1673 NULL, php); 1674 if (ret == PICL_SUCCESS) { 1675 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1676 row, VPT_NUMSENSOR); 1677 } 1678 break; 1679 1680 case PP_SPEED: 1681 ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT, 1682 PICL_READ, sizeof (int), read_volprop, NULL, php); 1683 if (ret == PICL_SUCCESS) { 1684 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1685 row, VPT_NUMSENSOR); 1686 } 1687 break; 1688 1689 case PP_SENSOR_VALUE: 1690 ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE, 1691 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1692 NULL, php); 1693 if (ret == PICL_SUCCESS) { 1694 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1695 row, VPT_NUMSENSOR); 1696 } 1697 break; 1698 1699 case PP_CONDITION: 1700 ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION, 1701 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1702 read_volprop, NULL, php); 1703 if (ret == PICL_SUCCESS) { 1704 save_volprop(*php, OID_sunPlatBinarySensorCurrent, 1705 row, VPT_BINSENSOR); 1706 } 1707 break; 1708 1709 case PP_EXPECTED: 1710 ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED, 1711 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1712 read_volprop, NULL, php); 1713 if (ret == PICL_SUCCESS) { 1714 save_volprop(*php, OID_sunPlatBinarySensorExpected, 1715 row, VPT_BINSENSOR); 1716 } 1717 break; 1718 1719 case PP_EXPONENT: 1720 ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT, 1721 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1722 NULL, php); 1723 if (ret == PICL_SUCCESS) { 1724 save_volprop(*php, OID_sunPlatNumericSensorExponent, 1725 row, VPT_NUMSENSOR); 1726 } 1727 break; 1728 1729 case PP_REPLACEABLE: 1730 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable, 1731 row, &val, snmp_syserr_p); 1732 CHECK_LINKRESET_VOID(snmp_syserr_p) 1733 if ((ret == 0) && (val == ST_TRUE)) 1734 (void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE); 1735 if (ret == -1) 1736 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1737 *snmp_syserr_p ? *snmp_syserr_p : ret, 1738 OID_sunPlatCircuitPackReplaceable, row); 1739 break; 1740 1741 case PP_HOTSWAPPABLE: 1742 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable, 1743 row, &val, snmp_syserr_p); 1744 CHECK_LINKRESET_VOID(snmp_syserr_p) 1745 if ((ret == 0) && (val == ST_TRUE)) 1746 (void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE); 1747 if (ret == -1) 1748 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1749 *snmp_syserr_p ? *snmp_syserr_p : ret, 1750 OID_sunPlatCircuitPackHotSwappable, row); 1751 break; 1752 1753 case PP_IS_FRU: 1754 ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row, 1755 &val, snmp_syserr_p); 1756 CHECK_LINKRESET_VOID(snmp_syserr_p) 1757 if ((ret == 0) && (val == ST_TRUE)) 1758 (void) add_void_prop(nodeh, PICL_PROP_IS_FRU); 1759 if (ret == -1) 1760 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1761 *snmp_syserr_p ? *snmp_syserr_p : ret, 1762 OID_entPhysicalIsFRU, row); 1763 break; 1764 1765 case PP_HW_REVISION: 1766 ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev, 1767 row, &hw_revision, snmp_syserr_p); 1768 CHECK_LINKRESET_VOID(snmp_syserr_p) 1769 if ((ret == 0) && hw_revision) { 1770 (void) add_string_prop(nodeh, 1771 PICL_PROP_HW_REVISION, hw_revision); 1772 free((void *) hw_revision); 1773 } 1774 if (ret == -1) 1775 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1776 *snmp_syserr_p ? *snmp_syserr_p : ret, 1777 OID_entPhysicalHardwareRev, row); 1778 break; 1779 1780 case PP_FW_REVISION: 1781 ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev, 1782 row, &fw_revision, snmp_syserr_p); 1783 CHECK_LINKRESET_VOID(snmp_syserr_p) 1784 if ((ret == 0) && fw_revision) { 1785 (void) add_string_prop(nodeh, 1786 PICL_PROP_FW_REVISION, fw_revision); 1787 free((void *) fw_revision); 1788 } 1789 if (ret == -1) 1790 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1791 *snmp_syserr_p ? *snmp_syserr_p : ret, 1792 OID_entPhysicalFirmwareRev, row); 1793 break; 1794 1795 case PP_MFG_NAME: 1796 ret = snmp_get_str(hdl, OID_entPhysicalMfgName, 1797 row, &mfg_name, snmp_syserr_p); 1798 CHECK_LINKRESET_VOID(snmp_syserr_p) 1799 if ((ret == 0) && mfg_name) { 1800 (void) add_string_prop(nodeh, 1801 PICL_PROP_MFG_NAME, mfg_name); 1802 free((void *) mfg_name); 1803 } 1804 if (ret == -1) 1805 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1806 *snmp_syserr_p ? *snmp_syserr_p : ret, 1807 OID_entPhysicalMfgName, row); 1808 break; 1809 1810 case PP_MODEL_NAME: 1811 ret = snmp_get_str(hdl, OID_entPhysicalModelName, 1812 row, &model_name, snmp_syserr_p); 1813 CHECK_LINKRESET_VOID(snmp_syserr_p) 1814 if ((ret == 0) && model_name) { 1815 (void) add_string_prop(nodeh, 1816 PICL_PROP_MODEL_NAME, model_name); 1817 free((void *) model_name); 1818 } 1819 if (ret == -1) 1820 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1821 *snmp_syserr_p ? *snmp_syserr_p : ret, 1822 OID_entPhysicalModelName, row); 1823 break; 1824 1825 case PP_DESCRIPTION: 1826 ret = snmp_get_str(hdl, OID_entPhysicalDescr, 1827 row, &phys_descr, snmp_syserr_p); 1828 CHECK_LINKRESET_VOID(snmp_syserr_p) 1829 if ((ret == 0) && phys_descr) { 1830 (void) add_string_prop(nodeh, 1831 PICL_PROP_PHYS_DESCRIPTION, phys_descr); 1832 free((void *) phys_descr); 1833 } 1834 if (ret == -1) 1835 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1836 *snmp_syserr_p ? *snmp_syserr_p : ret, 1837 OID_entPhysicalDescr, row); 1838 break; 1839 1840 case PP_LABEL: 1841 if (label && *label) 1842 (void) add_string_prop(nodeh, PICL_PROP_LABEL, label); 1843 break; 1844 1845 case PP_BASE_UNITS: 1846 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits, 1847 row, &val, snmp_syserr_p); 1848 CHECK_LINKRESET_VOID(snmp_syserr_p) 1849 if ((ret == 0) && (val > 0) && (val < n_baseunits)) { 1850 (void) add_string_prop(nodeh, 1851 PICL_PROP_BASE_UNITS, sensor_baseunits[val]); 1852 } 1853 if (ret == -1) 1854 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1855 *snmp_syserr_p ? *snmp_syserr_p : ret, 1856 OID_sunPlatNumericSensorBaseUnits, row); 1857 break; 1858 1859 case PP_RATE_UNITS: 1860 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits, 1861 row, &val, snmp_syserr_p); 1862 CHECK_LINKRESET_VOID(snmp_syserr_p) 1863 if ((ret == 0) && (val > 0) && (val < n_rateunits)) { 1864 (void) add_string_prop(nodeh, 1865 PICL_PROP_RATE_UNITS, sensor_rateunits[val]); 1866 } 1867 if (ret == -1) 1868 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1869 *snmp_syserr_p ? *snmp_syserr_p : ret, 1870 OID_sunPlatNumericSensorRateUnits, row); 1871 break; 1872 } 1873 } 1874 1875 /* 1876 * Initialize the SNMP library's cache refresh subsystem, then periodically 1877 * process refresh job to prevent cache entries from expiring. 1878 */ 1879 /*ARGSUSED*/ 1880 static void * 1881 cache_refresher(void *arg) 1882 { 1883 int jobs; 1884 int next_expiration; 1885 timestruc_t to; 1886 hrtime_t cycle_start, cycle_elapsed; 1887 1888 /* 1889 * Initialize refresh subsystem 1890 */ 1891 LOGPRINTF("Initializing SNMP refresh subsystem.\n"); 1892 if (snmp_refresh_init() < 0) { 1893 return ((void *)-1); 1894 } 1895 1896 (void) mutex_lock(&cache_refresh_lock); 1897 1898 1899 for (;;) { 1900 cycle_start = gethrtime(); 1901 1902 /* 1903 * Process jobs from the snmp cache refresh work queue until one 1904 * of the following conditions is true: 1905 * 1) we are told to exit, or 1906 * 2) we have processed at least as many jobs as recommended by 1907 * the library, and the next job expiration is at least 1908 * CACHE_REFRESH_MIN_WINDOW * seconds away. 1909 */ 1910 jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE); 1911 while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) { 1912 (void) snmp_refresh_process_job(); 1913 jobs--; 1914 } 1915 1916 next_expiration = snmp_refresh_get_next_expiration(); 1917 while ((cache_refresh_thr_exit == B_FALSE) && 1918 ((next_expiration >= 0) && 1919 (next_expiration < CACHE_REFRESH_MIN_WINDOW))) { 1920 (void) snmp_refresh_process_job(); 1921 next_expiration = snmp_refresh_get_next_expiration(); 1922 } 1923 1924 /* 1925 * As long as we haven't been told to exit, sleep for 1926 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has 1927 * elapsed since this cycle started. If the elapsed time is 1928 * equal to or greater than 60 seconds, skip sleeping entirely. 1929 */ 1930 cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC; 1931 if ((cache_refresh_thr_exit == B_FALSE) && 1932 (cycle_elapsed < CACHE_REFRESH_CYCLE)) { 1933 to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed; 1934 to.tv_nsec = 0; 1935 (void) cond_reltimedwait(&cache_refresh_cv, 1936 &cache_refresh_lock, &to); 1937 } 1938 1939 /* 1940 * If we have been told to exit, clean up and bail out. 1941 */ 1942 if (cache_refresh_thr_exit == B_TRUE) { 1943 snmp_refresh_fini(); 1944 (void) mutex_unlock(&cache_refresh_lock); 1945 LOGPRINTF("cache_refresher: time to exit\n"); 1946 return (NULL); 1947 } 1948 1949 } 1950 1951 /*NOTREACHED*/ 1952 return (NULL); 1953 } 1954 1955 /* 1956 * Check to see if the cache_refresher thread is running. If it is, signal it 1957 * to terminate and clean up associated data structures. 1958 */ 1959 void 1960 cache_refresher_fini(void) 1961 { 1962 /* if the thread isn't running, there is nothing to do */ 1963 if (cache_refresh_thr_exit == B_TRUE) 1964 return; 1965 1966 /* wake up the cache_refresher thread, tell it to exit */ 1967 (void) mutex_lock(&cache_refresh_lock); 1968 cache_refresh_thr_exit = B_TRUE; 1969 (void) cond_signal(&cache_refresh_cv); 1970 (void) mutex_unlock(&cache_refresh_lock); 1971 1972 /* reap the thread */ 1973 (void) thr_join(cache_refresh_thr_id, NULL, NULL); 1974 1975 /* finish cleanup... */ 1976 (void) cond_destroy(&cache_refresh_cv); 1977 (void) mutex_destroy(&cache_refresh_lock); 1978 } 1979 1980 /*VARARGS2*/ 1981 static void 1982 log_msg(int pri, const char *fmt, ...) 1983 { 1984 va_list ap; 1985 1986 va_start(ap, fmt); 1987 vsyslog(pri, fmt, ap); 1988 va_end(ap); 1989 } 1990 1991 #ifdef SNMPPLUGIN_DEBUG 1992 1993 static void 1994 snmpplugin_log_init(void) 1995 { 1996 (void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL); 1997 } 1998 1999 static void 2000 snmpplugin_log(const char *fmt, ...) 2001 { 2002 va_list ap; 2003 2004 (void) mutex_lock(&snmpplugin_dbuf_lock); 2005 2006 va_start(ap, fmt); 2007 (void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap); 2008 snmpplugin_log_append(); 2009 va_end(ap); 2010 2011 (void) mutex_unlock(&snmpplugin_dbuf_lock); 2012 } 2013 2014 static void 2015 snmpplugin_log_append(void) 2016 { 2017 int len; 2018 2019 len = strlen(snmpplugin_lbuf); 2020 2021 if ((snmpplugin_dbuf_curp + len) >= 2022 (snmpplugin_dbuf + snmpplugin_dbuf_sz)) { 2023 snmpplugin_dbuf_realloc(); 2024 if (snmpplugin_dbuf == NULL) { 2025 return; 2026 } 2027 } 2028 2029 (void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf); 2030 snmpplugin_dbuf_curp += len; 2031 } 2032 2033 static void 2034 snmpplugin_dbuf_realloc(void) 2035 { 2036 char *p; 2037 size_t offset = 0; 2038 size_t count; 2039 2040 count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ; 2041 if ((p = (char *)calloc(count, 1)) == NULL) { 2042 snmpplugin_dbuf_overflow++; 2043 snmpplugin_dbuf_curp = snmpplugin_dbuf; 2044 return; 2045 } 2046 2047 if (snmpplugin_dbuf) { 2048 offset = snmpplugin_dbuf_curp - snmpplugin_dbuf; 2049 (void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz); 2050 free(snmpplugin_dbuf); 2051 } 2052 2053 snmpplugin_dbuf = p; 2054 snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ; 2055 2056 snmpplugin_dbuf_curp = snmpplugin_dbuf + offset; 2057 } 2058 #endif 2059