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