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 do { 1106 snmp_syserr = 0; 1107 ret = snmp_get_int(hdl, OID_entLastChangeTime, 0, 1108 &cur_change_time, &snmp_syserr); 1109 (void) time(&change_time_check); 1110 if ((ret == 0) && (cur_change_time == change_time)) { 1111 (void) rw_unlock(&stale_tree_rwlp); 1112 return; 1113 } 1114 } while (ret != 0 && snmp_syserr == EINTR); 1115 1116 /* 1117 * If we can't read entLastChangeTime we assume we need to rebuild 1118 * the tree. This will also cover the case when we need to rebuild 1119 * the tree because a link reset had happened. 1120 */ 1121 LOGPRINTF2("check_for_stale_data: LastChange times have changed, " 1122 "(%#x != %#x)\n", change_time, cur_change_time); 1123 1124 /* 1125 * If the mib data has changed, we need to rebuild the physical-platform 1126 * subtree. To do this, we set a flag to mark the tree stale, 1127 * so that any future reads to get value of volatile properties will 1128 * return PICL_PROPVALUNAVAILABLE, until the stale_tree flag 1129 * is reset by the tree builder thread. 1130 */ 1131 stale_tree = B_TRUE; 1132 if (vol_props) { 1133 free(vol_props); 1134 } 1135 vol_props = NULL; 1136 volprop_ndx = 0; 1137 n_vol_props = 0; 1138 1139 (void) rw_unlock(&stale_tree_rwlp); 1140 1141 (void) mutex_lock(&rebuild_tree_lock); 1142 rebuild_tree = B_TRUE; 1143 (void) cond_signal(&rebuild_tree_cv); 1144 LOGPRINTF("check_for_stale_data: signalled tree builder\n"); 1145 (void) mutex_unlock(&rebuild_tree_lock); 1146 } 1147 1148 /* 1149 * This is the critical routine. This callback is invoked by picl whenever 1150 * it needs to fetch the value of a volatile property. The first thing we 1151 * must do, however, is to see if there has been a hotplug or a link-reset 1152 * event since the last time we built the tree and whether we need to 1153 * rebuild the tree. If so, we do whatever is necessary to make that happen, 1154 * but return PICL_PROPVALUNAVAILABLE for now, without making any further 1155 * snmp requests or accessing any globals. 1156 */ 1157 static int 1158 read_volprop(ptree_rarg_t *parg, void *buf) 1159 { 1160 char *pstr; 1161 int propval; 1162 int i, ndx; 1163 int ret; 1164 int snmp_syserr = 0; 1165 1166 /* 1167 * First check for any event that would make us throw away 1168 * the existing /physical-platform subtree and rebuild 1169 * another one. If we are rebuilding the subtree, we just 1170 * return the stale value until the tree is fully built. 1171 */ 1172 check_for_stale_data(B_FALSE); 1173 1174 (void) rw_rdlock(&stale_tree_rwlp); 1175 1176 if (stale_tree == B_TRUE) { 1177 (void) rw_unlock(&stale_tree_rwlp); 1178 return (PICL_PROPVALUNAVAILABLE); 1179 } 1180 1181 for (i = 0; i < volprop_ndx; i++) { 1182 if (vol_props[i].prop == parg->proph) { 1183 ndx = i; 1184 break; 1185 } 1186 } 1187 if (i == volprop_ndx) { 1188 (void) rw_unlock(&stale_tree_rwlp); 1189 log_msg(LOG_ERR, SNMPP_CANT_FIND_VOLPROP, parg->proph); 1190 return (PICL_FAILURE); 1191 } 1192 1193 /* 1194 * If we can't read the value, return failure. Even if this was 1195 * due to a link reset, between the check for stale data and now, 1196 * the next volatile callback by picl will initiate a tree-rebuild. 1197 */ 1198 ret = snmp_get_int(hdl, vol_props[ndx].oidstr, vol_props[ndx].row, 1199 &propval, &snmp_syserr); 1200 if (ret < 0) { 1201 (void) rw_unlock(&stale_tree_rwlp); 1202 check_for_stale_data(B_TRUE); 1203 if (stale_tree == B_TRUE) { 1204 return (PICL_PROPVALUNAVAILABLE); 1205 } 1206 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1207 snmp_syserr ? snmp_syserr : ret, 1208 vol_props[ndx].oidstr, vol_props[ndx].row); 1209 return (PICL_FAILURE); 1210 } 1211 1212 switch (vol_props[ndx].proptype) { 1213 case VPT_PLATOPSTATE: 1214 if (propval == SSOS_DISABLED) { 1215 (void) strlcpy(buf, STR_SSOS_DISABLED, MAX_OPSTATE_LEN); 1216 } else if (propval == SSOS_ENABLED) { 1217 (void) strlcpy(buf, STR_SSOS_ENABLED, MAX_OPSTATE_LEN); 1218 } else { 1219 (void) rw_unlock(&stale_tree_rwlp); 1220 log_msg(LOG_ERR, SNMPP_INV_PLAT_EQUIP_OPSTATE, 1221 propval, vol_props[ndx].row); 1222 return (PICL_FAILURE); 1223 } 1224 break; 1225 1226 case VPT_NUMSENSOR: 1227 (void) memcpy(buf, &propval, sizeof (propval)); 1228 break; 1229 1230 case VPT_BINSENSOR: 1231 if (propval == ST_TRUE) { 1232 ret = snmp_get_str(hdl, 1233 OID_sunPlatBinarySensorInterpretTrue, 1234 vol_props[ndx].row, &pstr, &snmp_syserr); 1235 if (snmp_syserr == ECANCELED) { 1236 (void) rw_unlock(&stale_tree_rwlp); 1237 if (pstr) 1238 free(pstr); 1239 return (PICL_FAILURE); 1240 } 1241 if (ret < 0 || pstr == NULL) { 1242 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1243 snmp_syserr ? snmp_syserr : ret, 1244 OID_sunPlatBinarySensorInterpretTrue, 1245 vol_props[ndx].row); 1246 (void) strlcpy(buf, STR_ST_TRUE, 1247 MAX_TRUTHVAL_LEN); 1248 } else { 1249 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1250 } 1251 if (pstr) 1252 free(pstr); 1253 } else if (propval == ST_FALSE) { 1254 ret = snmp_get_str(hdl, 1255 OID_sunPlatBinarySensorInterpretFalse, 1256 vol_props[ndx].row, &pstr, &snmp_syserr); 1257 if (snmp_syserr == ECANCELED) { 1258 (void) rw_unlock(&stale_tree_rwlp); 1259 if (pstr) 1260 free(pstr); 1261 return (PICL_FAILURE); 1262 } 1263 if (ret < 0 || pstr == NULL) { 1264 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1265 snmp_syserr ? snmp_syserr : ret, 1266 OID_sunPlatBinarySensorInterpretFalse, 1267 vol_props[ndx].row); 1268 (void) strlcpy(buf, STR_ST_FALSE, 1269 MAX_TRUTHVAL_LEN); 1270 } else { 1271 (void) strlcpy(buf, pstr, MAX_TRUTHVAL_LEN); 1272 } 1273 if (pstr) 1274 free(pstr); 1275 } else { 1276 (void) rw_unlock(&stale_tree_rwlp); 1277 log_msg(LOG_ERR, SNMPP_INV_PLAT_BINSNSR_CURRENT, 1278 propval, vol_props[ndx].row); 1279 return (PICL_FAILURE); 1280 } 1281 break; 1282 1283 case VPT_ALARMSTATE: 1284 if (propval == SSAS_OFF) { 1285 (void) strlcpy(buf, STR_SSAS_OFF, MAX_ALARMSTATE_LEN); 1286 } else if (propval == SSAS_STEADY) { 1287 (void) strlcpy(buf, STR_SSAS_STEADY, 1288 MAX_ALARMSTATE_LEN); 1289 } else if (propval == SSAS_ALTERNATING) { 1290 (void) strlcpy(buf, STR_SSAS_ALTERNATING, 1291 MAX_ALARMSTATE_LEN); 1292 } else { 1293 (void) strlcpy(buf, STR_SSAS_UNKNOWN, 1294 MAX_ALARMSTATE_LEN); 1295 } 1296 break; 1297 1298 case VPT_BATTERYSTATUS: 1299 switch (propval) { 1300 case SSBS_OTHER: 1301 (void) strlcpy(buf, STR_SSBS_OTHER, 1302 MAX_BATTERYSTATUS_LEN); 1303 break; 1304 case SSBS_FULLYCHARGED: 1305 (void) strlcpy(buf, STR_SSBS_FULLYCHARGED, 1306 MAX_BATTERYSTATUS_LEN); 1307 break; 1308 case SSBS_LOW: 1309 (void) strlcpy(buf, STR_SSBS_LOW, 1310 MAX_BATTERYSTATUS_LEN); 1311 break; 1312 case SSBS_CRITICAL: 1313 (void) strlcpy(buf, STR_SSBS_CRITICAL, 1314 MAX_BATTERYSTATUS_LEN); 1315 break; 1316 case SSBS_CHARGING: 1317 (void) strlcpy(buf, STR_SSBS_CHARGING, 1318 MAX_BATTERYSTATUS_LEN); 1319 break; 1320 case SSBS_CHARGING_AND_LOW: 1321 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_LOW, 1322 MAX_BATTERYSTATUS_LEN); 1323 break; 1324 case SSBS_CHARGING_AND_HIGH: 1325 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_HIGH, 1326 MAX_BATTERYSTATUS_LEN); 1327 break; 1328 case SSBS_CHARGING_AND_CRITICAL: 1329 (void) strlcpy(buf, STR_SSBS_CHARGING_AND_CRITICAL, 1330 MAX_BATTERYSTATUS_LEN); 1331 break; 1332 case SSBS_UNDEFINED: 1333 (void) strlcpy(buf, STR_SSBS_UNDEFINED, 1334 MAX_BATTERYSTATUS_LEN); 1335 break; 1336 case SSBS_PARTIALLY_CHARGED: 1337 (void) strlcpy(buf, STR_SSBS_PARTIALLY_CHARGED, 1338 MAX_BATTERYSTATUS_LEN); 1339 break; 1340 case SSBS_UNKNOWN: 1341 default: 1342 (void) strlcpy(buf, STR_SSBS_UNKNOWN, 1343 MAX_BATTERYSTATUS_LEN); 1344 break; 1345 } 1346 break; 1347 } 1348 1349 (void) rw_unlock(&stale_tree_rwlp); 1350 1351 return (PICL_SUCCESS); 1352 } 1353 1354 static void 1355 threshold(picl_nodehdl_t node, char *oidstr, int row, char *propname, 1356 int *snmp_syserr_p) 1357 { 1358 picl_prophdl_t prop; 1359 int err; 1360 int val; 1361 1362 if ((err = snmp_get_int(hdl, oidstr, row, &val, snmp_syserr_p)) != -1) { 1363 err = add_volatile_prop(node, propname, PICL_PTYPE_INT, 1364 PICL_READ, sizeof (int), read_volprop, NULL, &prop); 1365 if (err == PICL_SUCCESS) 1366 save_volprop(prop, oidstr, row, VPT_NUMSENSOR); 1367 } else 1368 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1369 *snmp_syserr_p ? *snmp_syserr_p : err, oidstr, row); 1370 } 1371 1372 static void 1373 add_thresholds(picl_nodehdl_t node, int row, int *snmp_syserr_p) 1374 { 1375 uchar_t *bitstr = NULL; 1376 uchar_t enabled; 1377 uint_t nbytes; 1378 int ret; 1379 1380 ret = snmp_get_str(hdl, 1381 OID_sunPlatNumericSensorEnabledThresholds, 1382 row, (char **)&bitstr, snmp_syserr_p); 1383 if (ret == -1) { 1384 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1385 *snmp_syserr_p ? *snmp_syserr_p : ret, 1386 OID_sunPlatNumericSensorEnabledThresholds, row); 1387 } else { 1388 nbytes = strlen((const char *)bitstr); 1389 } 1390 1391 CHECK_LINKRESET_VOID(snmp_syserr_p); 1392 1393 /* 1394 * No bit string of threshold masks was returned, so we can't 1395 * assume that any thresholds exist. 1396 * 1397 * This mask prevents us from attempting to fetch thresholds 1398 * which don't apply to the sensor or that aren't there anyway, 1399 * That speeds up the plug-in significantly since otherwise it 1400 * takes several seconds to time out. 1401 */ 1402 if (ret < 0 || bitstr == NULL || nbytes == 0 || 2 < nbytes) { 1403 if (bitstr) 1404 free(bitstr); 1405 return; 1406 } else if (nbytes == 1) { 1407 /* 1408 * The ALOM snmp agent doesn't adhere to the BER rules for 1409 * encoding bit strings. While the BER states that bitstrings 1410 * must begin from the second octet after length, and the 1411 * first octet after length must indicate the number of unused 1412 * bits in the last octet, the snmp agent simply sends the 1413 * bitstring data as if it were octet string -- that is, the 1414 * "unused bits" octet is missing. 1415 */ 1416 enabled = bitstr[0]; 1417 } else if (nbytes == 2) 1418 enabled = bitstr[1]; 1419 1420 if (bitstr) { 1421 free(bitstr); 1422 } 1423 1424 if (enabled & LOWER_FATAL) { 1425 threshold(node, 1426 OID_sunPlatNumericSensorLowerThresholdFatal, row, 1427 PICL_PROP_LOW_POWER_OFF, snmp_syserr_p); 1428 CHECK_LINKRESET_VOID(snmp_syserr_p) 1429 } 1430 if (enabled & LOWER_CRITICAL) { 1431 threshold(node, 1432 OID_sunPlatNumericSensorLowerThresholdCritical, row, 1433 PICL_PROP_LOW_SHUTDOWN, snmp_syserr_p); 1434 CHECK_LINKRESET_VOID(snmp_syserr_p) 1435 } 1436 if (enabled & LOWER_NON_CRITICAL) { 1437 threshold(node, 1438 OID_sunPlatNumericSensorLowerThresholdNonCritical, row, 1439 PICL_PROP_LOW_WARNING, snmp_syserr_p); 1440 CHECK_LINKRESET_VOID(snmp_syserr_p) 1441 } 1442 if (enabled & UPPER_NON_CRITICAL) { 1443 threshold(node, 1444 OID_sunPlatNumericSensorUpperThresholdNonCritical, row, 1445 PICL_PROP_HIGH_WARNING, snmp_syserr_p); 1446 CHECK_LINKRESET_VOID(snmp_syserr_p) 1447 } 1448 if (enabled & UPPER_CRITICAL) { 1449 threshold(node, 1450 OID_sunPlatNumericSensorUpperThresholdCritical, row, 1451 PICL_PROP_HIGH_SHUTDOWN, snmp_syserr_p); 1452 CHECK_LINKRESET_VOID(snmp_syserr_p) 1453 } 1454 if (enabled & UPPER_FATAL) { 1455 threshold(node, 1456 OID_sunPlatNumericSensorUpperThresholdFatal, row, 1457 PICL_PROP_HIGH_POWER_OFF, snmp_syserr_p); 1458 CHECK_LINKRESET_VOID(snmp_syserr_p) 1459 } 1460 } 1461 1462 static char * 1463 get_slot_type(int row, int *snmp_syserr_p) 1464 { 1465 char *p; 1466 char *slott = NULL; 1467 int ret; 1468 1469 ret = snmp_get_str(hdl, OID_sunPlatEquipmentHolderAcceptableTypes, 1470 row, &p, snmp_syserr_p); 1471 CHECK_LINKRESET(snmp_syserr_p, NULL) 1472 1473 if ((ret == 0) && p && *p) { 1474 slott = p; 1475 if ((p = strchr(slott, '\n')) != NULL) 1476 *p = 0; 1477 } else { 1478 log_msg(LOG_WARNING, SNMPP_NO_SLOT_TYPE, row); 1479 if (p) { 1480 free(p); 1481 } 1482 } 1483 1484 return (slott); 1485 } 1486 1487 /* 1488 * Create and add the specified volatile property 1489 */ 1490 static int 1491 add_volatile_prop(picl_nodehdl_t node, char *name, int type, int access, 1492 int size, int (*rdfunc)(ptree_rarg_t *, void *), 1493 int (*wrfunc)(ptree_warg_t *, const void *), picl_prophdl_t *propp) 1494 { 1495 ptree_propinfo_t propinfo; 1496 picl_prophdl_t prop; 1497 int err; 1498 1499 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1500 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc); 1501 if (err != PICL_SUCCESS) { 1502 log_msg(LOG_ERR, SNMPP_CANT_INIT_PROPINFO, err); 1503 return (err); 1504 } 1505 1506 err = ptree_create_and_add_prop(node, &propinfo, NULL, &prop); 1507 if (err != PICL_SUCCESS) { 1508 log_msg(LOG_ERR, SNMPP_CANT_ADD_PROP, err, node); 1509 return (err); 1510 } 1511 1512 if (propp) 1513 *propp = prop; 1514 1515 return (PICL_SUCCESS); 1516 } 1517 1518 /* 1519 * Add the specified string property to the node 1520 */ 1521 static int 1522 add_string_prop(picl_nodehdl_t node, char *propname, char *propval) 1523 { 1524 ptree_propinfo_t propinfo; 1525 int err; 1526 1527 if (*propval == '\0') 1528 return (PICL_SUCCESS); 1529 1530 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1531 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(propval) + 1, 1532 propname, NULL, NULL); 1533 if (err != PICL_SUCCESS) { 1534 log_msg(LOG_ERR, SNMPP_CANT_INIT_STR_PROPINFO, err); 1535 return (err); 1536 } 1537 1538 err = ptree_create_and_add_prop(node, &propinfo, propval, NULL); 1539 if (err != PICL_SUCCESS) { 1540 log_msg(LOG_ERR, SNMPP_CANT_ADD_STR_PROP, err, node); 1541 return (err); 1542 } 1543 1544 return (PICL_SUCCESS); 1545 } 1546 1547 /* 1548 * Add the specified void property to the node 1549 */ 1550 static int 1551 add_void_prop(picl_nodehdl_t node, char *propname) 1552 { 1553 ptree_propinfo_t propinfo; 1554 int err; 1555 1556 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1557 PICL_PTYPE_VOID, PICL_READ, 0, propname, NULL, NULL); 1558 if (err != PICL_SUCCESS) { 1559 log_msg(LOG_ERR, SNMPP_CANT_INIT_VOID_PROPINFO, err); 1560 return (err); 1561 } 1562 1563 err = ptree_create_and_add_prop(node, &propinfo, NULL, NULL); 1564 if (err != PICL_SUCCESS) { 1565 log_msg(LOG_ERR, SNMPP_CANT_ADD_VOID_PROP, err, node); 1566 return (err); 1567 } 1568 1569 return (PICL_SUCCESS); 1570 } 1571 1572 static void 1573 add_prop(picl_nodehdl_t nodeh, picl_prophdl_t *php, char *label, 1574 int row, sp_propid_t pp, int *snmp_syserr_p) 1575 { 1576 char *serial_num; 1577 char *slot_type; 1578 char *fw_revision, *hw_revision; 1579 char *mfg_name, *model_name; 1580 char *phys_descr; 1581 int val; 1582 int ret; 1583 1584 switch (pp) { 1585 case PP_SERIAL_NUM: 1586 ret = snmp_get_str(hdl, OID_entPhysicalSerialNum, 1587 row, &serial_num, snmp_syserr_p); 1588 CHECK_LINKRESET_VOID(snmp_syserr_p) 1589 if ((ret == 0) && serial_num) { 1590 (void) add_string_prop(nodeh, 1591 PICL_PROP_SERIAL_NUMBER, serial_num); 1592 free((void *) serial_num); 1593 } 1594 if (ret == -1) 1595 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1596 *snmp_syserr_p ? *snmp_syserr_p : ret, 1597 OID_entPhysicalSerialNum, row); 1598 break; 1599 1600 case PP_SLOT_TYPE: 1601 if ((slot_type = get_slot_type(row, snmp_syserr_p)) == NULL) { 1602 CHECK_LINKRESET_VOID(snmp_syserr_p) 1603 (void) add_string_prop(nodeh, 1604 PICL_PROP_SLOT_TYPE, DEFAULT_SLOT_TYPE); 1605 } else { 1606 (void) add_string_prop(nodeh, 1607 PICL_PROP_SLOT_TYPE, slot_type); 1608 free((void *) slot_type); 1609 } 1610 break; 1611 1612 case PP_STATE: 1613 ret = add_volatile_prop(nodeh, PICL_PROP_STATE, 1614 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_ALARMSTATE_LEN, 1615 read_volprop, NULL, php); 1616 if (ret == PICL_SUCCESS) { 1617 save_volprop(*php, OID_sunPlatAlarmState, row, 1618 VPT_ALARMSTATE); 1619 } 1620 break; 1621 1622 case PP_OPSTATUS: 1623 ret = add_volatile_prop(nodeh, PICL_PROP_OPERATIONAL_STATUS, 1624 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_OPSTATE_LEN, 1625 read_volprop, NULL, php); 1626 if (ret == PICL_SUCCESS) { 1627 save_volprop(*php, 1628 OID_sunPlatEquipmentOperationalState, row, 1629 VPT_PLATOPSTATE); 1630 } 1631 break; 1632 1633 case PP_BATT_STATUS: 1634 ret = add_volatile_prop(nodeh, PICL_PROP_BATTERY_STATUS, 1635 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_BATTERYSTATUS_LEN, 1636 read_volprop, NULL, php); 1637 if (ret == PICL_SUCCESS) { 1638 save_volprop(*php, OID_sunPlatBatteryStatus, row, 1639 VPT_BATTERYSTATUS); 1640 } 1641 break; 1642 1643 case PP_TEMPERATURE: 1644 ret = add_volatile_prop(nodeh, PICL_PROP_TEMPERATURE, 1645 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1646 NULL, php); 1647 if (ret == PICL_SUCCESS) { 1648 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1649 row, VPT_NUMSENSOR); 1650 } 1651 break; 1652 1653 case PP_VOLTAGE: 1654 ret = add_volatile_prop(nodeh, PICL_PROP_VOLTAGE, 1655 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1656 NULL, php); 1657 if (ret == PICL_SUCCESS) { 1658 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1659 row, VPT_NUMSENSOR); 1660 } 1661 break; 1662 1663 case PP_CURRENT: 1664 ret = add_volatile_prop(nodeh, PICL_PROP_CURRENT, 1665 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1666 NULL, php); 1667 if (ret == PICL_SUCCESS) { 1668 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1669 row, VPT_NUMSENSOR); 1670 } 1671 break; 1672 1673 case PP_SPEED: 1674 ret = add_volatile_prop(nodeh, PICL_PROP_SPEED, PICL_PTYPE_INT, 1675 PICL_READ, sizeof (int), read_volprop, NULL, php); 1676 if (ret == PICL_SUCCESS) { 1677 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1678 row, VPT_NUMSENSOR); 1679 } 1680 break; 1681 1682 case PP_SENSOR_VALUE: 1683 ret = add_volatile_prop(nodeh, PICL_PROP_SENSOR_VALUE, 1684 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1685 NULL, php); 1686 if (ret == PICL_SUCCESS) { 1687 save_volprop(*php, OID_sunPlatNumericSensorCurrent, 1688 row, VPT_NUMSENSOR); 1689 } 1690 break; 1691 1692 case PP_CONDITION: 1693 ret = add_volatile_prop(nodeh, PICL_PROP_CONDITION, 1694 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1695 read_volprop, NULL, php); 1696 if (ret == PICL_SUCCESS) { 1697 save_volprop(*php, OID_sunPlatBinarySensorCurrent, 1698 row, VPT_BINSENSOR); 1699 } 1700 break; 1701 1702 case PP_EXPECTED: 1703 ret = add_volatile_prop(nodeh, PICL_PROP_EXPECTED, 1704 PICL_PTYPE_CHARSTRING, PICL_READ, MAX_TRUTHVAL_LEN, 1705 read_volprop, NULL, php); 1706 if (ret == PICL_SUCCESS) { 1707 save_volprop(*php, OID_sunPlatBinarySensorExpected, 1708 row, VPT_BINSENSOR); 1709 } 1710 break; 1711 1712 case PP_EXPONENT: 1713 ret = add_volatile_prop(nodeh, PICL_PROP_EXPONENT, 1714 PICL_PTYPE_INT, PICL_READ, sizeof (int), read_volprop, 1715 NULL, php); 1716 if (ret == PICL_SUCCESS) { 1717 save_volprop(*php, OID_sunPlatNumericSensorExponent, 1718 row, VPT_NUMSENSOR); 1719 } 1720 break; 1721 1722 case PP_REPLACEABLE: 1723 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackReplaceable, 1724 row, &val, snmp_syserr_p); 1725 CHECK_LINKRESET_VOID(snmp_syserr_p) 1726 if ((ret == 0) && (val == ST_TRUE)) 1727 (void) add_void_prop(nodeh, PICL_PROP_IS_REPLACEABLE); 1728 if (ret == -1) 1729 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1730 *snmp_syserr_p ? *snmp_syserr_p : ret, 1731 OID_sunPlatCircuitPackReplaceable, row); 1732 break; 1733 1734 case PP_HOTSWAPPABLE: 1735 ret = snmp_get_int(hdl, OID_sunPlatCircuitPackHotSwappable, 1736 row, &val, snmp_syserr_p); 1737 CHECK_LINKRESET_VOID(snmp_syserr_p) 1738 if ((ret == 0) && (val == ST_TRUE)) 1739 (void) add_void_prop(nodeh, PICL_PROP_IS_HOT_SWAPPABLE); 1740 if (ret == -1) 1741 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1742 *snmp_syserr_p ? *snmp_syserr_p : ret, 1743 OID_sunPlatCircuitPackHotSwappable, row); 1744 break; 1745 1746 case PP_IS_FRU: 1747 ret = snmp_get_int(hdl, OID_entPhysicalIsFRU, row, 1748 &val, snmp_syserr_p); 1749 CHECK_LINKRESET_VOID(snmp_syserr_p) 1750 if ((ret == 0) && (val == ST_TRUE)) 1751 (void) add_void_prop(nodeh, PICL_PROP_IS_FRU); 1752 if (ret == -1) 1753 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1754 *snmp_syserr_p ? *snmp_syserr_p : ret, 1755 OID_entPhysicalIsFRU, row); 1756 break; 1757 1758 case PP_HW_REVISION: 1759 ret = snmp_get_str(hdl, OID_entPhysicalHardwareRev, 1760 row, &hw_revision, snmp_syserr_p); 1761 CHECK_LINKRESET_VOID(snmp_syserr_p) 1762 if ((ret == 0) && hw_revision) { 1763 (void) add_string_prop(nodeh, 1764 PICL_PROP_HW_REVISION, hw_revision); 1765 free((void *) hw_revision); 1766 } 1767 if (ret == -1) 1768 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1769 *snmp_syserr_p ? *snmp_syserr_p : ret, 1770 OID_entPhysicalHardwareRev, row); 1771 break; 1772 1773 case PP_FW_REVISION: 1774 ret = snmp_get_str(hdl, OID_entPhysicalFirmwareRev, 1775 row, &fw_revision, snmp_syserr_p); 1776 CHECK_LINKRESET_VOID(snmp_syserr_p) 1777 if ((ret == 0) && fw_revision) { 1778 (void) add_string_prop(nodeh, 1779 PICL_PROP_FW_REVISION, fw_revision); 1780 free((void *) fw_revision); 1781 } 1782 if (ret == -1) 1783 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1784 *snmp_syserr_p ? *snmp_syserr_p : ret, 1785 OID_entPhysicalFirmwareRev, row); 1786 break; 1787 1788 case PP_MFG_NAME: 1789 ret = snmp_get_str(hdl, OID_entPhysicalMfgName, 1790 row, &mfg_name, snmp_syserr_p); 1791 CHECK_LINKRESET_VOID(snmp_syserr_p) 1792 if ((ret == 0) && mfg_name) { 1793 (void) add_string_prop(nodeh, 1794 PICL_PROP_MFG_NAME, mfg_name); 1795 free((void *) mfg_name); 1796 } 1797 if (ret == -1) 1798 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1799 *snmp_syserr_p ? *snmp_syserr_p : ret, 1800 OID_entPhysicalMfgName, row); 1801 break; 1802 1803 case PP_MODEL_NAME: 1804 ret = snmp_get_str(hdl, OID_entPhysicalModelName, 1805 row, &model_name, snmp_syserr_p); 1806 CHECK_LINKRESET_VOID(snmp_syserr_p) 1807 if ((ret == 0) && model_name) { 1808 (void) add_string_prop(nodeh, 1809 PICL_PROP_MODEL_NAME, model_name); 1810 free((void *) model_name); 1811 } 1812 if (ret == -1) 1813 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1814 *snmp_syserr_p ? *snmp_syserr_p : ret, 1815 OID_entPhysicalModelName, row); 1816 break; 1817 1818 case PP_DESCRIPTION: 1819 ret = snmp_get_str(hdl, OID_entPhysicalDescr, 1820 row, &phys_descr, snmp_syserr_p); 1821 CHECK_LINKRESET_VOID(snmp_syserr_p) 1822 if ((ret == 0) && phys_descr) { 1823 (void) add_string_prop(nodeh, 1824 PICL_PROP_PHYS_DESCRIPTION, phys_descr); 1825 free((void *) phys_descr); 1826 } 1827 if (ret == -1) 1828 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1829 *snmp_syserr_p ? *snmp_syserr_p : ret, 1830 OID_entPhysicalDescr, row); 1831 break; 1832 1833 case PP_LABEL: 1834 if (label && *label) 1835 (void) add_string_prop(nodeh, PICL_PROP_LABEL, label); 1836 break; 1837 1838 case PP_BASE_UNITS: 1839 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorBaseUnits, 1840 row, &val, snmp_syserr_p); 1841 CHECK_LINKRESET_VOID(snmp_syserr_p) 1842 if ((ret == 0) && (val > 0) && (val < n_baseunits)) { 1843 (void) add_string_prop(nodeh, 1844 PICL_PROP_BASE_UNITS, sensor_baseunits[val]); 1845 } 1846 if (ret == -1) 1847 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1848 *snmp_syserr_p ? *snmp_syserr_p : ret, 1849 OID_sunPlatNumericSensorBaseUnits, row); 1850 break; 1851 1852 case PP_RATE_UNITS: 1853 ret = snmp_get_int(hdl, OID_sunPlatNumericSensorRateUnits, 1854 row, &val, snmp_syserr_p); 1855 CHECK_LINKRESET_VOID(snmp_syserr_p) 1856 if ((ret == 0) && (val > 0) && (val < n_rateunits)) { 1857 (void) add_string_prop(nodeh, 1858 PICL_PROP_RATE_UNITS, sensor_rateunits[val]); 1859 } 1860 if (ret == -1) 1861 log_msg(LOG_ERR, SNMPP_CANT_FETCH_OBJECT_VAL, 1862 *snmp_syserr_p ? *snmp_syserr_p : ret, 1863 OID_sunPlatNumericSensorRateUnits, row); 1864 break; 1865 } 1866 } 1867 1868 /* 1869 * Initialize the SNMP library's cache refresh subsystem, then periodically 1870 * process refresh job to prevent cache entries from expiring. 1871 */ 1872 /*ARGSUSED*/ 1873 static void * 1874 cache_refresher(void *arg) 1875 { 1876 int jobs; 1877 int next_expiration; 1878 timestruc_t to; 1879 hrtime_t cycle_start, cycle_elapsed; 1880 1881 /* 1882 * Initialize refresh subsystem 1883 */ 1884 LOGPRINTF("Initializing SNMP refresh subsystem.\n"); 1885 if (snmp_refresh_init() < 0) { 1886 return ((void *)-1); 1887 } 1888 1889 (void) mutex_lock(&cache_refresh_lock); 1890 1891 1892 for (;;) { 1893 cycle_start = gethrtime(); 1894 1895 /* 1896 * Process jobs from the snmp cache refresh work queue until one 1897 * of the following conditions is true: 1898 * 1) we are told to exit, or 1899 * 2) we have processed at least as many jobs as recommended by 1900 * the library, and the next job expiration is at least 1901 * CACHE_REFRESH_MIN_WINDOW * seconds away. 1902 */ 1903 jobs = snmp_refresh_get_cycle_hint(CACHE_REFRESH_CYCLE); 1904 while ((cache_refresh_thr_exit == B_FALSE) && (jobs > 0)) { 1905 (void) snmp_refresh_process_job(); 1906 jobs--; 1907 } 1908 1909 next_expiration = snmp_refresh_get_next_expiration(); 1910 while ((cache_refresh_thr_exit == B_FALSE) && 1911 ((next_expiration >= 0) && 1912 (next_expiration < CACHE_REFRESH_MIN_WINDOW))) { 1913 (void) snmp_refresh_process_job(); 1914 next_expiration = snmp_refresh_get_next_expiration(); 1915 } 1916 1917 /* 1918 * As long as we haven't been told to exit, sleep for 1919 * CACHE_REFRESH_CYCLE seconds minus the amount of time that has 1920 * elapsed since this cycle started. If the elapsed time is 1921 * equal to or greater than 60 seconds, skip sleeping entirely. 1922 */ 1923 cycle_elapsed = (gethrtime() - cycle_start) / NANOSEC; 1924 if ((cache_refresh_thr_exit == B_FALSE) && 1925 (cycle_elapsed < CACHE_REFRESH_CYCLE)) { 1926 to.tv_sec = CACHE_REFRESH_CYCLE - cycle_elapsed; 1927 to.tv_nsec = 0; 1928 (void) cond_reltimedwait(&cache_refresh_cv, 1929 &cache_refresh_lock, &to); 1930 } 1931 1932 /* 1933 * If we have been told to exit, clean up and bail out. 1934 */ 1935 if (cache_refresh_thr_exit == B_TRUE) { 1936 snmp_refresh_fini(); 1937 (void) mutex_unlock(&cache_refresh_lock); 1938 LOGPRINTF("cache_refresher: time to exit\n"); 1939 return (NULL); 1940 } 1941 1942 } 1943 1944 /*NOTREACHED*/ 1945 return (NULL); 1946 } 1947 1948 /* 1949 * Check to see if the cache_refresher thread is running. If it is, signal it 1950 * to terminate and clean up associated data structures. 1951 */ 1952 void 1953 cache_refresher_fini(void) 1954 { 1955 /* if the thread isn't running, there is nothing to do */ 1956 if (cache_refresh_thr_exit == B_TRUE) 1957 return; 1958 1959 /* wake up the cache_refresher thread, tell it to exit */ 1960 (void) mutex_lock(&cache_refresh_lock); 1961 cache_refresh_thr_exit = B_TRUE; 1962 (void) cond_signal(&cache_refresh_cv); 1963 (void) mutex_unlock(&cache_refresh_lock); 1964 1965 /* reap the thread */ 1966 (void) thr_join(cache_refresh_thr_id, NULL, NULL); 1967 1968 /* finish cleanup... */ 1969 (void) cond_destroy(&cache_refresh_cv); 1970 (void) mutex_destroy(&cache_refresh_lock); 1971 } 1972 1973 /*VARARGS2*/ 1974 static void 1975 log_msg(int pri, const char *fmt, ...) 1976 { 1977 va_list ap; 1978 1979 va_start(ap, fmt); 1980 vsyslog(pri, fmt, ap); 1981 va_end(ap); 1982 } 1983 1984 #ifdef SNMPPLUGIN_DEBUG 1985 1986 static void 1987 snmpplugin_log_init(void) 1988 { 1989 (void) mutex_init(&snmpplugin_dbuf_lock, USYNC_THREAD, NULL); 1990 } 1991 1992 static void 1993 snmpplugin_log(const char *fmt, ...) 1994 { 1995 va_list ap; 1996 1997 (void) mutex_lock(&snmpplugin_dbuf_lock); 1998 1999 va_start(ap, fmt); 2000 (void) vsnprintf(snmpplugin_lbuf, SNMPPLUGIN_DMAX_LINE, fmt, ap); 2001 snmpplugin_log_append(); 2002 va_end(ap); 2003 2004 (void) mutex_unlock(&snmpplugin_dbuf_lock); 2005 } 2006 2007 static void 2008 snmpplugin_log_append(void) 2009 { 2010 int len; 2011 2012 len = strlen(snmpplugin_lbuf); 2013 2014 if ((snmpplugin_dbuf_curp + len) >= 2015 (snmpplugin_dbuf + snmpplugin_dbuf_sz)) { 2016 snmpplugin_dbuf_realloc(); 2017 if (snmpplugin_dbuf == NULL) { 2018 return; 2019 } 2020 } 2021 2022 (void) strcpy(snmpplugin_dbuf_curp, snmpplugin_lbuf); 2023 snmpplugin_dbuf_curp += len; 2024 } 2025 2026 static void 2027 snmpplugin_dbuf_realloc(void) 2028 { 2029 char *p; 2030 size_t offset = 0; 2031 size_t count; 2032 2033 count = snmpplugin_dbuf_sz + SNMPPLUGIN_DBLOCK_SZ; 2034 if ((p = (char *)calloc(count, 1)) == NULL) { 2035 snmpplugin_dbuf_overflow++; 2036 snmpplugin_dbuf_curp = snmpplugin_dbuf; 2037 return; 2038 } 2039 2040 if (snmpplugin_dbuf) { 2041 offset = snmpplugin_dbuf_curp - snmpplugin_dbuf; 2042 (void) memcpy(p, snmpplugin_dbuf, snmpplugin_dbuf_sz); 2043 free(snmpplugin_dbuf); 2044 } 2045 2046 snmpplugin_dbuf = p; 2047 snmpplugin_dbuf_sz += SNMPPLUGIN_DBLOCK_SZ; 2048 2049 snmpplugin_dbuf_curp = snmpplugin_dbuf + offset; 2050 } 2051 #endif 2052