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