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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This plugin creates PICL nodes and properties for objects handled through 29 * the enhanced LOMV system-processor interface. 30 * 31 * All the nodes which may be accessible through the system-processor are 32 * included below the service-processor node in the /platform tree. 33 * This plugin interrogates the system-processor to determine which of 34 * those nodes are actually available. Properties are added to such nodes and 35 * in the case of volatile properties like temperature, a call-back function 36 * is established for on-demand access to the current value. 37 * LEDs for which the system-processor provides write access are associated 38 * with read/write volatile properties. 39 * 40 * NOTE: 41 * Depends on PICL devtree plugin. 42 */ 43 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <unistd.h> 47 #include <fcntl.h> 48 #include <alloca.h> 49 #include <syslog.h> 50 #include <string.h> 51 #include <libintl.h> 52 #include <picl.h> 53 #include <picltree.h> 54 #include <libnvpair.h> 55 #include <errno.h> 56 #include <limits.h> 57 #include <ctype.h> 58 #include <sys/types.h> 59 #include <sys/stat.h> 60 #include <sys/obpdefs.h> 61 #include <sys/envmon.h> 62 #include <sys/systeminfo.h> 63 #include <dirent.h> 64 #include <time.h> 65 #include <picldefs.h> 66 #include <picld_pluginutil.h> 67 #include <libdevinfo.h> 68 #include "piclenvmon.h" 69 70 static void piclenvmon_register(void); 71 static void piclenvmon_init(void); 72 static void piclenvmon_fini(void); 73 static node_el_t *create_node_el(picl_nodehdl_t nodeh); 74 static void delete_node_el(node_el_t *pel); 75 static node_list_t *create_node_list(); 76 static void delete_node_list(node_list_t *pnl); 77 static void add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp); 78 static void get_node_list_by_class(picl_nodehdl_t nodeh, 79 const char *classname, node_list_t *listp); 80 static int get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p); 81 static void create_arrays(); 82 static int get_envmon_node(picl_nodehdl_t *envmoninfh); 83 static char *create_envmon_pathname(picl_nodehdl_t envmoninfh); 84 static int get_child_by_name(picl_nodehdl_t nodeh, const char *name, 85 picl_nodehdl_t *childh); 86 static int add_regular_prop(picl_nodehdl_t nodeh, const char *name, 87 int type, int access, int size, const void *valbuf, picl_prophdl_t *prophp); 88 static int add_volatile_prop(picl_nodehdl_t nodeh, const char *name, 89 int type, int access, int size, ptree_vol_rdfunc_t rdfunc, 90 ptree_vol_wrfunc_t wrfunc, picl_prophdl_t *prophp); 91 static int get_sensor_data(int envmon_fd, envmon_handle_t *id, int cmd, 92 envmon_thresholds_t *lows, envmon_thresholds_t *highs, int16_t *value); 93 static int get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd, 94 int16_t *condition); 95 static int get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd, 96 envmon_thresholds_t *lows, uint16_t *speed, char *units); 97 static int get_led_data(int envmon_fd, envmon_handle_t *id, int cmd, 98 int8_t *state, int8_t *colour); 99 static int get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd, 100 envmon_keysw_pos_t *key_state); 101 static void convert_node_name(char *ptr); 102 static void convert_label_name(char *ptr); 103 static int add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name, 104 int fru_type, int16_t value); 105 static int find_picl_handle(picl_prophdl_t proph); 106 static int lookup_led_status(int8_t state, const char **string); 107 static int lookup_key_posn(envmon_keysw_pos_t pos, const char **string); 108 static int get_config_file(char *filename); 109 static int read_vol_data(ptree_rarg_t *r_arg, void *buf); 110 static int write_led_data(ptree_warg_t *w_arg, const void *buf); 111 static int add_env_nodes(int envmon_fd, uint8_t fru_type, 112 picl_nodehdl_t envmonh); 113 static void fixstate(uint8_t state, const char *string, int *max_len); 114 static void fixkeyposn(envmon_keysw_pos_t keyposn, const char *string, 115 int *max_len); 116 static void setup_strings(); 117 static void free_vol_prop(picl_prophdl_t proph); 118 static void envmon_evhandler(const char *ename, const void *earg, 119 size_t size, void *cookie); 120 static int get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd, 121 envmon_chassis_t *chassis); 122 123 #pragma init(piclenvmon_register) 124 125 static picld_plugin_reg_t my_reg_info = { 126 PICLD_PLUGIN_VERSION_1, 127 PICLD_PLUGIN_NON_CRITICAL, 128 "SUNW_piclenvmon", 129 piclenvmon_init, 130 piclenvmon_fini 131 }; 132 133 static const char str_On[] = "on"; 134 static const char str_Off[] = "off"; 135 static const char str_Blinking[] = "blinking"; 136 static const char str_Flashing[] = "flashing"; 137 static const char str_SC[] = "SC"; 138 static char *envmon_device_name = NULL; 139 static envmon_sysinfo_t env_limits; 140 static handle_array_t handle_arr; 141 static struct { 142 int size; 143 char *str_colour; 144 } colour_lkup[1 + ENVMON_LED_CLR_RED]; 145 146 static struct { 147 int8_t state; 148 char *str_ledstate; 149 } ledstate_lkup[] = { 150 { ENVMON_LED_OFF }, 151 { ENVMON_LED_ON }, 152 { ENVMON_LED_BLINKING }, 153 { ENVMON_LED_FLASHING } 154 }; 155 156 static struct { 157 envmon_keysw_pos_t pos; 158 char *str_keyposn; 159 } keyposn_lkup[] = { 160 { ENVMON_KEYSW_POS_UNKNOWN }, 161 { ENVMON_KEYSW_POS_NORMAL }, 162 { ENVMON_KEYSW_POS_DIAG }, 163 { ENVMON_KEYSW_POS_LOCKED }, 164 { ENVMON_KEYSW_POS_OFF } 165 }; 166 167 /* 168 * fru-type to ioctl cmd lookup 169 */ 170 int fru_to_cmd[] = { 171 ENVMONIOCVOLTSENSOR, 172 ENVMONIOCVOLTIND, 173 ENVMONIOCAMPSENSOR, 174 ENVMONIOCAMPIND, 175 ENVMONIOCTEMPSENSOR, 176 ENVMONIOCTEMPIND, 177 ENVMONIOCFAN, 178 ENVMONIOCFANIND, 179 ENVMONIOCGETLED, 180 ENVMONIOCGETKEYSW, 181 ENVMONIOCCHASSISSERIALNUM 182 }; 183 184 /* 185 * fru-type to PICL CLASS 186 */ 187 const char *fru_to_class[] = { 188 PICL_CLASS_VOLTAGE_SENSOR, 189 PICL_CLASS_VOLTAGE_INDICATOR, 190 PICL_CLASS_CURRENT_SENSOR, 191 PICL_CLASS_CURRENT_INDICATOR, 192 PICL_CLASS_TEMPERATURE_SENSOR, 193 PICL_CLASS_TEMPERATURE_INDICATOR, 194 PICL_CLASS_FAN, 195 PICL_CLASS_FAN, 196 PICL_CLASS_LED, 197 PICL_CLASS_KEYSWITCH, 198 PICL_CLASS_CHASSIS_SERIAL_NUM 199 }; 200 201 /* 202 * fru-type to PICL PROPERTY for volatile data 203 */ 204 const char *fru_to_prop[] = { 205 PICL_PROP_VOLTAGE, 206 PICL_PROP_CONDITION, 207 PICL_PROP_CURRENT, 208 PICL_PROP_CONDITION, 209 PICL_PROP_TEMPERATURE, 210 PICL_PROP_CONDITION, 211 PICL_PROP_FAN_SPEED, 212 PICL_PROP_FAN_SPEED_UNIT, 213 PICL_PROP_STATE, 214 PICL_PROP_STATE, 215 PICL_PROP_SERIAL_NUMBER 216 }; 217 218 /* 219 * fru-type to PICL PTYPE 220 */ 221 int fru_to_ptype[] = { 222 PICL_PTYPE_FLOAT, 223 PICL_PTYPE_CHARSTRING, 224 PICL_PTYPE_FLOAT, 225 PICL_PTYPE_CHARSTRING, 226 PICL_PTYPE_INT, 227 PICL_PTYPE_CHARSTRING, 228 PICL_PTYPE_UNSIGNED_INT, 229 PICL_PTYPE_CHARSTRING, 230 PICL_PTYPE_CHARSTRING, 231 PICL_PTYPE_CHARSTRING, 232 PICL_PTYPE_CHARSTRING 233 }; 234 235 /* 236 * condition strings 237 */ 238 static char *cond_okay; 239 static char *cond_failed; 240 241 /* 242 * fru-type to size of volatile property 243 * the -1's are replaced by the max size of a condition string 244 */ 245 int fru_to_size[] = { 246 4, -1, 4, -1, 2, -1, 2, -1, -1, -1, -1 247 }; 248 249 static node_el_t * 250 create_node_el(picl_nodehdl_t nodeh) 251 { 252 node_el_t *ptr = malloc(sizeof (node_el_t)); 253 254 if (ptr != NULL) { 255 ptr->nodeh = nodeh; 256 ptr->next = NULL; 257 } 258 259 return (ptr); 260 } 261 262 static void 263 delete_node_el(node_el_t *pel) 264 { 265 free(pel); 266 } 267 268 static node_list_t * 269 create_node_list() 270 { 271 node_list_t *ptr = malloc(sizeof (node_list_t)); 272 273 if (ptr != NULL) { 274 ptr->head = NULL; 275 ptr->tail = NULL; 276 } 277 278 return (ptr); 279 } 280 281 static void 282 delete_node_list(node_list_t *pnl) 283 { 284 node_el_t *pel; 285 286 if (pnl == NULL) 287 return; 288 289 while ((pel = pnl->head) != NULL) { 290 pnl->head = pel->next; 291 delete_node_el(pel); 292 } 293 294 /* 295 * normally pnl->tail would be to NULL next, 296 * but as it is about to be freed, this step can be skipped. 297 */ 298 free(pnl); 299 } 300 301 /* 302 * Get a linking element and add handle to end of chain 303 */ 304 static void 305 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp) 306 { 307 node_el_t *pel = create_node_el(nodeh); 308 309 if (pel != NULL) { 310 if (listp->tail == NULL) 311 listp->head = pel; 312 else 313 listp->tail->next = pel; 314 315 listp->tail = pel; 316 } 317 } 318 319 /* 320 * Get a list of nodes of the specified classname under nodeh. 321 * Once a node of the specified class is found, its children are not 322 * searched. 323 */ 324 static void 325 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname, 326 node_list_t *listp) 327 { 328 int err; 329 char clname[PICL_CLASSNAMELEN_MAX+1]; 330 picl_nodehdl_t chdh; 331 332 /* 333 * go through the children 334 */ 335 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 336 sizeof (picl_nodehdl_t)); 337 338 while (err == PICL_SUCCESS) { 339 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME, 340 clname, strlen(classname) + 1); 341 342 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0)) 343 add_node_to_list(chdh, listp); 344 else 345 get_node_list_by_class(chdh, classname, listp); 346 347 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 348 sizeof (picl_nodehdl_t)); 349 } 350 } 351 352 static int 353 get_envmon_limits(int envmon_fd, envmon_sysinfo_t *limits_p) 354 { 355 return (ioctl(envmon_fd, ENVMONIOCSYSINFO, limits_p)); 356 } 357 358 static int 359 re_create_arrays(int envmon_fd) 360 { 361 envmon_sysinfo_t new_limits; 362 int res; 363 int maxnum; 364 uchar_t *fru_types; 365 envmon_handle_t *envhandles; 366 picl_prophdl_t *piclprhdls; 367 368 res = get_envmon_limits(envmon_fd, &new_limits); 369 if (res != 0) 370 return (res); 371 372 maxnum = new_limits.maxVoltSens + new_limits.maxVoltInd + 373 new_limits.maxAmpSens + new_limits.maxAmpInd + 374 new_limits.maxTempSens + new_limits.maxTempInd + 375 new_limits.maxFanSens + new_limits.maxFanInd + 376 new_limits.maxLED + N_KEY_SWITCHES; 377 378 if (maxnum != handle_arr.maxnum) { 379 /* 380 * space requirements have changed 381 */ 382 fru_types = calloc(maxnum, sizeof (uchar_t)); 383 envhandles = calloc(maxnum, sizeof (envmon_handle_t)); 384 piclprhdls = calloc(maxnum, sizeof (picl_prophdl_t)); 385 if ((fru_types == NULL) || (envhandles == NULL) || 386 (piclprhdls == NULL)) { 387 free(fru_types); 388 free(envhandles); 389 free(piclprhdls); 390 return (-1); 391 } 392 free(handle_arr.fru_types); 393 handle_arr.fru_types = fru_types; 394 free(handle_arr.envhandles); 395 handle_arr.envhandles = envhandles; 396 free(handle_arr.piclprhdls); 397 handle_arr.piclprhdls = piclprhdls; 398 } else { 399 (void) memset(handle_arr.fru_types, 0, 400 maxnum * sizeof (uchar_t)); 401 (void) memset(handle_arr.envhandles, 0, 402 maxnum * sizeof (envmon_handle_t)); 403 (void) memset(handle_arr.piclprhdls, 0, 404 maxnum * sizeof (picl_prophdl_t)); 405 } 406 407 handle_arr.num = 0; 408 handle_arr.maxnum = maxnum; 409 env_limits = new_limits; 410 return (0); 411 } 412 413 static void 414 create_arrays() 415 { 416 int maxnum = env_limits.maxVoltSens + env_limits.maxVoltInd + 417 env_limits.maxAmpSens + env_limits.maxAmpInd + 418 env_limits.maxTempSens + env_limits.maxTempInd + 419 env_limits.maxFanSens + env_limits.maxFanInd + 420 env_limits.maxLED + N_KEY_SWITCHES; 421 handle_arr.maxnum = maxnum; 422 handle_arr.num = 0; 423 handle_arr.fru_types = calloc(maxnum, sizeof (uchar_t)); 424 handle_arr.envhandles = calloc(maxnum, sizeof (envmon_handle_t)); 425 handle_arr.piclprhdls = calloc(maxnum, sizeof (picl_prophdl_t)); 426 } 427 428 static int 429 get_envmon_node(picl_nodehdl_t *envmoninfh) 430 { 431 int err = PICL_SUCCESS; 432 node_list_t *listp; 433 434 listp = create_node_list(); 435 436 if ((err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, 437 envmoninfh)) != PICL_SUCCESS) { 438 syslog(LOG_ERR, EM_MISSING_NODE, 439 PICL_NODE_ROOT PICL_NODE_PLATFORM); 440 return (err); /* no /platform ! */ 441 } 442 443 get_node_list_by_class(*envmoninfh, PICL_CLASS_SERVICE_PROCESSOR, 444 listp); 445 446 if (listp->head == NULL) { 447 *envmoninfh = 0; 448 syslog(LOG_ERR, EM_MISSING_NODE, PICL_CLASS_SERVICE_PROCESSOR); 449 err = PICL_NODENOTFOUND; 450 } else { 451 *envmoninfh = listp->head->nodeh; 452 } 453 454 delete_node_list(listp); 455 return (err); 456 } 457 458 static char * 459 create_envmon_pathname(picl_nodehdl_t envmoninfh) 460 { 461 char *ptr; 462 char namebuf[PATH_MAX]; 463 size_t len; 464 DIR *dirp; 465 struct dirent *dp; 466 struct stat statbuf; 467 468 /* prefix devfs-path name with /devices */ 469 (void) strlcpy(namebuf, "/devices", PATH_MAX); 470 471 /* 472 * append devfs-path property 473 */ 474 len = strlen(namebuf); 475 if (ptree_get_propval_by_name(envmoninfh, PICL_PROP_DEVFS_PATH, 476 namebuf + len, sizeof (namebuf) - len) != PICL_SUCCESS) { 477 syslog(LOG_ERR, EM_SC_NODE_INCOMPLETE); 478 return (NULL); 479 } 480 481 /* locate final component of name */ 482 ptr = strrchr(namebuf, '/'); 483 if (ptr == NULL) 484 return (NULL); 485 *ptr = '\0'; /* terminate at end of directory path */ 486 len = strlen(ptr + 1); /* length of terminal name */ 487 dirp = opendir(namebuf); 488 if (dirp == NULL) { 489 syslog(LOG_ERR, EM_SC_NODE_MISSING); 490 return (NULL); 491 } 492 *ptr++ = '/'; /* restore '/' and advance to final name */ 493 494 while ((dp = readdir(dirp)) != NULL) { 495 /* 496 * look for a name which starts with the string at *ptr 497 */ 498 if (strlen(dp->d_name) < len) 499 continue; /* skip short names */ 500 if (strncmp(dp->d_name, ptr, len) == 0) { 501 /* 502 * Got a match, restore full pathname and stat the 503 * entry. Reject if not a char device 504 */ 505 (void) strlcpy(ptr, dp->d_name, 506 sizeof (namebuf) - (ptr - namebuf)); 507 if (stat(namebuf, &statbuf) < 0) 508 continue; /* reject if can't stat it */ 509 if (!S_ISCHR(statbuf.st_mode)) 510 continue; /* not a character device */ 511 /* 512 * go with this entry 513 */ 514 (void) closedir(dirp); 515 return (strdup(namebuf)); 516 } 517 } 518 syslog(LOG_ERR, EM_SC_NODE_MISSING); 519 (void) closedir(dirp); 520 return (NULL); 521 } 522 523 /* 524 * look for named node as child of supplied handle 525 */ 526 static int 527 get_child_by_name(picl_nodehdl_t nodeh, const char *name, 528 picl_nodehdl_t *childh) 529 { 530 int err; 531 char node_name[ENVMON_MAXNAMELEN]; 532 533 if (strlen(name) >= ENVMON_MAXNAMELEN) 534 return (PICL_NODENOTFOUND); 535 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, childh, 536 sizeof (*childh)); 537 while (err == PICL_SUCCESS) { 538 err = ptree_get_propval_by_name(*childh, PICL_PROP_NAME, 539 node_name, sizeof (node_name)); 540 if ((err == PICL_SUCCESS) && 541 (strncmp(name, node_name, ENVMON_MAXNAMELEN) == 0)) 542 return (PICL_SUCCESS); 543 err = ptree_get_propval_by_name(*childh, PICL_PROP_PEER, 544 childh, sizeof (*childh)); 545 } 546 return (err); 547 } 548 549 /* 550 * Create and add the specified regular property 551 */ 552 static int 553 add_regular_prop(picl_nodehdl_t nodeh, const char *name, int type, int access, 554 int size, const void *valbuf, picl_prophdl_t *prophp) 555 { 556 int err; 557 ptree_propinfo_t propinfo; 558 picl_prophdl_t proph; 559 560 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 561 type, access, size, (char *)name, NULL, NULL); 562 if (err != PICL_SUCCESS) 563 return (err); 564 565 err = ptree_create_and_add_prop(nodeh, &propinfo, (void *)valbuf, 566 &proph); 567 if (err == PICL_SUCCESS && prophp) 568 *prophp = proph; 569 return (err); 570 } 571 572 573 /* 574 * Create and add the specified volatile property 575 */ 576 static int 577 add_volatile_prop(picl_nodehdl_t nodeh, const char *name, int type, int access, 578 int size, ptree_vol_rdfunc_t rdfunc, ptree_vol_wrfunc_t wrfunc, 579 picl_prophdl_t *prophp) 580 { 581 int err; 582 ptree_propinfo_t propinfo; 583 picl_prophdl_t proph; 584 585 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 586 type, (access|PICL_VOLATILE), size, (char *)name, rdfunc, wrfunc); 587 if (err != PICL_SUCCESS) 588 return (err); 589 590 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph); 591 if (err == PICL_SUCCESS && prophp) 592 *prophp = proph; 593 return (err); 594 } 595 596 /* 597 * There are 5 different structures used for reading environmental data 598 * from the service-processor. A different function is used for each one. 599 * Some functions cover several ioctls, so the desired ioctl is part of 600 * the interface. In each case the id parameter is read/write, the 601 * returned value being the next id for this fru type. 602 */ 603 604 /* 605 * Function to read sensor data. 606 */ 607 static int 608 get_sensor_data(int envmon_fd, envmon_handle_t *id, int cmd, 609 envmon_thresholds_t *lows, envmon_thresholds_t *highs, int16_t *value) 610 { 611 int res; 612 envmon_sensor_t data; 613 614 (void) memset(&data, 0, sizeof (data)); 615 data.id = *id; 616 res = ioctl(envmon_fd, cmd, &data); 617 if (res < 0) { 618 return (PICL_NOTREADABLE); 619 } 620 621 *id = data.next_id; 622 623 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0) 624 return (PICL_INVALIDHANDLE); 625 626 /* 627 * it is assumed that threshold data will be available, 628 * even though the current sensor value may be inaccessible 629 */ 630 if (lows != NULL) 631 *lows = data.lowthresholds; 632 if (highs != NULL) 633 *highs = data.highthresholds; 634 635 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) { 636 if (value != NULL) 637 *value = ENVMON_VAL_UNAVAILABLE; 638 return (PICL_PROPVALUNAVAILABLE); 639 } 640 if (value != NULL) 641 *value = data.value; 642 return (PICL_SUCCESS); 643 } 644 645 /* 646 * Function to read indicator data. 647 */ 648 static int 649 get_indicator_data(int envmon_fd, envmon_handle_t *id, int cmd, 650 int16_t *condition) 651 { 652 int res; 653 envmon_indicator_t data; 654 655 data.id = *id; 656 res = ioctl(envmon_fd, cmd, &data); 657 if (res < 0) 658 return (PICL_NOTREADABLE); 659 *id = data.next_id; 660 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0) 661 return (PICL_INVALIDHANDLE); 662 if (condition != NULL) 663 *condition = data.condition; 664 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) { 665 return (PICL_PROPVALUNAVAILABLE); 666 } 667 return (PICL_SUCCESS); 668 } 669 670 /* 671 * Function to read fan data. 672 */ 673 static int 674 get_fan_data(int envmon_fd, envmon_handle_t *id, int cmd, 675 envmon_thresholds_t *lows, uint16_t *speed, char *units) 676 { 677 int res; 678 envmon_fan_t data; 679 680 data.id = *id; 681 res = ioctl(envmon_fd, cmd, &data); 682 if (res < 0) 683 return (PICL_NOTREADABLE); 684 *id = data.next_id; 685 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0) 686 return (PICL_INVALIDHANDLE); 687 if (lows != NULL) 688 *lows = data.lowthresholds; 689 if (units != NULL) 690 (void) strlcpy(units, data.units, sizeof (data.units)); 691 692 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) { 693 if (speed != NULL) 694 *speed = ENVMON_VAL_UNAVAILABLE; 695 return (PICL_PROPVALUNAVAILABLE); 696 } 697 if (speed != NULL) 698 *speed = data.speed; 699 return (PICL_SUCCESS); 700 } 701 702 /* 703 * Function to read LED data. 704 */ 705 static int 706 get_led_data(int envmon_fd, envmon_handle_t *id, int cmd, 707 int8_t *state, int8_t *colour) 708 { 709 int res; 710 envmon_led_info_t data; 711 712 data.id = *id; 713 res = ioctl(envmon_fd, cmd, &data); 714 if (res < 0) 715 return (PICL_NOTREADABLE); 716 *id = data.next_id; 717 if ((data.sensor_status & ENVMON_NOT_PRESENT) != 0) 718 return (PICL_INVALIDHANDLE); 719 if (colour != NULL) 720 *colour = data.led_color; 721 if ((data.sensor_status & ENVMON_INACCESSIBLE) != 0) { 722 return (PICL_PROPVALUNAVAILABLE); 723 } 724 if (state != NULL) 725 *state = data.led_state; 726 return (PICL_SUCCESS); 727 } 728 729 /* 730 * Function to read key-switch position 731 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails) 732 */ 733 static int 734 get_keyswitch_data(int envmon_fd, envmon_handle_t *id, int cmd, 735 envmon_keysw_pos_t *key_state) 736 { 737 int res; 738 739 if (id->name[0] == '\0') { 740 (void) strlcpy(id->name, KEYSWITCH_NAME, sizeof (id->name)); 741 return (PICL_INVALIDHANDLE); 742 } else if (strncmp(id->name, KEYSWITCH_NAME, sizeof (id->name)) != 0) { 743 id->name[0] = '\0'; 744 return (PICL_INVALIDHANDLE); 745 } else { 746 res = ioctl(envmon_fd, cmd, key_state); 747 id->name[0] = '\0'; 748 749 if (res < 0) 750 return (PICL_INVALIDHANDLE); 751 return (PICL_SUCCESS); 752 } 753 } 754 755 /* 756 * Function to read the chassis serial number 757 * Returns PICL_INVALIDHANDLE if ioctl not supported (or fails) 758 */ 759 static int 760 get_serial_num(int envmon_fd, envmon_handle_t *id, int cmd, 761 envmon_chassis_t *chassis) 762 { 763 int res; 764 765 if (id->name[0] == '\0') { 766 (void) strlcpy(id->name, CHASSIS_SERIAL_NUMBER, 767 sizeof (id->name)); 768 return (PICL_INVALIDHANDLE); 769 } else if (strncmp(id->name, CHASSIS_SERIAL_NUMBER, sizeof (id->name)) 770 != 0) { 771 id->name[0] = '\0'; 772 return (PICL_INVALIDHANDLE); 773 } else { 774 res = ioctl(envmon_fd, cmd, chassis); 775 id->name[0] = '\0'; 776 777 if (res < 0) 778 return (PICL_INVALIDHANDLE); 779 return (PICL_SUCCESS); 780 } 781 } 782 783 /* 784 * change to lower case and convert any spaces into hyphens, 785 * and any dots or colons symbols into underscores 786 */ 787 static void 788 convert_node_name(char *ptr) 789 { 790 char ch; 791 792 for (ch = *ptr; ch != '\0'; ch = *++ptr) { 793 if (isupper(ch)) { 794 *ptr = tolower(ch); 795 } else if (isspace(ch)) { 796 *ptr = '-'; 797 } else if ((ch == '.') || (ch == ':')) { 798 *ptr = '_'; 799 } 800 } 801 } 802 803 /* 804 * strip to the last '.' separator and keep the rest 805 * change ':' to '/' within the last component 806 */ 807 static void 808 convert_label_name(char *name) 809 { 810 const char *cptr; 811 char ch; 812 813 cptr = strrchr(name, '.'); 814 815 if (cptr == NULL) 816 cptr = name; 817 else 818 cptr++; /* skip the '.' */ 819 820 do { 821 ch = *cptr++; 822 823 if (ch == ':') 824 ch = '/'; 825 826 *name++ = ch; 827 } while (ch != '\0'); 828 } 829 830 /* 831 * add a value property 832 */ 833 static int 834 add_value_prop(picl_nodehdl_t node_hdl, const char *prop_name, int fru_type, 835 int16_t value) 836 { 837 int err; 838 union { 839 float u_f; 840 int16_t u_i16; 841 } val_buf; 842 843 if (fru_to_ptype[fru_type] == PICL_PTYPE_FLOAT) 844 val_buf.u_f = (float)((float)value / (float)1000.0); 845 else 846 val_buf.u_i16 = value; 847 848 err = add_regular_prop(node_hdl, prop_name, fru_to_ptype[fru_type], 849 PICL_READ, fru_to_size[fru_type], &val_buf, NULL); 850 return (err); 851 } 852 853 static int 854 find_picl_handle(picl_prophdl_t proph) 855 { 856 int index; 857 858 for (index = 0; index < handle_arr.num; index++) { 859 if (handle_arr.piclprhdls[index] == proph) 860 return (index); 861 } 862 863 return (-1); 864 } 865 866 /* 867 * look up function to convert led status into string 868 */ 869 static int 870 lookup_led_status(int8_t state, const char **string) 871 { 872 int i; 873 int lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]); 874 875 for (i = 0; i < lim; i++) { 876 if (ledstate_lkup[i].state == state) { 877 *string = ledstate_lkup[i].str_ledstate; 878 return (PICL_SUCCESS); 879 } 880 } 881 882 *string = ""; 883 return (PICL_PROPVALUNAVAILABLE); 884 } 885 886 static int 887 lookup_key_posn(envmon_keysw_pos_t pos, const char **string) 888 { 889 int i; 890 int lim = sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0]); 891 892 for (i = 0; i < lim; i++) { 893 if (keyposn_lkup[i].pos == pos) { 894 *string = keyposn_lkup[i].str_keyposn; 895 return (PICL_SUCCESS); 896 } 897 } 898 899 *string = ""; 900 return (PICL_PROPVALUNAVAILABLE); 901 } 902 903 /* 904 * function to read volatile data associated with a PICL property handle 905 */ 906 static int 907 read_vol_data(ptree_rarg_t *r_arg, void *buf) 908 { 909 picl_prophdl_t proph; 910 int index; 911 uint8_t fru_type; 912 envmon_handle_t id; 913 int16_t sensor_data; 914 int8_t led_state; 915 envmon_keysw_pos_t key_posn; 916 envmon_chassis_t chassis; 917 float float_data; 918 int cmd; 919 int err; 920 int envmon_fd; 921 const char *cptr; 922 923 proph = r_arg->proph; 924 index = find_picl_handle(proph); 925 if (index < 0) 926 return (PICL_INVALIDHANDLE); 927 fru_type = handle_arr.fru_types[index]; 928 id = handle_arr.envhandles[index]; 929 cmd = fru_to_cmd[fru_type]; 930 envmon_fd = open(envmon_device_name, O_RDONLY); 931 if (envmon_fd < 0) 932 return (PICL_NOTREADABLE); 933 934 /* 935 * read environmental data according to type 936 */ 937 switch (fru_type) { 938 case ENVMON_VOLT_SENS: 939 /*FALLTHROUGH*/ 940 case ENVMON_AMP_SENS: 941 /*FALLTHROUGH*/ 942 case ENVMON_TEMP_SENS: 943 err = get_sensor_data(envmon_fd, &id, cmd, NULL, NULL, 944 &sensor_data); 945 break; 946 case ENVMON_VOLT_IND: 947 /*FALLTHROUGH*/ 948 case ENVMON_AMP_IND: 949 /*FALLTHROUGH*/ 950 case ENVMON_TEMP_IND: 951 /*FALLTHROUGH*/ 952 case ENVMON_FAN_IND: 953 err = get_indicator_data(envmon_fd, &id, cmd, &sensor_data); 954 break; 955 case ENVMON_FAN_SENS: 956 err = get_fan_data(envmon_fd, &id, cmd, NULL, 957 (uint16_t *)&sensor_data, NULL); 958 break; 959 case ENVMON_LED_IND: 960 err = get_led_data(envmon_fd, &id, cmd, &led_state, NULL); 961 break; 962 case ENVMON_KEY_SWITCH: 963 err = get_keyswitch_data(envmon_fd, &id, cmd, &key_posn); 964 break; 965 case ENVMON_CHASSIS: 966 err = get_serial_num(envmon_fd, &id, cmd, &chassis); 967 break; 968 default: 969 err = PICL_FAILURE; 970 break; 971 } 972 973 (void) close(envmon_fd); 974 if (err != PICL_SUCCESS) { 975 /* 976 * PICL_INVALIDHANDLE is used internally, but it upsets 977 * prtpicl; change it to PICL_PROPVALUNAVAILABLE 978 */ 979 if (err == PICL_INVALIDHANDLE) 980 err = PICL_PROPVALUNAVAILABLE; 981 return (err); 982 } 983 984 /* 985 * convert data and copy out 986 */ 987 switch (fru_type) { 988 case ENVMON_VOLT_SENS: 989 /*FALLTHROUGH*/ 990 case ENVMON_AMP_SENS: 991 float_data = (float)((float)sensor_data / (float)1000.0); 992 (void) memcpy(buf, &float_data, sizeof (float_data)); 993 break; 994 995 case ENVMON_TEMP_SENS: 996 /*FALLTHROUGH*/ 997 case ENVMON_FAN_SENS: 998 (void) memcpy(buf, &sensor_data, sizeof (sensor_data)); 999 break; 1000 1001 case ENVMON_VOLT_IND: 1002 /*FALLTHROUGH*/ 1003 case ENVMON_AMP_IND: 1004 /*FALLTHROUGH*/ 1005 case ENVMON_TEMP_IND: 1006 /*FALLTHROUGH*/ 1007 case ENVMON_FAN_IND: 1008 (void) strlcpy(buf, sensor_data == 0 ? cond_okay : cond_failed, 1009 fru_to_size[fru_type]); 1010 break; 1011 1012 case ENVMON_LED_IND: 1013 err = lookup_led_status(led_state, &cptr); 1014 if (err != PICL_SUCCESS) 1015 return (err); 1016 (void) strlcpy(buf, cptr, fru_to_size[fru_type]); 1017 break; 1018 1019 case ENVMON_KEY_SWITCH: 1020 err = lookup_key_posn(key_posn, &cptr); 1021 if (err != PICL_SUCCESS) 1022 return (err); 1023 (void) strlcpy(buf, cptr, fru_to_size[fru_type]); 1024 break; 1025 case ENVMON_CHASSIS: 1026 (void) memcpy(buf, chassis.serial_number, 1027 sizeof (chassis.serial_number)); 1028 break; 1029 1030 default: 1031 return (PICL_FAILURE); 1032 } 1033 1034 return (PICL_SUCCESS); 1035 } 1036 1037 static int 1038 write_led_data(ptree_warg_t *w_arg, const void *buf) 1039 { 1040 picl_prophdl_t proph; 1041 int index; 1042 uint8_t fru_type; 1043 int err; 1044 int envmon_fd; 1045 envmon_led_ctl_t led_ctl; 1046 1047 proph = w_arg->proph; 1048 index = find_picl_handle(proph); 1049 if (index < 0) 1050 return (PICL_INVALIDHANDLE); 1051 fru_type = handle_arr.fru_types[index]; 1052 if (fru_type != ENVMON_LED_IND) 1053 return (PICL_INVALIDARG); 1054 if (w_arg->cred.dc_euid != SUPER_USER) 1055 return (PICL_PERMDENIED); 1056 1057 /* see if the requested state is recognized */ 1058 if (strcasecmp(str_Off, buf) == 0) 1059 led_ctl.led_state = ENVMON_LED_OFF; 1060 else if (strcasecmp(str_On, buf) == 0) 1061 led_ctl.led_state = ENVMON_LED_ON; 1062 else if (strcasecmp(str_Blinking, buf) == 0) 1063 led_ctl.led_state = ENVMON_LED_BLINKING; 1064 else if (strcasecmp(str_Flashing, buf) == 0) 1065 led_ctl.led_state = ENVMON_LED_FLASHING; 1066 else 1067 return (PICL_INVALIDARG); 1068 1069 envmon_fd = open(envmon_device_name, O_RDWR); 1070 if (envmon_fd < 0) 1071 return (PICL_FAILURE); 1072 led_ctl.id = handle_arr.envhandles[index]; 1073 err = ioctl(envmon_fd, ENVMONIOCSETLED, &led_ctl); 1074 (void) close(envmon_fd); 1075 if (err < 0) 1076 return (PICL_FAILURE); 1077 return (PICL_SUCCESS); 1078 } 1079 1080 /* 1081 * if colour information is not supplied by the service processor, 1082 * try to determine led colour from the handle name. 1083 */ 1084 static void 1085 fix_led_colour(int8_t *colour_p, const char *id) 1086 { 1087 const char *cptr = strrchr(id, '.'); 1088 1089 if ((*colour_p < ENVMON_LED_CLR_NONE) || 1090 (*colour_p > ENVMON_LED_CLR_RED)) 1091 syslog(LOG_ERR, EM_INVALID_COLOR, *colour_p, id); 1092 if (cptr == NULL) { 1093 *colour_p = ENVMON_LED_CLR_NONE; 1094 return; 1095 } 1096 1097 cptr++; /* step over '.' */ 1098 1099 if (strcmp(cptr, LED_ACT) == 0) 1100 *colour_p = ENVMON_LED_CLR_GREEN; 1101 else if (strcmp(cptr, LED_SERVICE) == 0) 1102 *colour_p = ENVMON_LED_CLR_AMBER; 1103 else if (strcmp(cptr, LED_LOCATE) == 0) 1104 *colour_p = ENVMON_LED_CLR_WHITE; 1105 else if (strcmp(cptr, LED_OK2RM) == 0) 1106 *colour_p = ENVMON_LED_CLR_BLUE; 1107 else 1108 *colour_p = ENVMON_LED_CLR_NONE; 1109 } 1110 1111 /* 1112 * Add nodes for environmental devices of type fru_type 1113 * below the supplied node. 1114 */ 1115 static int 1116 add_env_nodes(int envmon_fd, uint8_t fru_type, picl_nodehdl_t envmonh) 1117 { 1118 envmon_handle_t id; 1119 envmon_thresholds_t lows; 1120 envmon_thresholds_t highs; 1121 char units[ENVMON_MAXNAMELEN]; 1122 char platform_tree_name[ENVMON_MAXNAMELEN]; 1123 char label_name[ENVMON_MAXNAMELEN]; 1124 int16_t sensor_data; 1125 int8_t led_state; 1126 int8_t colour; 1127 envmon_keysw_pos_t key_state; 1128 envmon_chassis_t chassis_num; 1129 int cmd; 1130 int err; 1131 int index = handle_arr.num; 1132 picl_nodehdl_t node_hdl; 1133 1134 /* 1135 * catch table is full at start 1136 */ 1137 if (index >= handle_arr.maxnum) 1138 return (PICL_FAILURE); 1139 1140 cmd = fru_to_cmd[fru_type]; 1141 id.name[0] = '\0'; 1142 1143 do { 1144 lows.warning = lows.shutdown = lows.poweroff = 1145 ENVMON_VAL_UNAVAILABLE; 1146 highs.warning = highs.shutdown = highs.poweroff = 1147 ENVMON_VAL_UNAVAILABLE; 1148 handle_arr.fru_types[index] = fru_type; 1149 /* must store id before reading data as it is then updated */ 1150 handle_arr.envhandles[index] = id; 1151 /* 1152 * read environmental data according to type 1153 */ 1154 switch (fru_type) { 1155 case ENVMON_VOLT_SENS: 1156 /*FALLTHROUGH*/ 1157 case ENVMON_AMP_SENS: 1158 /*FALLTHROUGH*/ 1159 case ENVMON_TEMP_SENS: 1160 err = get_sensor_data(envmon_fd, &id, cmd, &lows, 1161 &highs, &sensor_data); 1162 break; 1163 case ENVMON_VOLT_IND: 1164 /*FALLTHROUGH*/ 1165 case ENVMON_AMP_IND: 1166 /*FALLTHROUGH*/ 1167 case ENVMON_TEMP_IND: 1168 /*FALLTHROUGH*/ 1169 case ENVMON_FAN_IND: 1170 err = get_indicator_data(envmon_fd, &id, cmd, 1171 &sensor_data); 1172 break; 1173 case ENVMON_FAN_SENS: 1174 err = get_fan_data(envmon_fd, &id, cmd, &lows, 1175 (uint16_t *)&sensor_data, units); 1176 break; 1177 case ENVMON_LED_IND: 1178 err = get_led_data(envmon_fd, &id, cmd, &led_state, 1179 &colour); 1180 break; 1181 case ENVMON_KEY_SWITCH: 1182 err = get_keyswitch_data(envmon_fd, &id, cmd, 1183 &key_state); 1184 break; 1185 case ENVMON_CHASSIS: 1186 err = get_serial_num(envmon_fd, &id, cmd, 1187 &chassis_num); 1188 break; 1189 default: 1190 return (PICL_FAILURE); 1191 } 1192 1193 if (err == PICL_INVALIDHANDLE) 1194 continue; 1195 if ((err != PICL_SUCCESS) && (err != PICL_PROPVALUNAVAILABLE)) { 1196 syslog(LOG_ERR, EM_NODE_ACCESS, id, fru_type, err); 1197 continue; 1198 } 1199 1200 /* 1201 * successfully read environmental data, add to PICL 1202 */ 1203 (void) strlcpy(platform_tree_name, 1204 handle_arr.envhandles[index].name, 1205 sizeof (platform_tree_name)); 1206 1207 (void) strlcpy(label_name, platform_tree_name, 1208 ENVMON_MAXNAMELEN); 1209 convert_label_name(label_name); 1210 convert_node_name(platform_tree_name); 1211 /* 1212 * does this node already exist? 1213 */ 1214 err = get_child_by_name(envmonh, platform_tree_name, &node_hdl); 1215 if (err == PICL_SUCCESS) { 1216 /* 1217 * skip over existing node 1218 */ 1219 continue; 1220 } 1221 err = ptree_create_node(platform_tree_name, 1222 fru_to_class[fru_type], &node_hdl); 1223 if (err != PICL_SUCCESS) { 1224 break; 1225 } 1226 err = add_volatile_prop(node_hdl, fru_to_prop[fru_type], 1227 fru_to_ptype[fru_type], 1228 PICL_READ | (fru_type == ENVMON_LED_IND ? PICL_WRITE : 0), 1229 fru_to_size[fru_type], read_vol_data, 1230 fru_type == ENVMON_LED_IND ? write_led_data : NULL, 1231 &handle_arr.piclprhdls[index]); 1232 if (err != PICL_SUCCESS) { 1233 break; 1234 } 1235 1236 /* 1237 * if any thresholds are defined add a property 1238 */ 1239 if (lows.warning != ENVMON_VAL_UNAVAILABLE) { 1240 err = add_value_prop(node_hdl, PICL_PROP_LOW_WARNING, 1241 fru_type, lows.warning); 1242 if (err != PICL_SUCCESS) { 1243 break; 1244 } 1245 } 1246 if (lows.shutdown != ENVMON_VAL_UNAVAILABLE) { 1247 err = add_value_prop(node_hdl, PICL_PROP_LOW_SHUTDOWN, 1248 fru_type, lows.shutdown); 1249 if (err != PICL_SUCCESS) { 1250 break; 1251 } 1252 } 1253 if (lows.poweroff != ENVMON_VAL_UNAVAILABLE) { 1254 err = add_value_prop(node_hdl, PICL_PROP_LOW_POWER_OFF, 1255 fru_type, lows.poweroff); 1256 if (err != PICL_SUCCESS) { 1257 break; 1258 } 1259 } 1260 if (highs.warning != ENVMON_VAL_UNAVAILABLE) { 1261 err = add_value_prop(node_hdl, PICL_PROP_HIGH_WARNING, 1262 fru_type, highs.warning); 1263 if (err != PICL_SUCCESS) { 1264 break; 1265 } 1266 } 1267 if (highs.shutdown != ENVMON_VAL_UNAVAILABLE) { 1268 err = add_value_prop(node_hdl, PICL_PROP_HIGH_SHUTDOWN, 1269 fru_type, highs.shutdown); 1270 if (err != PICL_SUCCESS) { 1271 break; 1272 } 1273 } 1274 if (highs.poweroff != ENVMON_VAL_UNAVAILABLE) { 1275 err = add_value_prop(node_hdl, PICL_PROP_HIGH_POWER_OFF, 1276 fru_type, highs.poweroff); 1277 if (err != PICL_SUCCESS) { 1278 break; 1279 } 1280 } 1281 1282 /* 1283 * if device is a fan sensor, add a speedunit property 1284 */ 1285 if (fru_type == ENVMON_FAN_SENS) { 1286 err = add_regular_prop(node_hdl, 1287 PICL_PROP_FAN_SPEED_UNIT, PICL_PTYPE_CHARSTRING, 1288 PICL_READ, 1 + strlen(units), units, NULL); 1289 if (err != PICL_SUCCESS) { 1290 break; 1291 } 1292 } 1293 /* 1294 * If device is a LED indicator and returns a colour, 1295 * add a colour property. 1296 */ 1297 if (fru_type == ENVMON_LED_IND) { 1298 if (colour < 0 || colour == ENVMON_LED_CLR_ANY || 1299 colour > ENVMON_LED_CLR_RED) 1300 fix_led_colour(&colour, 1301 handle_arr.envhandles[index].name); 1302 if (colour != ENVMON_LED_CLR_NONE) { 1303 err = add_regular_prop(node_hdl, 1304 PICL_PROP_COLOR, PICL_PTYPE_CHARSTRING, 1305 PICL_READ, colour_lkup[colour].size, 1306 colour_lkup[colour].str_colour, NULL); 1307 if (err != PICL_SUCCESS) { 1308 break; 1309 } 1310 } 1311 } 1312 /* 1313 * add a label property unless it's a keyswitch or the 1314 * chassis serial number. keyswitch and chassis serial 1315 * number are labelled from a config file because the 1316 * ALOM interface doesn't supply a name for it) 1317 */ 1318 if ((fru_type != ENVMON_KEY_SWITCH) && 1319 (fru_type != ENVMON_CHASSIS)) { 1320 err = add_regular_prop(node_hdl, PICL_PROP_LABEL, 1321 PICL_PTYPE_CHARSTRING, PICL_READ, 1322 1 + strlen(label_name), label_name, NULL); 1323 1324 if (err != PICL_SUCCESS) { 1325 break; 1326 } 1327 } 1328 /* 1329 * all properties added to this node, add the node below 1330 * the supplied anchor point 1331 */ 1332 err = ptree_add_node(envmonh, node_hdl); 1333 1334 if (err != PICL_SUCCESS) { 1335 break; 1336 } 1337 1338 /* 1339 * that node went in OK, advance index 1340 */ 1341 index++; 1342 1343 } while ((id.name[0] != '\0') && (index < handle_arr.maxnum)); 1344 1345 handle_arr.num = index; 1346 return (err); 1347 } 1348 1349 static void 1350 fixstate(uint8_t state, const char *string, int *max_len) 1351 { 1352 int i; 1353 int len; 1354 1355 for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0])); 1356 i++) { 1357 if (ledstate_lkup[i].state == state) { 1358 if (ledstate_lkup[i].str_ledstate != NULL) 1359 free(ledstate_lkup[i].str_ledstate); 1360 ledstate_lkup[i].str_ledstate = strdup(string); 1361 len = strlen(string); 1362 if (len >= *max_len) 1363 *max_len = len + 1; 1364 break; 1365 } 1366 } 1367 } 1368 1369 static void 1370 fixkeyposn(envmon_keysw_pos_t keyposn, const char *string, int *max_len) 1371 { 1372 int i; 1373 int len; 1374 1375 for (i = 0; i < (sizeof (keyposn_lkup) / sizeof (keyposn_lkup[0])); 1376 i++) { 1377 if (keyposn_lkup[i].pos == keyposn) { 1378 if (keyposn_lkup[i].str_keyposn != NULL) 1379 free(keyposn_lkup[i].str_keyposn); 1380 keyposn_lkup[i].str_keyposn = strdup(string); 1381 len = strlen(string); 1382 if (len >= *max_len) 1383 *max_len = len + 1; 1384 break; 1385 } 1386 } 1387 } 1388 1389 static void 1390 setup_strings() 1391 { 1392 int string_size; 1393 int i; 1394 int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]); 1395 1396 /* 1397 * initialise led colours lookup 1398 */ 1399 for (i = 0; i < lim; i++) { 1400 if (colour_lkup[i].str_colour != NULL) 1401 free(colour_lkup[i].str_colour); 1402 } 1403 1404 colour_lkup[ENVMON_LED_CLR_ANY].str_colour = strdup(gettext("any")); 1405 colour_lkup[ENVMON_LED_CLR_WHITE].str_colour = 1406 strdup(gettext("white")); 1407 colour_lkup[ENVMON_LED_CLR_BLUE].str_colour = strdup(gettext("blue")); 1408 colour_lkup[ENVMON_LED_CLR_GREEN].str_colour = 1409 strdup(gettext("green")); 1410 colour_lkup[ENVMON_LED_CLR_AMBER].str_colour = 1411 strdup(gettext("amber")); 1412 colour_lkup[ENVMON_LED_CLR_RED].str_colour = 1413 strdup(gettext("red")); 1414 1415 for (i = 0; i < lim; i++) { 1416 if (colour_lkup[i].str_colour != NULL) 1417 colour_lkup[i].size = 1418 1 + strlen(colour_lkup[i].str_colour); 1419 } 1420 1421 /* 1422 * initialise condition strings and note longest 1423 */ 1424 string_size = 0; 1425 cond_okay = strdup(gettext("okay")); 1426 if (strlen(cond_okay) >= string_size) 1427 string_size = 1 + strlen(cond_okay); 1428 cond_failed = strdup(gettext("failed")); 1429 if (strlen(cond_failed) >= string_size) 1430 string_size = 1 + strlen(cond_failed); 1431 1432 for (i = 0; i < sizeof (fru_to_size) / sizeof (fru_to_size[0]); i++) 1433 if (fru_to_size[i] == -1) 1434 fru_to_size[i] = string_size; 1435 1436 /* 1437 * initialise led state lookup strings 1438 */ 1439 string_size = 0; 1440 fixstate(ENVMON_LED_OFF, gettext("off"), &string_size); 1441 fixstate(ENVMON_LED_ON, gettext("on"), &string_size); 1442 fixstate(ENVMON_LED_BLINKING, gettext("blinking"), &string_size); 1443 fixstate(ENVMON_LED_FLASHING, gettext("flashing"), &string_size); 1444 fru_to_size[ENVMON_LED_IND] = string_size; 1445 1446 /* 1447 * initialise key position lookup strings 1448 */ 1449 string_size = 0; 1450 fixkeyposn(ENVMON_KEYSW_POS_UNKNOWN, gettext("UNKNOWN"), &string_size); 1451 fixkeyposn(ENVMON_KEYSW_POS_NORMAL, gettext("NORMAL"), &string_size); 1452 fixkeyposn(ENVMON_KEYSW_POS_DIAG, gettext("DIAG"), &string_size); 1453 fixkeyposn(ENVMON_KEYSW_POS_LOCKED, gettext("LOCKED"), &string_size); 1454 fixkeyposn(ENVMON_KEYSW_POS_OFF, gettext("STBY"), &string_size); 1455 fru_to_size[ENVMON_KEY_SWITCH] = string_size; 1456 1457 /* 1458 * initialise chassis serial number string 1459 */ 1460 fru_to_size[ENVMON_CHASSIS] = ENVMON_MAXNAMELEN; 1461 } 1462 1463 /* 1464 * The size of outfilename must be PATH_MAX 1465 */ 1466 static int 1467 get_config_file(char *filename) 1468 { 1469 char nmbuf[SYS_NMLN]; 1470 char pname[PATH_MAX]; 1471 1472 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 1473 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 1474 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX); 1475 if (access(pname, R_OK) == 0) { 1476 (void) strlcpy(filename, pname, PATH_MAX); 1477 return (0); 1478 } 1479 } 1480 1481 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 1482 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 1483 (void) strlcat(pname, ENVMON_CONFFILE_NAME, PATH_MAX); 1484 if (access(pname, R_OK) == 0) { 1485 (void) strlcpy(filename, pname, PATH_MAX); 1486 return (0); 1487 } 1488 } 1489 1490 (void) snprintf(pname, PATH_MAX, "%s/%s", 1491 PICLD_COMMON_PLUGIN_DIR, ENVMON_CONFFILE_NAME); 1492 1493 if (access(pname, R_OK) == 0) { 1494 (void) strlcpy(filename, pname, PATH_MAX); 1495 return (0); 1496 } 1497 1498 return (-1); 1499 } 1500 1501 static void 1502 free_vol_prop(picl_prophdl_t proph) 1503 { 1504 int index; 1505 1506 index = find_picl_handle(proph); 1507 if (index >= 0) { 1508 handle_arr.num--; 1509 if (index != handle_arr.num) { 1510 /* relocate last entry into hole just created */ 1511 handle_arr.fru_types[index] = 1512 handle_arr.fru_types[handle_arr.num]; 1513 handle_arr.envhandles[index] = 1514 handle_arr.envhandles[handle_arr.num]; 1515 handle_arr.piclprhdls[index] = 1516 handle_arr.piclprhdls[handle_arr.num]; 1517 } 1518 } 1519 } 1520 1521 /* 1522 * handle PICL FRU ADDED and FRU REMOVED events 1523 */ 1524 /*ARGSUSED*/ 1525 static void 1526 envmon_evhandler(const char *ename, const void *earg, size_t size, 1527 void *cookie) 1528 { 1529 char path[MAXPATHLEN]; 1530 picl_nodehdl_t locnodeh; 1531 int retval; 1532 picl_nodehdl_t childh; 1533 picl_nodehdl_t nodeh; 1534 picl_prophdl_t tableh; 1535 picl_prophdl_t tblh; 1536 picl_prophdl_t proph; 1537 ptree_propinfo_t pi; 1538 1539 if (strcmp(ename, PICL_FRU_ADDED) == 0) { 1540 retval = nvlist_lookup_uint64((nvlist_t *)earg, 1541 PICLEVENTARG_PARENTHANDLE, &locnodeh); 1542 1543 if (retval != 0) { 1544 syslog(LOG_ERR, EM_EV_MISSING_ARG, 1545 PICLEVENTARG_PARENTHANDLE); 1546 return; 1547 } 1548 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME, 1549 path, sizeof (path)); 1550 if (retval == PICL_SUCCESS) { 1551 /* 1552 * Open envmon device and interrogate 1553 */ 1554 int envmon_fd; 1555 int fru_type; 1556 picl_nodehdl_t envmoninfh; 1557 1558 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS) { 1559 syslog(LOG_ERR, EM_SC_NODE_MISSING); 1560 return; 1561 } 1562 1563 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) < 1564 0) { 1565 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name, 1566 strerror(errno)); 1567 return; 1568 } 1569 1570 if (strcmp(str_SC, path) == 0) { 1571 /* 1572 * SC state change - re-assess platform tree 1573 */ 1574 if (re_create_arrays(envmon_fd) != 0) { 1575 /* 1576 * out of memory - make no changes 1577 */ 1578 return; 1579 } 1580 /* 1581 * dropped memory of volatile prop handles 1582 * so drop the nodes also, then rebuild for 1583 * the newly loaded SC 1584 */ 1585 retval = ptree_get_propval_by_name(envmoninfh, 1586 PICL_PROP_PARENT, &nodeh, sizeof (nodeh)); 1587 if (retval != PICL_SUCCESS) { 1588 (void) close(envmon_fd); 1589 return; 1590 } 1591 retval = ptree_get_propval_by_name(envmoninfh, 1592 PICL_PROP_NAME, path, sizeof (path)); 1593 if (retval != PICL_SUCCESS) { 1594 (void) close(envmon_fd); 1595 return; 1596 } 1597 1598 retval = ptree_delete_node(envmoninfh); 1599 if (retval == PICL_SUCCESS) 1600 (void) ptree_destroy_node(envmoninfh); 1601 retval = ptree_create_node(path, 1602 PICL_CLASS_SERVICE_PROCESSOR, &envmoninfh); 1603 if (retval != PICL_SUCCESS) { 1604 (void) close(envmon_fd); 1605 return; 1606 } 1607 retval = ptree_add_node(nodeh, envmoninfh); 1608 if (retval != PICL_SUCCESS) { 1609 (void) close(envmon_fd); 1610 return; 1611 } 1612 } 1613 1614 for (fru_type = 0; fru_type < ENVMONTYPES; 1615 fru_type++) { 1616 (void) add_env_nodes(envmon_fd, fru_type, 1617 envmoninfh); 1618 } 1619 1620 (void) close(envmon_fd); 1621 } 1622 } else if (strcmp(ename, PICL_FRU_REMOVED) == 0) { 1623 retval = nvlist_lookup_uint64((nvlist_t *)earg, 1624 PICLEVENTARG_FRUHANDLE, &childh); 1625 1626 if (retval != 0) { 1627 syslog(LOG_ERR, EM_EV_MISSING_ARG, 1628 PICLEVENTARG_FRUHANDLE); 1629 return; 1630 } 1631 retval = ptree_get_propval_by_name(childh, PICL_PROP_NAME, 1632 path, sizeof (path)); 1633 if (retval == PICL_SUCCESS) { 1634 retval = ptree_get_prop_by_name(childh, 1635 PICL_PROP_DEVICES, &tableh); 1636 1637 if (retval != PICL_SUCCESS) { 1638 /* no Devices table, nothing to do */ 1639 return; 1640 } 1641 1642 /* 1643 * follow all reference properties in the second 1644 * column of the table and delete the referenced node 1645 */ 1646 retval = ptree_get_propval(tableh, &tblh, 1647 sizeof (tblh)); 1648 if (retval != PICL_SUCCESS) { 1649 /* 1650 * can't get value of table property 1651 */ 1652 return; 1653 } 1654 /* get first col, first row */ 1655 retval = ptree_get_next_by_col(tblh, &tblh); 1656 if (retval != PICL_SUCCESS) { 1657 /* 1658 * no rows? 1659 */ 1660 return; 1661 } 1662 /* 1663 * starting at next col, get every entry in the column 1664 */ 1665 for (retval = ptree_get_next_by_row(tblh, &tblh); 1666 retval == PICL_SUCCESS; 1667 retval = ptree_get_next_by_col(tblh, &tblh)) { 1668 /* 1669 * should be a ref prop in our hands, 1670 * get the target node handle 1671 */ 1672 retval = ptree_get_propval(tblh, &nodeh, 1673 sizeof (nodeh)); 1674 if (retval != PICL_SUCCESS) { 1675 continue; 1676 } 1677 /* 1678 * got the referenced node, has it got a 1679 * volatile property to clean up? 1680 */ 1681 retval = ptree_get_first_prop(nodeh, &proph); 1682 while (retval == PICL_SUCCESS) { 1683 retval = ptree_get_propinfo(proph, &pi); 1684 if ((retval == PICL_SUCCESS) && 1685 (pi.piclinfo.accessmode & 1686 PICL_VOLATILE)) 1687 free_vol_prop(proph); 1688 retval = ptree_get_next_prop(proph, 1689 &proph); 1690 } 1691 /* 1692 * all volatile properties gone, remove node 1693 */ 1694 retval = ptree_delete_node(nodeh); 1695 if (retval == PICL_SUCCESS) 1696 (void) ptree_destroy_node(nodeh); 1697 } 1698 } 1699 } 1700 } 1701 1702 /* 1703 * executed as part of .init when the plugin is dlopen()ed 1704 */ 1705 static void 1706 piclenvmon_register(void) 1707 { 1708 (void) picld_plugin_register(&my_reg_info); 1709 } 1710 1711 /* 1712 * Init entry point of the plugin 1713 * Creates the PICL nodes and properties in the physical and logical aspects. 1714 */ 1715 static void 1716 piclenvmon_init(void) 1717 { 1718 picl_nodehdl_t rooth; 1719 picl_nodehdl_t plfh; 1720 picl_nodehdl_t envmoninfh; 1721 int res; 1722 int envmon_fd; 1723 int fru_type; 1724 char pathname[PATH_MAX]; 1725 1726 /* 1727 * locate and parse config file 1728 */ 1729 if (get_config_file(pathname) < 0) 1730 return; 1731 1732 if ((ptree_get_root(&rooth) != PICL_SUCCESS) || 1733 (picld_pluginutil_parse_config_file(rooth, pathname) != 1734 PICL_SUCCESS)) { 1735 syslog(LOG_ERR, EM_INIT_FAILED); 1736 } 1737 1738 /* 1739 * Get platform node 1740 */ 1741 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh) 1742 != PICL_SUCCESS) { 1743 syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM); 1744 syslog(LOG_ERR, EM_INIT_FAILED); 1745 return; 1746 } 1747 1748 /* 1749 * Get service-processor node 1750 */ 1751 if (get_envmon_node(&envmoninfh) != PICL_SUCCESS) 1752 return; 1753 1754 /* 1755 * We may have been restarted, make sure we don't leak 1756 */ 1757 if (envmon_device_name != NULL) { 1758 free(envmon_device_name); 1759 } 1760 1761 if ((envmon_device_name = create_envmon_pathname(envmoninfh)) == NULL) 1762 return; 1763 1764 /* 1765 * Open envmon device and interrogate for devices it monitors 1766 */ 1767 if ((envmon_fd = open(envmon_device_name, O_RDONLY)) < 0) { 1768 syslog(LOG_ERR, EM_SYS_ERR, envmon_device_name, 1769 strerror(errno)); 1770 return; 1771 } 1772 1773 if (get_envmon_limits(envmon_fd, &env_limits) < 0) 1774 return; 1775 1776 /* 1777 * A set of arrays are used whose bounds are determined by the 1778 * response to get_envmon_limits. Establish these arrays now. 1779 */ 1780 create_arrays(); 1781 setup_strings(); 1782 1783 for (fru_type = 0; fru_type < ENVMONTYPES; fru_type++) { 1784 (void) add_env_nodes(envmon_fd, fru_type, envmoninfh); 1785 } 1786 1787 (void) close(envmon_fd); 1788 1789 res = ptree_register_handler(PICL_FRU_ADDED, envmon_evhandler, NULL); 1790 if (res != PICL_SUCCESS) { 1791 syslog(LOG_ERR, EM_EVREG_FAILED, res); 1792 } 1793 res = ptree_register_handler(PICL_FRU_REMOVED, envmon_evhandler, NULL); 1794 if (res != PICL_SUCCESS) { 1795 syslog(LOG_ERR, EM_EVREG_FAILED, res); 1796 } 1797 } 1798 1799 /* 1800 * fini entry point of the plugin 1801 */ 1802 static void 1803 piclenvmon_fini(void) 1804 { 1805 if (envmon_device_name != NULL) { 1806 free(envmon_device_name); 1807 envmon_device_name = NULL; 1808 } 1809 (void) ptree_unregister_handler(PICL_FRU_ADDED, 1810 envmon_evhandler, NULL); 1811 (void) ptree_unregister_handler(PICL_FRU_REMOVED, 1812 envmon_evhandler, NULL); 1813 } 1814