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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * This plugin creates PICL nodes and properties for objects handled through 28 * the blade support chip (BSC). The BSC Solaris land device driver exposes 29 * information to the plugin and other clients through an existing LOM 30 * (Lights Out Management) ioctl interface. The plugin only exercises 31 * a subset of the interface which is known to be supported by the bsc. 32 * 33 * All the nodes which may be accessible through the BSC are included below 34 * the SUNW,bscv node (class system-controller) in the /platform tree. 35 * This plugin interrogates the BSC 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 * 40 * NOTE: 41 * Depends on PICL devtree plugin. 42 */ 43 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <unistd.h> 47 #include <fcntl.h> 48 #include <alloca.h> 49 #include <syslog.h> 50 #include <string.h> 51 #include <libintl.h> 52 #include <picl.h> 53 #include <picltree.h> 54 #include <errno.h> 55 #include <limits.h> 56 #include <ctype.h> 57 #include <sys/types.h> 58 #include <sys/obpdefs.h> 59 #include <sys/lom_io.h> 60 #include <sys/systeminfo.h> 61 #include <time.h> 62 #include <picldefs.h> 63 #include <picld_pluginutil.h> 64 #include "picllom.h" 65 66 static void picllom_register(void); 67 static void picllom_init(void); 68 static void picllom_fini(void); 69 static node_el_t *create_node_el(picl_nodehdl_t nodeh); 70 static void delete_node_el(node_el_t *pel); 71 static node_list_t *create_node_list(); 72 static void delete_node_list_contents(node_list_t *pnl); 73 static void delete_node_list(node_list_t *pnl); 74 static void add_node_to_list(picl_nodehdl_t nodeh, 75 node_list_t *listp); 76 static void get_node_list_by_class(picl_nodehdl_t nodeh, 77 const char *classname, node_list_t *listp); 78 static int get_lom_node(picl_nodehdl_t *lominfh); 79 static int get_lom_device_path(picl_nodehdl_t *lominfh); 80 static int get_node_by_name_and_class(picl_nodehdl_t srchnodeh, 81 const char *nodename, const char *classname, picl_nodehdl_t *chdh); 82 static int add_regular_prop(picl_nodehdl_t nodeh, const char *name, 83 int type, int access, int size, const void *valbuf, picl_prophdl_t *prophp); 84 static int add_volatile_prop(picl_nodehdl_t nodeh, char *name, 85 int type, int access, int size, ptree_vol_rdfunc_t rdfunc, 86 ptree_vol_wrfunc_t wrfunc, picl_prophdl_t *prophp); 87 static int open_lom_rd(int *lom_fd); 88 static int get_lom_temp(int index, tempr_t *temp_p); 89 static int update_voltage_stats(); 90 static int get_lom_volts_status(int index, int *voltsStatus_p); 91 static int get_lom_volts_shutdown(int index, int *voltsShutdown_p); 92 static int update_fan_stats(); 93 static int get_lom_fan_speed(int index, int *fan_speed); 94 static int read_vol_temp(ptree_rarg_t *parg, void *buf); 95 static int read_vol_volts_status(ptree_rarg_t *parg, void *buf); 96 static int read_vol_volts_shutdown(ptree_rarg_t *parg, void *buf); 97 static int read_fan_speed(ptree_rarg_t *parg, void *buf); 98 static int read_fan_status(ptree_rarg_t *parg, void *buf); 99 static int lookup_led_status(int8_t state, const char **string); 100 static int read_led_status(ptree_rarg_t *parg, void *buf); 101 static void convert_node_name(char *ptr); 102 static int add_temp_sensors(int lom_fd, picl_nodehdl_t lominfh); 103 static int add_voltage_monitors(int lom_fd, 104 picl_nodehdl_t lominfh); 105 static int add_fan_nodes(int lom_fd, picl_nodehdl_t lominfh); 106 static int get_config_file(char *outfilename); 107 108 #pragma init(picllom_register) 109 110 static picld_plugin_reg_t my_reg_info = { 111 PICLD_PLUGIN_VERSION_1, 112 PICLD_PLUGIN_NON_CRITICAL, 113 "SUNW_picllom", 114 picllom_init, 115 picllom_fini 116 }; 117 118 static const char str_OK[] = "OK"; 119 static const char str_FAIL[] = "FAIL"; 120 static const char str_On[] = "on"; 121 static const char str_Off[] = "off"; 122 static const char str_Enabled[] = "Enabled"; 123 static const char str_Disabled[] = "Disabled"; 124 static char lom_device_path[PATH_MAX]; 125 static tempr_t high_warnings[MAX_TEMPS]; 126 static tempr_t high_shutdowns[MAX_TEMPS]; 127 static picl_prophdl_t temp_handles[MAX_TEMPS]; 128 static lom_fandata_t fandata; 129 static picl_prophdl_t fan_speed_handles[MAX_FANS]; 130 static picl_prophdl_t fan_status_handles[MAX_FANS]; 131 static lom_volts_t voltsdata; 132 static picl_prophdl_t volts_status_handles[MAX_VOLTS]; 133 static picl_prophdl_t volts_shutdown_handles[MAX_VOLTS]; 134 static int n_leds = 0; 135 static int max_state_size = 0; 136 static picl_prophdl_t *led_handles = NULL; 137 static char **led_labels = NULL; 138 static lom2_info_t info2data; 139 static struct { 140 int size; 141 char *str_colour; 142 } colour_lkup[1 + LOM_LED_COLOUR_AMBER]; 143 144 static struct { 145 int8_t state; 146 char *str_ledstate; 147 } ledstate_lkup[] = { 148 { LOM_LED_OFF }, 149 { LOM_LED_ON }, 150 { LOM_LED_BLINKING }, 151 }; 152 153 static node_el_t * 154 create_node_el(picl_nodehdl_t nodeh) 155 { 156 node_el_t *ptr = malloc(sizeof (node_el_t)); 157 158 if (ptr != NULL) { 159 ptr->nodeh = nodeh; 160 ptr->next = NULL; 161 } 162 163 return (ptr); 164 } 165 166 static void 167 delete_node_el(node_el_t *pel) 168 { 169 free(pel); 170 } 171 172 static node_list_t * 173 create_node_list() 174 { 175 node_list_t *ptr = malloc(sizeof (node_list_t)); 176 177 if (ptr != NULL) { 178 ptr->head = NULL; 179 ptr->tail = NULL; 180 } 181 182 return (ptr); 183 } 184 185 static void 186 delete_node_list_contents(node_list_t *pnl) 187 { 188 node_el_t *pel; 189 190 if (pnl == NULL) 191 return; 192 193 while ((pel = pnl->head) != NULL) { 194 pnl->head = pel->next; 195 delete_node_el(pel); 196 } 197 198 pnl->tail = NULL; 199 } 200 201 static void 202 delete_node_list(node_list_t *pnl) 203 { 204 delete_node_list_contents(pnl); 205 free(pnl); 206 } 207 208 /* 209 * Get a linking element and add handle to end of chain 210 */ 211 static void 212 add_node_to_list(picl_nodehdl_t nodeh, node_list_t *listp) 213 { 214 node_el_t *pel = create_node_el(nodeh); 215 216 if (pel != NULL) { 217 if (listp->tail == NULL) 218 listp->head = pel; 219 else 220 listp->tail->next = pel; 221 222 listp->tail = pel; 223 } 224 } 225 226 /* 227 * Get a list of nodes of the specified classname under nodeh. 228 * Once a node of the specified class is found, its children are not 229 * searched. 230 */ 231 static void 232 get_node_list_by_class(picl_nodehdl_t nodeh, const char *classname, 233 node_list_t *listp) 234 { 235 int err; 236 char clname[PICL_CLASSNAMELEN_MAX+1]; 237 picl_nodehdl_t chdh; 238 239 /* 240 * go through the children 241 */ 242 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &chdh, 243 sizeof (picl_nodehdl_t)); 244 245 while (err == PICL_SUCCESS) { 246 err = ptree_get_propval_by_name(chdh, PICL_PROP_CLASSNAME, 247 clname, strlen(classname) + 1); 248 249 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0)) 250 add_node_to_list(chdh, listp); 251 else 252 get_node_list_by_class(chdh, classname, listp); 253 254 err = ptree_get_propval_by_name(chdh, PICL_PROP_PEER, &chdh, 255 sizeof (picl_nodehdl_t)); 256 } 257 } 258 259 static int 260 get_lom_node(picl_nodehdl_t *lominfh) 261 { 262 int err = PICL_SUCCESS; 263 node_list_t *listp; 264 265 listp = create_node_list(); 266 267 if ((err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, 268 lominfh)) != PICL_SUCCESS) { 269 syslog(LOG_ERR, EM_MISSING_NODE, 270 PICL_NODE_ROOT PICL_NODE_PLATFORM); 271 return (err); /* no /platform ! */ 272 } 273 274 get_node_list_by_class(*lominfh, PICL_CLASS_SERVICE_PROCESSOR, listp); 275 276 if (listp->head == NULL) { 277 *lominfh = 0; 278 syslog(LOG_ERR, EM_MISSING_NODE, PICL_CLASS_SERVICE_PROCESSOR); 279 err = PICL_NODENOTFOUND; 280 } else { 281 *lominfh = listp->head->nodeh; 282 283 if (listp->head != listp->tail) 284 syslog(LOG_ERR, EM_LOM_DUPLICATE); 285 } 286 287 delete_node_list(listp); 288 return (err); 289 } 290 291 static int 292 get_lom_device_path(picl_nodehdl_t *lominfh) 293 { 294 int err = PICL_SUCCESS; 295 char devfs_path[PATH_MAX]; 296 char devices_path[PATH_MAX]; 297 298 err = ptree_get_propval_by_name(*lominfh, PICL_PROP_DEVFS_PATH, 299 devfs_path, sizeof (devfs_path)); 300 301 /* Build up the full device path and set the global */ 302 strcpy(devices_path, "/devices"); 303 strcat(devices_path, devfs_path); 304 strcat(devices_path, LOM_DEV_MINOR_NAME); 305 strcpy(lom_device_path, devices_path); 306 307 return (err); 308 309 } 310 311 312 313 314 /* 315 * Look for a node of specified name and class 316 * Confine search to nodes one level below that of supplied handle 317 */ 318 static int 319 get_node_by_name_and_class(picl_nodehdl_t srchnodeh, const char *nodename, 320 const char *classname, picl_nodehdl_t *chdh) 321 { 322 int err; 323 char namebuf[PATH_MAX]; 324 325 err = ptree_get_propval_by_name(srchnodeh, PICL_PROP_CHILD, chdh, 326 sizeof (picl_nodehdl_t)); 327 328 while (err == PICL_SUCCESS) { 329 err = ptree_get_propval_by_name(*chdh, PICL_PROP_NAME, namebuf, 330 sizeof (namebuf)); 331 if (err != PICL_SUCCESS) 332 break; 333 if (strcmp(namebuf, nodename) == 0) { 334 err = ptree_get_propval_by_name(*chdh, 335 PICL_PROP_CLASSNAME, namebuf, sizeof (namebuf)); 336 if ((err == PICL_SUCCESS) && 337 (strcmp(namebuf, classname) == 0)) 338 return (PICL_SUCCESS); 339 } 340 err = ptree_get_propval_by_name(*chdh, PICL_PROP_PEER, chdh, 341 sizeof (picl_nodehdl_t)); 342 } 343 344 return (err); 345 } 346 347 /* 348 * Create and add the specified regular property 349 */ 350 351 static int 352 add_regular_prop(picl_nodehdl_t nodeh, const char *name, int type, int access, 353 int size, const void *valbuf, picl_prophdl_t *prophp) 354 { 355 int err; 356 ptree_propinfo_t propinfo; 357 picl_prophdl_t proph; 358 359 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 360 type, access, size, (char *)name, NULL, NULL); 361 if (err != PICL_SUCCESS) 362 return (err); 363 364 err = ptree_create_and_add_prop(nodeh, &propinfo, (void *)valbuf, 365 &proph); 366 if (err == PICL_SUCCESS && prophp) 367 *prophp = proph; 368 return (err); 369 } 370 371 372 /* 373 * Create and add the specified volatile property 374 */ 375 static int 376 add_volatile_prop(picl_nodehdl_t nodeh, char *name, int type, int access, 377 int size, ptree_vol_rdfunc_t rdfunc, ptree_vol_wrfunc_t wrfunc, 378 picl_prophdl_t *prophp) 379 { 380 int err; 381 ptree_propinfo_t propinfo; 382 picl_prophdl_t proph; 383 384 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 385 type, (access|PICL_VOLATILE), size, name, rdfunc, wrfunc); 386 if (err != PICL_SUCCESS) 387 return (err); 388 389 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph); 390 if (err == PICL_SUCCESS && prophp) 391 *prophp = proph; 392 return (err); 393 } 394 395 /* 396 * open LOM device to read 397 */ 398 static int 399 open_lom_rd(int *lom_fd) 400 { 401 *lom_fd = open(lom_device_path, O_RDONLY); 402 403 if (*lom_fd < 0) 404 return (PICL_FAILURE); 405 406 return (PICL_SUCCESS); 407 } 408 409 /* 410 * Function to open LOM and read temperature sensor values. 411 * The index to a specific sensor is supplied and that value returned. 412 */ 413 static int 414 get_lom_temp(int index, tempr_t *temp_p) 415 { 416 lom_temp_t lom_temp; 417 int lom_fd; 418 int err; 419 int res; 420 421 err = open_lom_rd(&lom_fd); 422 423 if (err == PICL_SUCCESS) { 424 res = ioctl(lom_fd, LOMIOCTEMP, &lom_temp); 425 (void) close(lom_fd); 426 427 if (res == 0) { 428 *temp_p = lom_temp.temp[index]; 429 } else { 430 err = PICL_FAILURE; 431 } 432 } 433 434 return (err); 435 } 436 437 /* 438 * Function to open LOM and read voltage monitor values. 439 * Called for each property, so only perform update if time has changed 440 */ 441 static int 442 update_voltage_stats() 443 { 444 static time_t then = 0; 445 int lom_fd; 446 int err; 447 int res; 448 time_t now = time(NULL); 449 450 if (now == then) 451 return (PICL_SUCCESS); 452 453 then = now; 454 err = open_lom_rd(&lom_fd); 455 456 if (err == PICL_SUCCESS) { 457 res = ioctl(lom_fd, LOMIOCVOLTS, &voltsdata); 458 (void) close(lom_fd); 459 if (res < 0) { 460 err = PICL_FAILURE; 461 } 462 } 463 464 return (err); 465 } 466 467 /* 468 * Function to open LOM and read voltage monitor values. 469 * The index to a specific voltage status is supplied and that value returned. 470 */ 471 static int 472 get_lom_volts_status(int index, int *voltsStatus_p) 473 { 474 int res; 475 476 if ((res = update_voltage_stats()) != PICL_SUCCESS) 477 return (res); 478 479 *voltsStatus_p = voltsdata.status[index]; 480 return (PICL_SUCCESS); 481 } 482 483 /* 484 * Function to open LOM and read voltage monitor values. 485 * The index to a specific shutdown flag is supplied and that value returned. 486 */ 487 static int 488 get_lom_volts_shutdown(int index, int *voltsShutdown_p) 489 { 490 int res; 491 492 if ((res = update_voltage_stats()) != PICL_SUCCESS) 493 return (res); 494 495 *voltsShutdown_p = voltsdata.shutdown_enabled[index]; 496 return (PICL_SUCCESS); 497 } 498 499 500 501 /* 502 * Function to open LOM and read fan values. 503 * Called for each property, so only perform update if time has changed 504 */ 505 static int 506 update_fan_stats() 507 { 508 static time_t then = 0; 509 int lom_fd; 510 int err; 511 int res; 512 time_t now = time(NULL); 513 514 if (now == then) 515 return (PICL_SUCCESS); 516 517 then = now; 518 err = open_lom_rd(&lom_fd); 519 if (err == PICL_SUCCESS) { 520 res = ioctl(lom_fd, LOMIOCFANSTATE, &fandata); 521 (void) close(lom_fd); 522 if (res < 0) { 523 err = PICL_FAILURE; 524 } 525 } 526 527 return (err); 528 } 529 530 531 532 /* 533 * The index to a specific fan is supplied and its speed value returned. 534 */ 535 static int 536 get_lom_fan_speed(int index, int *fan_speed) 537 { 538 int res; 539 540 if ((res = update_fan_stats()) != PICL_SUCCESS) 541 return (res); 542 543 *fan_speed = fandata.speed[index]; 544 return (PICL_SUCCESS); 545 } 546 547 548 /* 549 * Read function for volatile "Temperature" property via LOM 550 */ 551 static int 552 read_vol_temp(ptree_rarg_t *parg, void *buf) 553 { 554 tempr_t temp; 555 picl_prophdl_t proph; 556 int index; 557 558 /* 559 * get the sensor index from the displacement of the 560 * property handle and get its temperature. 561 */ 562 proph = parg->proph; 563 for (index = 0; index < MAX_TEMPS; index++) { 564 if (temp_handles[index] == proph) 565 break; 566 } 567 568 if (index == MAX_TEMPS) { 569 /* 570 * Handle not found. As this is a plugin, stale handles 571 * cannot occur, so just fail. 572 */ 573 return (PICL_FAILURE); 574 } 575 576 if (get_lom_temp(index, &temp) != PICL_SUCCESS) 577 return (PICL_FAILURE); 578 (void) memcpy(buf, (caddr_t)&temp, sizeof (tempr_t)); 579 return (PICL_SUCCESS); 580 } 581 582 /* 583 * Read function for volatile "VoltageStatus" property via LOM 584 */ 585 static int 586 read_vol_volts_status(ptree_rarg_t *parg, void *buf) 587 { 588 int voltsStatus; 589 picl_prophdl_t proph; 590 int index; 591 592 /* 593 * get the voltage monitor index from the displacement of the 594 * status property handle and get its status. 595 */ 596 proph = parg->proph; 597 598 for (index = 0; index < MAX_VOLTS; index++) { 599 if (volts_status_handles[index] == proph) 600 break; 601 } 602 603 if (index == MAX_VOLTS) 604 return (PICL_FAILURE); 605 606 if (get_lom_volts_status(index, &voltsStatus) != PICL_SUCCESS) 607 return (PICL_FAILURE); 608 609 (void) strlcpy(buf, (voltsStatus == 0) ? str_OK : str_FAIL, 610 sizeof (str_FAIL)); 611 return (PICL_SUCCESS); 612 } 613 614 /* 615 * Read function for volatile "VoltageShutdown" property via LOM 616 */ 617 static int 618 read_vol_volts_shutdown(ptree_rarg_t *parg, void *buf) 619 { 620 int voltsShutdown; 621 picl_prophdl_t proph; 622 int index; 623 624 /* 625 * get the voltage monitor index from the displacement of the 626 * shutdown property handle and get its value. 627 */ 628 proph = parg->proph; 629 630 for (index = 0; index < MAX_VOLTS; index++) { 631 if (volts_shutdown_handles[index] == proph) 632 break; 633 } 634 635 if (index == MAX_VOLTS) 636 return (PICL_FAILURE); 637 638 if (get_lom_volts_shutdown(index, &voltsShutdown) != PICL_SUCCESS) 639 return (PICL_FAILURE); 640 641 (void) strlcpy(buf, (voltsShutdown == 0) ? str_Disabled : str_Enabled, 642 sizeof (str_Disabled)); 643 return (PICL_SUCCESS); 644 } 645 646 647 /* 648 * Read function for volatile fan speed property via LOM 649 */ 650 static int 651 read_fan_speed(ptree_rarg_t *parg, void *buf) 652 { 653 int fan_speed; 654 picl_prophdl_t proph; 655 int index; 656 657 /* 658 * get the relevant fan from the displacement of its property handle 659 */ 660 proph = parg->proph; 661 662 for (index = 0; index < MAX_FANS; index++) { 663 if (fan_speed_handles[index] == proph) 664 break; 665 } 666 667 if (index == MAX_FANS) 668 return (PICL_FAILURE); 669 670 if (get_lom_fan_speed(index, &fan_speed) != PICL_SUCCESS) 671 return (PICL_FAILURE); 672 673 (void) memcpy(buf, (caddr_t)&fan_speed, sizeof (fan_speed)); 674 return (PICL_SUCCESS); 675 } 676 677 /* 678 * look up function to convert led status into string 679 */ 680 static int 681 lookup_led_status(int8_t state, const char **string) 682 { 683 int i; 684 int lim = sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0]); 685 686 for (i = 0; i < lim; i++) { 687 if (ledstate_lkup[i].state == state) { 688 *string = ledstate_lkup[i].str_ledstate; 689 return (PICL_SUCCESS); 690 } 691 } 692 693 *string = ""; 694 switch (state) { 695 case LOM_LED_ACCESS_ERROR: 696 return (PICL_PROPVALUNAVAILABLE); 697 case LOM_LED_NOT_IMPLEMENTED: 698 /*FALLTHROUGH*/ 699 case LOM_LED_OUTOFRANGE: 700 /*FALLTHROUGH*/ 701 default: 702 return (PICL_FAILURE); 703 } 704 } 705 706 /* 707 * Read function for volatile led status property. 708 */ 709 static int 710 read_led_status(ptree_rarg_t *parg, void *buf) 711 { 712 lom_led_state_t led_data; 713 picl_prophdl_t proph; 714 int index; 715 int lom_fd; 716 int res; 717 const char *string; 718 719 /* 720 * get the relevant led from the displacement of its property handle 721 */ 722 proph = parg->proph; 723 724 for (index = 0; index < n_leds; index++) { 725 if (led_handles[index] == proph) 726 break; 727 } 728 729 if (index == n_leds) 730 return (PICL_FAILURE); 731 732 res = open_lom_rd(&lom_fd); 733 if (res != PICL_SUCCESS) 734 return (res); 735 /* 736 * The interface for reading LED status doesn't promise to maintain 737 * a constant mapping between LED index number and LED identity 738 * (as defined by its label). On the other hand, PICL does promise 739 * that whilst a handle remains valid the object it represents will 740 * remain constant. To reconcile these positions, we maintain 741 * tables of labels and handles linked by index value. We search 742 * for the handle with which we are presented and then locate its 743 * label. Then we request LED entries from the LOM and compare their 744 * labels with the one we seek. As an optimisation, we try the original 745 * index value first and then revert to a full search. 746 */ 747 (void) memset(&led_data, 0, sizeof (led_data)); 748 led_data.index = index; 749 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data); 750 751 if (res != 0 || led_data.state == LOM_LED_NOT_IMPLEMENTED || 752 strcmp(led_data.label, led_labels[index]) != 0) { 753 /* 754 * full scan required (bet it doesn't work!) 755 * first re-establish the range to scan 756 */ 757 int i; 758 int n; 759 760 (void) memset(&led_data, 0, sizeof (led_data)); 761 led_data.index = -1; 762 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data); 763 764 if (res != 0) { 765 (void) close(lom_fd); 766 return (PICL_PROPVALUNAVAILABLE); 767 } 768 769 if (led_data.state == LOM_LED_NOT_IMPLEMENTED || 770 strcmp(led_data.label, led_labels[index]) != 0) { 771 n = led_data.index; 772 for (i = 0; i < n; i++) { 773 (void) memset(&led_data, 0, sizeof (led_data)); 774 led_data.index = i; 775 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data); 776 777 if (res == 0 && 778 led_data.state != LOM_LED_NOT_IMPLEMENTED || 779 strcmp(led_data.label, led_labels[index]) == 780 0) { 781 break; 782 } 783 } 784 785 if (i == n) { 786 (void) close(lom_fd); 787 return (PICL_PROPVALUNAVAILABLE); 788 } 789 } 790 } 791 792 /* 793 * if we get here, then we found the right LED. 794 */ 795 (void) close(lom_fd); 796 res = lookup_led_status(led_data.state, &string); 797 (void) strlcpy(buf, string, max_state_size); 798 return (res); 799 } 800 801 /* 802 * Read function for volatile fan status property. 803 * This is a synthesized property using speed and min speed properties 804 */ 805 static int 806 read_fan_status(ptree_rarg_t *parg, void *buf) 807 { 808 int fan_speed; 809 picl_prophdl_t proph; 810 int index; 811 812 /* 813 * get the relevant fan from the displacement of its property handle 814 */ 815 proph = parg->proph; 816 817 for (index = 0; index < MAX_FANS; index++) { 818 if (fan_status_handles[index] == proph) 819 break; 820 } 821 822 if (index == MAX_FANS) 823 return (PICL_FAILURE); 824 825 if (get_lom_fan_speed(index, &fan_speed) != PICL_SUCCESS) 826 return (PICL_FAILURE); 827 828 (void) strlcpy(buf, 829 fan_speed < fandata.minspeed[index] ? str_FAIL : str_OK, 830 sizeof (str_FAIL)); 831 return (PICL_SUCCESS); 832 } 833 834 835 836 /* 837 * change to lower case and convert any spaces into hyphens 838 */ 839 static void 840 convert_node_name(char *ptr) 841 { 842 char ch; 843 844 for (ch = *ptr; ch != '\0'; ch = *++ptr) { 845 if (isupper(ch)) { 846 *ptr = tolower(ch); 847 } else if (isspace(ch)) { 848 *ptr = '-'; 849 } 850 } 851 } 852 853 static int 854 add_temp_sensors(int lom_fd, picl_nodehdl_t lominfh) 855 { 856 lom_temp_t lom_temp; 857 int res; 858 int i; 859 int err = PICL_SUCCESS; 860 const char *cptr; 861 862 res = ioctl(lom_fd, LOMIOCTEMP, &lom_temp); 863 864 if ((res == 0) && (lom_temp.num > 0)) { 865 /* 866 * for each temperature location add a sensor node 867 */ 868 for (i = 0; i < lom_temp.num; i++) { 869 picl_nodehdl_t tempsensh; 870 picl_prophdl_t proph; 871 872 high_warnings[i] = lom_temp.warning[i]; 873 high_shutdowns[i] = lom_temp.shutdown[i]; 874 875 convert_node_name(lom_temp.name[i]); 876 877 err = ptree_create_node(lom_temp.name[i], 878 PICL_CLASS_TEMPERATURE_SENSOR, &tempsensh); 879 if (err != PICL_SUCCESS) 880 break; 881 882 err = add_volatile_prop(tempsensh, 883 PICL_PROP_TEMPERATURE, PICL_PTYPE_INT, PICL_READ, 884 sizeof (tempr_t), read_vol_temp, NULL, 885 &temp_handles[i]); 886 if (err != PICL_SUCCESS) 887 break; 888 889 if (high_warnings[i] != 0) { 890 err = add_regular_prop( 891 tempsensh, PICL_PROP_HIGH_WARNING, 892 PICL_PTYPE_INT, PICL_READ, 893 sizeof (tempr_t), &high_warnings[i], 894 &proph); 895 if (err != PICL_SUCCESS) 896 break; 897 } 898 899 if (high_shutdowns[i] != 0) { 900 err = add_regular_prop( 901 tempsensh, PICL_PROP_HIGH_SHUTDOWN, 902 PICL_PTYPE_INT, PICL_READ, 903 sizeof (tempr_t), &high_shutdowns[i], 904 &proph); 905 if (err != PICL_SUCCESS) 906 break; 907 } 908 909 /* 910 * for the benefit of prtdiag, add a label of 911 * either enclosure or die where appropriate 912 */ 913 if ((strcasestr(lom_temp.name[i], CPU_ENCLOSURE) != 914 NULL) || 915 (strcasestr(lom_temp.name[i], CPU_AMBIENT) != 916 NULL)) { 917 cptr = CPU_AMBIENT; 918 } else if ((cptr = strcasestr(lom_temp.name[i], 919 CPU_DIE)) != NULL) { 920 cptr = CPU_DIE; 921 } 922 923 if (cptr != NULL) { 924 err = add_regular_prop( 925 tempsensh, PICL_PROP_LABEL, 926 PICL_PTYPE_CHARSTRING, PICL_READ, 927 strlen(cptr) + 1, cptr, &proph); 928 929 if (err != PICL_SUCCESS) { 930 break; 931 } 932 } 933 934 err = ptree_add_node(lominfh, tempsensh); 935 936 if (err != PICL_SUCCESS) 937 break; 938 } 939 940 if (err != PICL_SUCCESS) { 941 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED); 942 } 943 } 944 945 return (err); 946 } 947 948 static int 949 add_voltage_monitors(int lom_fd, picl_nodehdl_t lominfh) 950 { 951 int res; 952 int i; 953 int err = PICL_SUCCESS; 954 picl_prophdl_t proph; 955 956 res = ioctl(lom_fd, LOMIOCVOLTS, &voltsdata); 957 958 if ((res == 0) && (voltsdata.num > 0)) { 959 /* 960 * for each voltage monitor add a monitor node 961 */ 962 for (i = 0; i < voltsdata.num; i++) { 963 picl_nodehdl_t voltsmonh; 964 965 convert_node_name(voltsdata.name[i]); 966 967 err = ptree_create_node(voltsdata.name[i], 968 PICL_CLASS_VOLTAGE_INDICATOR, &voltsmonh); 969 if (err != PICL_SUCCESS) 970 break; 971 972 err = add_regular_prop(voltsmonh, PICL_PROP_LABEL, 973 PICL_PTYPE_CHARSTRING, PICL_READ, 974 strlen(voltsdata.name[i]) + 1, 975 voltsdata.name[i], &proph); 976 if (err != PICL_SUCCESS) 977 break; 978 979 err = add_volatile_prop(voltsmonh, PICL_VOLTS_SHUTDOWN, 980 PICL_PTYPE_CHARSTRING, PICL_READ, 981 sizeof (str_Disabled), read_vol_volts_shutdown, 982 NULL, &volts_shutdown_handles[i]); 983 if (err != PICL_SUCCESS) 984 break; 985 986 err = add_volatile_prop(voltsmonh, PICL_PROP_CONDITION, 987 PICL_PTYPE_CHARSTRING, PICL_READ, 988 sizeof (str_FAIL), read_vol_volts_status, NULL, 989 &volts_status_handles[i]); 990 if (err != PICL_SUCCESS) 991 break; 992 993 err = ptree_add_node(lominfh, voltsmonh); 994 995 if (err != PICL_SUCCESS) 996 break; 997 } 998 999 if (err != PICL_SUCCESS) { 1000 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED); 1001 } 1002 } 1003 1004 return (err); 1005 } 1006 1007 static void 1008 add_led(const lom_led_state_t *led_state, picl_nodehdl_t lominfh) 1009 { 1010 int err; 1011 picl_nodehdl_t ledh; 1012 picl_nodehdl_t proph; 1013 1014 if (((unsigned char)led_state->state == LOM_LED_STATE_NOT_PRESENT) || 1015 (led_state->label[0] == '\0')) { 1016 return; 1017 } 1018 1019 err = ptree_create_node(led_state->label, PICL_CLASS_LED, &ledh); 1020 /* 1021 * the led may exist already, e.g. Fault 1022 */ 1023 if (err != PICL_SUCCESS) 1024 return; 1025 1026 /* 1027 * Unlike LEDs derived from other interfaces, these are not 1028 * writable. Establish a read-only volatile property. 1029 */ 1030 err = add_volatile_prop(ledh, PICL_PROP_STATE, PICL_PTYPE_CHARSTRING, 1031 PICL_READ, max_state_size, read_led_status, NULL, 1032 &led_handles[led_state->index]); 1033 if (err != PICL_SUCCESS) 1034 return; 1035 1036 /* 1037 * if colour was defined for this LED, add a colour property 1038 */ 1039 if ((led_state->colour != LOM_LED_COLOUR_NONE) && 1040 (led_state->colour != LOM_LED_COLOUR_ANY)) { 1041 err = add_regular_prop(ledh, PICL_PROP_COLOR, 1042 PICL_PTYPE_CHARSTRING, PICL_READ, 1043 colour_lkup[led_state->index].size, 1044 colour_lkup[led_state->index].str_colour, &proph); 1045 } 1046 if (err != PICL_SUCCESS) 1047 return; 1048 1049 err = add_regular_prop(ledh, PICL_PROP_LABEL, 1050 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(led_state->label) + 1, 1051 led_state->label, &proph); 1052 if (err != PICL_SUCCESS) 1053 return; 1054 1055 err = ptree_add_node(lominfh, ledh); 1056 1057 if (err != PICL_SUCCESS) { 1058 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED); 1059 } 1060 } 1061 1062 static void 1063 fixstate(uint8_t state, const char *string, int *max_len) 1064 { 1065 int i; 1066 int len; 1067 1068 for (i = 0; i < (sizeof (ledstate_lkup) / sizeof (ledstate_lkup[0])); 1069 i++) { 1070 if (ledstate_lkup[i].state == state) { 1071 if (ledstate_lkup[i].str_ledstate != NULL) 1072 free(ledstate_lkup[i].str_ledstate); 1073 ledstate_lkup[i].str_ledstate = strdup(string); 1074 len = strlen(string); 1075 if (len >= *max_len) 1076 *max_len = len + 1; 1077 break; 1078 } 1079 } 1080 } 1081 1082 static void 1083 add_led_nodes(int lom_fd, picl_nodehdl_t lominfh) 1084 { 1085 lom_led_state_t led_data; 1086 picl_nodehdl_t ledh; 1087 int res; 1088 int i; 1089 1090 /* 1091 * If the led state enquiry ioctl is supported, an enquiry on 1092 * index -1 will return the state of the highest supported index 1093 * value. 1094 */ 1095 (void) memset(&led_data, 0, sizeof (led_data)); 1096 led_data.index = -1; 1097 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data); 1098 1099 if (res != 0) 1100 return; 1101 1102 if (led_labels != NULL) { 1103 for (i = 0; i < n_leds; i++) { 1104 if (led_labels[i] != NULL) { 1105 free(led_labels[i]); 1106 } 1107 } 1108 1109 free(led_labels); 1110 led_labels = NULL; 1111 } 1112 1113 if (led_handles != NULL) { 1114 free(led_handles); 1115 } 1116 1117 n_leds = 0; 1118 led_handles = calloc(led_data.index + 1, sizeof (picl_nodehdl_t)); 1119 led_labels = calloc(led_data.index + 1, sizeof (char *)); 1120 1121 if ((led_labels == NULL) || (led_handles == NULL)) { 1122 if (led_labels != NULL) 1123 free(led_labels); 1124 if (led_handles != NULL) 1125 free(led_handles); 1126 led_labels = NULL; 1127 led_handles = NULL; 1128 syslog(LOG_ERR, EM_NO_LED_MEM); 1129 return; 1130 } 1131 1132 n_leds = led_data.index + 1; 1133 1134 /* 1135 * For each LED with a valid state, add a node 1136 * and because of the ludicrous API, stache a copy of its label too 1137 */ 1138 for (i = 0; i < n_leds; i++) { 1139 (void) memset(&led_data, 0, sizeof (led_data)); 1140 led_data.index = i; 1141 res = ioctl(lom_fd, LOMIOCLEDSTATE, &led_data); 1142 1143 if (res != 0) 1144 continue; 1145 1146 if (led_data.state == LOM_LED_OUTOFRANGE || 1147 led_data.state == LOM_LED_NOT_IMPLEMENTED) 1148 continue; 1149 1150 1151 led_labels[i] = strdup(led_data.label); 1152 convert_node_name(led_data.label); 1153 1154 if (get_node_by_name_and_class(lominfh, led_data.label, 1155 "led", &ledh) != PICL_SUCCESS) { 1156 /* 1157 * only add a new led node, 1158 * if it's not already in place 1159 */ 1160 add_led(&led_data, lominfh); 1161 } 1162 } 1163 } 1164 1165 static int 1166 add_fan_nodes(int lom_fd, picl_nodehdl_t lominfh) 1167 { 1168 int res; 1169 int i; 1170 int err = PICL_SUCCESS; 1171 1172 res = ioctl(lom_fd, LOMIOCFANSTATE, &fandata); 1173 1174 if (res == 0) { 1175 /* 1176 * fan data available through lom, remove any placeholder 1177 * fan-unit nodes, they will be superseded via lom.conf 1178 */ 1179 char path[80]; 1180 int slot; 1181 picl_nodehdl_t fan_unit_h; 1182 1183 for (slot = 0; slot < MAX_FANS; slot++) { 1184 (void) snprintf(path, sizeof (path), 1185 "/frutree/chassis/fan-slot?Slot=%d/fan-unit", slot); 1186 if (ptree_get_node_by_path(path, &fan_unit_h) != 1187 PICL_SUCCESS) 1188 continue; 1189 if (ptree_delete_node(fan_unit_h) != PICL_SUCCESS) 1190 continue; 1191 (void) ptree_destroy_node(fan_unit_h); 1192 } 1193 /* 1194 * see if fan names can be obtained 1195 */ 1196 (void) memset(&info2data, 0, sizeof (info2data)); 1197 /* 1198 * if LOMIOCINFO2 not supported, names area 1199 * will remain empty 1200 */ 1201 (void) ioctl(lom_fd, LOMIOCINFO2, &info2data); 1202 1203 /* 1204 * for each fan which is present, add a fan node 1205 */ 1206 for (i = 0; i < MAX_FANS; i++) { 1207 char fanname[80]; 1208 picl_nodehdl_t fanh; 1209 picl_nodehdl_t proph; 1210 1211 if (fandata.fitted[i] == 0) 1212 continue; 1213 1214 if (info2data.fan_names[i][0] == '\0') { 1215 (void) snprintf(fanname, sizeof (fanname), 1216 "fan%d", i + 1); 1217 } else { 1218 (void) strlcpy(fanname, info2data.fan_names[i], 1219 sizeof (fanname)); 1220 } 1221 convert_node_name(fanname); 1222 err = ptree_create_node(fanname, PICL_CLASS_FAN, &fanh); 1223 if (err != PICL_SUCCESS) 1224 break; 1225 1226 err = add_volatile_prop(fanh, PICL_PROP_FAN_SPEED, 1227 PICL_PTYPE_INT, PICL_READ, sizeof (int), 1228 read_fan_speed, NULL, &fan_speed_handles[i]); 1229 if (err != PICL_SUCCESS) 1230 break; 1231 1232 err = add_regular_prop(fanh, PICL_PROP_LOW_WARNING, 1233 PICL_PTYPE_INT, PICL_READ, sizeof (int), 1234 &fandata.minspeed[i], &proph); 1235 if (err != PICL_SUCCESS) 1236 break; 1237 1238 err = add_regular_prop(fanh, PICL_PROP_FAN_SPEED_UNIT, 1239 PICL_PTYPE_CHARSTRING, PICL_READ, sizeof ("%"), 1240 "%", &proph); 1241 if (err != PICL_SUCCESS) 1242 break; 1243 1244 err = add_volatile_prop(fanh, PICL_PROP_CONDITION, 1245 PICL_PTYPE_CHARSTRING, PICL_READ, 1246 sizeof (str_FAIL), read_fan_status, NULL, 1247 &fan_status_handles[i]); 1248 if (err != PICL_SUCCESS) 1249 break; 1250 1251 /* 1252 * add a label for prtdiag 1253 */ 1254 err = add_regular_prop(fanh, PICL_PROP_LABEL, 1255 PICL_PTYPE_CHARSTRING, PICL_READ, 1256 strlen(fanname) + 1, fanname, &proph); 1257 if (err != PICL_SUCCESS) 1258 break; 1259 1260 err = ptree_add_node(lominfh, fanh); 1261 if (err != PICL_SUCCESS) 1262 break; 1263 } 1264 1265 if (err != PICL_SUCCESS) { 1266 syslog(LOG_ERR, EM_LOMINFO_TREE_FAILED); 1267 } 1268 } 1269 1270 return (err); 1271 } 1272 1273 static void 1274 setup_strings() 1275 { 1276 /* 1277 * initialise led colours lookup 1278 */ 1279 int i; 1280 int lim = sizeof (colour_lkup) / sizeof (colour_lkup[0]); 1281 1282 for (i = 0; i < lim; i++) { 1283 if (colour_lkup[i].str_colour != NULL) 1284 free(colour_lkup[i].str_colour); 1285 } 1286 1287 colour_lkup[LOM_LED_COLOUR_ANY].str_colour = strdup(gettext("any")); 1288 colour_lkup[LOM_LED_COLOUR_WHITE].str_colour = strdup(gettext("white")); 1289 colour_lkup[LOM_LED_COLOUR_BLUE].str_colour = strdup(gettext("blue")); 1290 colour_lkup[LOM_LED_COLOUR_GREEN].str_colour = strdup(gettext("green")); 1291 colour_lkup[LOM_LED_COLOUR_AMBER].str_colour = strdup(gettext("amber")); 1292 1293 for (i = 0; i < lim; i++) { 1294 if (colour_lkup[i].str_colour != NULL) 1295 colour_lkup[i].size = 1296 1 + strlen(colour_lkup[i].str_colour); 1297 } 1298 1299 /* 1300 * initialise led state lookup strings 1301 */ 1302 fixstate(LOM_LED_OFF, gettext("off"), &max_state_size); 1303 fixstate(LOM_LED_ON, gettext("on"), &max_state_size); 1304 fixstate(LOM_LED_BLINKING, gettext("blinking"), &max_state_size); 1305 } 1306 1307 /* 1308 * The size of outfilename must be PATH_MAX 1309 */ 1310 static int 1311 get_config_file(char *outfilename) 1312 { 1313 char nmbuf[SYS_NMLN]; 1314 char pname[PATH_MAX]; 1315 1316 if (sysinfo(SI_PLATFORM, nmbuf, sizeof (nmbuf)) != -1) { 1317 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 1318 (void) strlcat(pname, LOM_CONFFILE_NAME, PATH_MAX); 1319 if (access(pname, R_OK) == 0) { 1320 (void) strlcpy(outfilename, pname, PATH_MAX); 1321 return (0); 1322 } 1323 } 1324 1325 if (sysinfo(SI_MACHINE, nmbuf, sizeof (nmbuf)) != -1) { 1326 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 1327 (void) strlcat(pname, LOM_CONFFILE_NAME, PATH_MAX); 1328 if (access(pname, R_OK) == 0) { 1329 (void) strlcpy(outfilename, pname, PATH_MAX); 1330 return (0); 1331 } 1332 } 1333 1334 (void) snprintf(pname, PATH_MAX, "%s/%s", PICLD_COMMON_PLUGIN_DIR, 1335 LOM_CONFFILE_NAME); 1336 1337 if (access(pname, R_OK) == 0) { 1338 (void) strlcpy(outfilename, pname, PATH_MAX); 1339 return (0); 1340 } 1341 1342 return (-1); 1343 } 1344 1345 1346 1347 /* 1348 * executed as part of .init when the plugin is dlopen()ed 1349 */ 1350 static void 1351 picllom_register(void) 1352 { 1353 (void) picld_plugin_register(&my_reg_info); 1354 } 1355 1356 /* 1357 * Init entry point of the plugin 1358 * Creates the PICL nodes and properties in the physical and logical aspects. 1359 */ 1360 static void 1361 picllom_init(void) 1362 { 1363 picl_nodehdl_t rooth; 1364 picl_nodehdl_t plfh; 1365 picl_nodehdl_t lominfh; 1366 int lom_fd; 1367 char fullfilename[PATH_MAX]; 1368 1369 /* 1370 * Get platform node 1371 */ 1372 if (ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, &plfh) 1373 != PICL_SUCCESS) { 1374 syslog(LOG_ERR, EM_MISSING_NODE, PICL_NODE_PLATFORM); 1375 syslog(LOG_ERR, EM_INIT_FAILED); 1376 return; 1377 } 1378 1379 /* 1380 * Get lom node 1381 */ 1382 if (get_lom_node(&lominfh) != PICL_SUCCESS) { 1383 syslog(LOG_ERR, EM_LOM_NODE_MISSING); 1384 syslog(LOG_ERR, EM_INIT_FAILED); 1385 return; 1386 } 1387 1388 /* 1389 * Retrive the device path to open 1390 */ 1391 if (get_lom_device_path(&lominfh) < 0) { 1392 syslog(LOG_ERR, EM_INIT_FAILED); 1393 return; 1394 } 1395 1396 /* 1397 * Open LOM device and interrogate for devices it monitors 1398 */ 1399 if ((lom_fd = open(lom_device_path, O_RDONLY)) < 0) { 1400 syslog(LOG_ERR, EM_SYS_ERR, lom_device_path, strerror(errno)); 1401 return; 1402 } 1403 1404 setup_strings(); 1405 (void) add_temp_sensors(lom_fd, lominfh); 1406 (void) add_voltage_monitors(lom_fd, lominfh); 1407 (void) add_fan_nodes(lom_fd, lominfh); 1408 add_led_nodes(lom_fd, lominfh); 1409 1410 1411 if (get_config_file(fullfilename) < 0) { 1412 (void) close(lom_fd); 1413 syslog(LOG_ERR, EM_NO_CONFIG); 1414 return; 1415 } 1416 1417 if (ptree_get_root(&rooth) != PICL_SUCCESS) { 1418 (void) close(lom_fd); 1419 return; 1420 } 1421 1422 if (picld_pluginutil_parse_config_file(rooth, fullfilename) != 1423 PICL_SUCCESS) 1424 syslog(LOG_ERR, EM_INIT_FAILED); 1425 1426 (void) close(lom_fd); 1427 } 1428 1429 /* 1430 * fini entry point of the plugin 1431 */ 1432 static void 1433 picllom_fini(void) 1434 { 1435 } 1436