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