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