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 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 #include <stdio.h> 30 #include <stddef.h> 31 #include <syslog.h> 32 #include <strings.h> 33 #include <unistd.h> 34 #include <libintl.h> 35 #include <stdlib.h> 36 #include <ctype.h> 37 #include <picl.h> 38 #include <picltree.h> 39 #include <picld_pluginutil.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <fcntl.h> 43 #include <dirent.h> 44 #include <sys/sysevent/dr.h> 45 #include <pthread.h> 46 #include <libdevinfo.h> 47 #include <limits.h> 48 #include <sys/systeminfo.h> 49 #include <sys/envmon.h> 50 #include <i2c_gpio.h> 51 #include "libdevice.h" 52 #include "picldefs.h" 53 #include <sys/raidioctl.h> 54 #include <sys/param.h> 55 56 /* 57 * Plugin registration entry points 58 */ 59 static void piclfrudr_register(void); 60 static void piclfrudr_init(void); 61 static void piclfrudr_fini(void); 62 #pragma init(piclfrudr_register) 63 64 static picld_plugin_reg_t my_reg_info = { 65 PICLD_PLUGIN_VERSION_1, 66 PICLD_PLUGIN_CRITICAL, 67 "SUNW_MPXU_frudr", 68 piclfrudr_init, 69 piclfrudr_fini, 70 }; 71 72 /* 73 * Log message texts 74 */ 75 #define EM_THREAD_CREATE_FAILED gettext("piclfrudr: pthread_create failed: %s") 76 #define DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d") 77 #define EM_DI_INIT_FAIL gettext("piclfrudr: di_init failed: %s") 78 #define PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d") 79 #define ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d") 80 #define ADD_TBL_ENTRY_FAIL gettext("piclfrudr: cannot add entry to table") 81 #define EM_POLL_FAIL gettext("piclfrudr: poll() failed: %s") 82 #define ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d") 83 #define EM_MUTEX_FAIL gettext("piclfrudr: pthread_mutex_lock returned: %s") 84 #define EM_UNK_FRU gettext("piclfrudr: Fru removed event for unknown node") 85 #define PARSE_CONF_FAIL gettext("parse config file %s failed") 86 #define EM_NO_SC_DEV gettext("piclfrudr: failed to locate SC device node") 87 #define EM_NO_SYSINFO gettext("piclfrudr: failed to get SC sysinfo: %s") 88 89 /* 90 * PICL property values 91 */ 92 #define PICL_PROPVAL_ON "ON" 93 #define PICL_PROPVAL_OFF "OFF" 94 95 /* 96 * Local defines 97 */ 98 #define SEEPROM_DRIVER_NAME "seeprom" 99 #define FRUTREE_PATH "/frutree" 100 #define CHASSIS_LOC_PATH "/frutree/chassis/%s" 101 #define SYS_BOARD_PATH "/frutree/chassis/MB/system-board/%s" 102 #define CONFFILE_PREFIX "fru_" 103 #define CONFFILE_SUFFIX ".conf" 104 #define CONFFILE_FRUTREE "piclfrutree.conf" 105 #define PS_NAME "PS" 106 #define PS_NAME_LEN 2 107 #define PS_FRU_NAME "power-supply" 108 #define PS_PLATFORM_NAME "power-supply-fru-prom" 109 #define DISK_NAME "HDD" 110 #define DISK_NAME_LEN 3 111 #define DISK_FRU_NAME "disk" 112 #define SCC_NAME "SCC" 113 #define SCC_NAME_LEN 3 114 #define SCC_FRU_NAME "scc" 115 #define RMC_NAME "SC" 116 #define RMC_NAME_LEN 2 117 #define RMC_FRU_NAME "sc" 118 #define DEV_PREFIX "/devices" 119 #define ENXS_FRONT_SRVC_LED 0x20 120 #define ENXS_FRONT_ACT_LED 0x10 121 #define ENXS_REAR_SRVC_LED 0x20 122 #define ENXS_REAR_ACT_LED 0x10 123 #define ENTS_SRVC_LED 0x20 124 #define ENTS_ACT_LED 0x10 125 #define V440_SRVC_LED 0x2 126 #define V440_ACT_LED 0x1 127 128 /* 129 * PSU defines 130 */ 131 #define PSU_I2C_BUS_DEV "/devices/pci@1e,600000/isa@7/i2c@0,320:devctl" 132 #define PSU_DEV \ 133 "/devices/pci@1e,600000/isa@7/i2c@0,320/power-supply-fru-prom@0,%x" 134 #define PSU_PLATFORM "/platform/pci@1e,600000/isa@7/i2c@0,320" 135 #define PS0_ADDR ((sys_platform == PLAT_CHALUPA19) ? 0xc0 : 0xb0) 136 #define PS1_ADDR ((sys_platform == PLAT_CHALUPA19) ? 0xc2 : 0xa4) 137 #define PS2_ADDR 0x70 138 #define PS3_ADDR 0x72 139 #define PS0_UNITADDR ((sys_platform == PLAT_CHALUPA19) ? "0,c0" : "0,b0") 140 #define PS1_UNITADDR ((sys_platform == PLAT_CHALUPA19) ? "0,c2" : "0,a4") 141 #define PS2_UNITADDR "0,70" 142 #define PS3_UNITADDR "0,72" 143 #define PS0_NAME "PS0" 144 #define PS1_NAME "PS1" 145 #define PS2_NAME "PS2" 146 #define PS3_NAME "PS3" 147 #define PSU0_NAME "PSU0" 148 #define PSU1_NAME "PSU1" 149 #define PSU2_NAME "PSU2" 150 #define PSU3_NAME "PSU3" 151 #define PS_DEVICE_NAME "power-supply-fru-prom" 152 153 /* 154 * disk defines 155 */ 156 #define REMOK_LED "OK2RM" 157 #define FAULT_LED "SERVICE" 158 #define PLATFORMLEN 9 159 #define N_DISKS 8 160 #define N_CHALUPA_DISKS 4 161 #define N_ENTS_DISKS 8 162 #define N_MPXU_DISKS 4 163 #define N_EN19_DISKS 2 164 #define DISK_POLL_TIME 5000 165 /* For V440 RAID policy */ 166 #define V440_DISK_DEVCTL "/devices/pci@1f,700000/scsi@2:devctl" 167 168 /* 169 * led defines 170 */ 171 #define ENXS_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/" 172 #define ENXS_FRONT_LEDS "gpio@0,70:" 173 #define ENXS_REAR_LEDS ENXS_LED_DIR "gpio@0,44:port_1" 174 175 #define ENTS_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/" 176 #define ENTS_LEDS "gpio@0,70:" 177 178 #define V440_LED_DIR "/devices/pci@1e,600000/isa@7/i2c@0,320/" 179 #define V440_LED_PATH V440_LED_DIR "gpio@0,48:port_0" 180 181 typedef struct id_props { 182 envmon_handle_t envhandle; 183 picl_prophdl_t volprop; 184 } id_props_t; 185 186 typedef struct idp_lkup { 187 int maxnum; /* entries in array */ 188 int num; /* entries in use */ 189 id_props_t idp[1]; 190 } idp_lkup_t; 191 192 /* 193 * table for mapping RMC handles to volatile property handles 194 */ 195 static idp_lkup_t *idprop = NULL; 196 197 /* 198 * path names to system-controller device and fault led gpio 199 */ 200 static char *sc_device_name = NULL; 201 static char *bezel_leds = NULL; 202 203 /* 204 * disk data 205 */ 206 static int disk_ready[N_DISKS]; 207 static char *disk_name[N_DISKS] = { "HDD0", "HDD1", "HDD2", "HDD3", 208 "HDD4", "HDD5", "HDD6", "HDD7" }; 209 static volatile boolean_t disk_leds_thread_ack = B_FALSE; 210 static volatile boolean_t disk_leds_thread_running = B_FALSE; 211 static pthread_t ledsthr_tid; 212 static pthread_attr_t ledsthr_attr; 213 static boolean_t ledsthr_created = B_FALSE; 214 static boolean_t g_mutex_init = B_FALSE; 215 static pthread_cond_t g_cv; 216 static pthread_cond_t g_cv_ack; 217 static pthread_mutex_t g_mutex; 218 static volatile boolean_t g_finish_now = B_FALSE; 219 220 /* 221 * static strings 222 */ 223 static const char str_devfs_path[] = "devfs-path"; 224 225 /* 226 * OperationalStatus property values 227 */ 228 static const char str_opst_present[] = "present"; 229 static const char str_opst_ok[] = "okay"; 230 static const char str_opst_faulty[] = "faulty"; 231 static const char str_opst_download[] = "download"; 232 static const char str_opst_unknown[] = "unknown"; 233 static size_t max_opst_len = sizeof (str_opst_download); 234 235 /* 236 * forward reference 237 */ 238 static void opst_init(void); 239 static void add_op_status_by_name(const char *name, const char *child_name, 240 picl_prophdl_t *prophdl_p); 241 static void add_op_status_to_node(picl_nodehdl_t nodeh, 242 picl_prophdl_t *prophdl_p); 243 static int read_vol_data(ptree_rarg_t *r_arg, void *buf); 244 static int find_picl_handle(picl_prophdl_t proph); 245 static void disk_leds_init(void); 246 static void disk_leds_fini(void); 247 static void *disk_leds_thread(void *args); 248 static picl_nodehdl_t find_child_by_name(picl_nodehdl_t parh, char *name); 249 static void post_frudr_event(char *ename, picl_nodehdl_t parenth, 250 picl_nodehdl_t fruh); 251 static int add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name); 252 static void remove_fru_parents(picl_nodehdl_t fruh); 253 static int get_node_by_class(picl_nodehdl_t nodeh, const char *classname, 254 picl_nodehdl_t *foundnodeh); 255 static int get_sys_controller_node(picl_nodehdl_t *nodeh); 256 static char *create_sys_controller_pathname(picl_nodehdl_t sysconh); 257 static char *create_bezel_leds_pathname(const char *dirpath, 258 const char *devname); 259 static void frudr_evhandler(const char *ename, const void *earg, 260 size_t size, void *cookie); 261 static void fru_add_handler(const char *ename, const void *earg, 262 size_t size, void *cookie); 263 static void frutree_evhandler(const char *ename, const void *earg, 264 size_t size, void *cookie); 265 static int create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, 266 char *tbl_name); 267 static int create_table_entry(picl_prophdl_t tblhdl, 268 picl_nodehdl_t refhdl, char *class); 269 static int create_i2c_node(char *ap_id); 270 static void delete_i2c_node(char *ap_id); 271 static int set_led(char *name, char *ptr, char *value); 272 static int ps_name_to_addr(char *name); 273 static char *ps_name_to_unitaddr(char *name); 274 static char *ps_apid_to_nodename(char *apid); 275 static void add_op_status(envmon_hpu_t *hpu, int *index); 276 277 #define sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2) 278 279 /* 280 * Because this plugin is shared across different platforms, we need to 281 * distinguish for certain functionality 282 */ 283 #define PLAT_UNKNOWN (-1) 284 #define PLAT_ENXS 0 285 #define PLAT_ENTS 1 286 #define PLAT_CHALUPA 2 287 #define PLAT_EN19 3 288 #define PLAT_CHALUPA19 4 289 #define PLAT_SALSA19 5 290 291 static int sys_platform; 292 293 static void 294 get_platform() 295 { 296 char platform[64]; 297 (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); 298 if (strcmp(platform, "SUNW,Sun-Fire-V250") == 0) 299 sys_platform = PLAT_ENTS; 300 else if (strcmp(platform, "SUNW,Sun-Fire-V440") == 0) 301 sys_platform = PLAT_CHALUPA; 302 else if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) 303 sys_platform = PLAT_ENXS; 304 else if (strcmp(platform, "SUNW,Sun-Fire-V240") == 0) 305 sys_platform = PLAT_ENXS; 306 else if (strcmp(platform, "SUNW,Netra-240") == 0) 307 sys_platform = PLAT_EN19; 308 else if (strcmp(platform, "SUNW,Netra-210") == 0) 309 sys_platform = PLAT_SALSA19; 310 else if (strcmp(platform, "SUNW,Netra-440") == 0) 311 sys_platform = PLAT_CHALUPA19; 312 else 313 sys_platform = PLAT_UNKNOWN; 314 } 315 316 /* 317 * This function is executed as part of .init when the plugin is 318 * dlopen()ed 319 */ 320 static void 321 piclfrudr_register(void) 322 { 323 (void) picld_plugin_register(&my_reg_info); 324 } 325 326 /* 327 * This function is the init entry point of the plugin. 328 * It initializes the /frutree tree 329 */ 330 static void 331 piclfrudr_init(void) 332 { 333 picl_nodehdl_t sc_nodeh; 334 picl_nodehdl_t locationh; 335 picl_nodehdl_t childh; 336 char namebuf[PATH_MAX]; 337 338 get_platform(); 339 340 if (sc_device_name != NULL) { 341 free(sc_device_name); /* must have reen restarted */ 342 sc_device_name = NULL; 343 } 344 345 if ((get_sys_controller_node(&sc_nodeh) != PICL_SUCCESS) || 346 ((sc_device_name = create_sys_controller_pathname(sc_nodeh)) == 347 NULL)) 348 syslog(LOG_ERR, EM_NO_SC_DEV); 349 350 opst_init(); 351 disk_leds_init(); 352 353 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE, 354 frudr_evhandler, NULL); 355 (void) ptree_register_handler(PICL_FRU_ADDED, fru_add_handler, NULL); 356 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED, 357 frutree_evhandler, NULL); 358 359 /* 360 * There is a window of opportunity for the RMC to deliver an event 361 * indicating a newly operable state just before we are listening for 362 * it. In this case, envmon will have missed setting up /platform 363 * and won't get a signal from frudr. So send it a PICL_FRU_ADDED just 364 * in case. 365 */ 366 367 if ((sys_platform == PLAT_CHALUPA) || 368 (sys_platform == PLAT_CHALUPA19)) { 369 sprintf_buf2(namebuf, CHASSIS_LOC_PATH, RMC_NAME); 370 } else { 371 sprintf_buf2(namebuf, SYS_BOARD_PATH, RMC_NAME); 372 } 373 374 if (ptree_get_node_by_path(namebuf, &locationh) != PICL_SUCCESS) 375 return; 376 if (ptree_get_propval_by_name(locationh, PICL_PROP_CHILD, 377 &childh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) 378 return; 379 post_frudr_event(PICL_FRU_ADDED, locationh, childh); 380 } 381 382 static void 383 add_op_status_by_name(const char *name, const char *child_name, 384 picl_prophdl_t *prophdl_p) 385 { 386 picl_nodehdl_t nodeh; 387 388 if (ptree_get_node_by_path(name, &nodeh) != PICL_SUCCESS) { 389 return; 390 } 391 392 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, 393 &nodeh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) { 394 395 if (child_name == NULL) 396 return; 397 /* 398 * create fru node of supplied name 399 */ 400 if (ptree_create_and_add_node(nodeh, child_name, 401 PICL_CLASS_FRU, &nodeh) != PICL_SUCCESS) 402 return; 403 } 404 405 add_op_status_to_node(nodeh, prophdl_p); 406 } 407 408 /* 409 * function to add a volatile property to a specified node 410 */ 411 static void 412 add_op_status_to_node(picl_nodehdl_t nodeh, picl_prophdl_t *prophdl_p) 413 { 414 int err; 415 ptree_propinfo_t info; 416 picl_prophdl_t proph; 417 418 err = ptree_init_propinfo(&info, PTREE_PROPINFO_VERSION, 419 PICL_PTYPE_CHARSTRING, PICL_VOLATILE | PICL_READ, max_opst_len, 420 PICL_PROP_OPERATIONAL_STATUS, read_vol_data, NULL); 421 422 if (err == PICL_SUCCESS) { 423 if (ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS, 424 &proph) == PICL_SUCCESS) { 425 if (ptree_delete_prop(proph) == PICL_SUCCESS) 426 err = ptree_destroy_prop(proph); 427 } 428 } 429 430 if ((err != PICL_SUCCESS) || ((err = ptree_create_and_add_prop(nodeh, 431 &info, NULL, prophdl_p)) != PICL_SUCCESS)) { 432 syslog(LOG_ERR, ADD_PROP_FAIL, PICL_PROP_OPERATIONAL_STATUS, 433 err); 434 return; 435 } 436 } 437 438 /* 439 * Deliver volatile property value. 440 * prtpicl gets very upset if we fail this command, so if the property 441 * cannot be retrieved, return a status of unknown. 442 */ 443 static int 444 read_vol_data(ptree_rarg_t *r_arg, void *buf) 445 { 446 picl_prophdl_t proph; 447 int index; 448 int envmon_fd; 449 int err; 450 envmon_hpu_t data; 451 452 proph = r_arg->proph; 453 index = find_picl_handle(proph); 454 455 if (index < 0) { 456 /* 457 * We drop memory of PSU op status handles in opst_init() 458 * when we get an RMC faulty event. We cannot access the 459 * status info in this circumstance, so returning "unknown" 460 * is appropriate. 461 */ 462 (void) strlcpy(buf, str_opst_unknown, max_opst_len); 463 return (PICL_SUCCESS); 464 } 465 466 envmon_fd = open(sc_device_name, O_RDONLY); 467 468 if (envmon_fd < 0) { 469 /* 470 * To get this far we must have succeeded with an earlier 471 * open, so this is an unlikely failure. It would be more 472 * helpful to indicate the nature of the failure, but we 473 * don't have the space to say much. Just return "unknown". 474 */ 475 (void) strlcpy(buf, str_opst_unknown, max_opst_len); 476 return (PICL_SUCCESS); 477 } 478 479 data.id = idprop->idp[index].envhandle; 480 err = ioctl(envmon_fd, ENVMONIOCHPU, &data); 481 482 if (err < 0) { 483 /* 484 * If we can't read the stats, "unknown" is a reasonable 485 * status to return. This one really shouldn't happen. 486 */ 487 (void) strlcpy(buf, str_opst_unknown, max_opst_len); 488 (void) close(envmon_fd); 489 return (PICL_SUCCESS); 490 } 491 492 (void) close(envmon_fd); 493 494 if (strncmp(data.id.name, DISK_NAME, DISK_NAME_LEN) == 0 && 495 data.fru_status == ENVMON_FRU_PRESENT) { 496 (void) strlcpy(buf, str_opst_present, max_opst_len); 497 return (PICL_SUCCESS); 498 } 499 500 if (data.sensor_status != ENVMON_SENSOR_OK) { 501 (void) strlcpy(buf, str_opst_unknown, max_opst_len); 502 return (PICL_SUCCESS); 503 } 504 505 (void) strlcpy(buf, 506 data.fru_status == ENVMON_FRU_PRESENT ? str_opst_ok : 507 data.fru_status == ENVMON_FRU_DOWNLOAD ? str_opst_download : 508 data.fru_status == ENVMON_FRU_FAULT ? str_opst_faulty : 509 str_opst_unknown, max_opst_len); 510 511 return (PICL_SUCCESS); 512 } 513 514 /* 515 * Function for explicitly turning on system leds 516 * for a failed/degraded RMC (SC). 517 */ 518 static void 519 solaris_setleds(const char *led_path, int leds) 520 { 521 i2c_gpio_t gpio; 522 int fd = open(led_path, O_RDWR); 523 524 if (fd < 0) 525 return; 526 527 gpio.reg_val = (leds ^ 0xff); 528 gpio.reg_mask = 0xffffffff; 529 if (ioctl(fd, GPIO_SET_CONFIG, &gpio) == 0) { 530 gpio.reg_val = (leds ^ 0xff); 531 gpio.reg_mask = 0xffffffff; 532 (void) ioctl(fd, GPIO_SET_OUTPUT, &gpio); 533 } 534 (void) close(fd); 535 } 536 537 static void 538 rmc_state_event(void) 539 { 540 envmon_hpu_t hpu; 541 int res; 542 int fd = open(sc_device_name, O_RDONLY); 543 544 if (fd < 0) 545 return; 546 547 (void) strlcpy(hpu.id.name, RMC_NAME, sizeof (hpu.id.name)); 548 res = ioctl(fd, ENVMONIOCHPU, &hpu); 549 (void) close(fd); 550 551 if ((res == 0) && (hpu.sensor_status == ENVMON_SENSOR_OK) && 552 ((hpu.fru_status & ENVMON_FRU_FAULT) != 0)) { 553 /* 554 * SC failed event - light the service led 555 * note that as Solaris is still running, 556 * the Solaris active led should be lit too. 557 */ 558 switch (sys_platform) { 559 case PLAT_ENXS: 560 case PLAT_SALSA19: 561 case PLAT_EN19: 562 solaris_setleds(ENXS_REAR_LEDS, 563 ENXS_REAR_SRVC_LED | ENXS_REAR_ACT_LED); 564 /* 565 * the device name for the bezel leds GPIO device 566 * tends to vary from Unix to Unix. Search for it. 567 */ 568 if (bezel_leds == NULL) { 569 bezel_leds = 570 create_bezel_leds_pathname(ENXS_LED_DIR, 571 ENXS_FRONT_LEDS); 572 } 573 if (bezel_leds == NULL) 574 return; 575 solaris_setleds(bezel_leds, 576 ENXS_FRONT_SRVC_LED | ENXS_FRONT_ACT_LED); 577 break; 578 case PLAT_ENTS: 579 /* 580 * the device name for the system leds gpio can vary 581 * as there are several similar gpio devices. Search 582 * for one with the desired address. 583 */ 584 if (bezel_leds == NULL) { 585 bezel_leds = 586 create_bezel_leds_pathname(ENTS_LED_DIR, 587 ENTS_LEDS); 588 } 589 if (bezel_leds == NULL) 590 return; 591 solaris_setleds(bezel_leds, 592 ENTS_SRVC_LED | ENTS_ACT_LED); 593 break; 594 case PLAT_CHALUPA: 595 case PLAT_CHALUPA19: 596 solaris_setleds(V440_LED_PATH, 597 V440_SRVC_LED | V440_ACT_LED); 598 break; 599 default: 600 break; 601 } 602 } 603 } 604 605 static int 606 find_picl_handle(picl_prophdl_t proph) 607 { 608 int index; 609 610 if (idprop == NULL) 611 return (-1); 612 613 for (index = 0; index < idprop->num; index++) { 614 if (idprop->idp[index].volprop == proph) 615 return (index); 616 } 617 618 return (-1); 619 } 620 621 static int 622 find_vol_prop_by_name(const char *name) 623 { 624 int index; 625 626 if (idprop == NULL) 627 return (-1); 628 629 for (index = 0; index < idprop->num; index++) { 630 if (strcmp(idprop->idp[index].envhandle.name, name) == 0) 631 return (index); 632 } 633 634 return (-1); 635 } 636 637 /* 638 * This function is the fini entry point of the plugin. 639 */ 640 static void 641 piclfrudr_fini(void) 642 { 643 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE, 644 frudr_evhandler, NULL); 645 (void) ptree_unregister_handler(PICL_FRU_ADDED, fru_add_handler, 646 NULL); 647 disk_leds_fini(); 648 if (idprop != NULL) { 649 free(idprop); 650 idprop = NULL; 651 } 652 if (sc_device_name != NULL) { 653 free(sc_device_name); 654 sc_device_name = NULL; 655 } 656 } 657 658 /* 659 * subroutine for various functions. Finds immediate child of parh with 660 * requested name if present. Otherwise returns NULL. 661 */ 662 static picl_nodehdl_t 663 find_child_by_name(picl_nodehdl_t parh, char *name) 664 { 665 picl_nodehdl_t nodeh; 666 int err; 667 char nodename[PICL_PROPNAMELEN_MAX]; 668 669 err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD, 670 &nodeh, sizeof (picl_nodehdl_t)); 671 if (err != PICL_SUCCESS) 672 return (NULL); 673 for (;;) { 674 err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename, 675 sizeof (nodename)); 676 if (err != PICL_SUCCESS) 677 return (NULL); 678 if (strcmp(name, nodename) == 0) { 679 return (nodeh); 680 } 681 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, 682 &nodeh, sizeof (picl_nodehdl_t)); 683 if (err != PICL_SUCCESS) 684 return (NULL); 685 } 686 } 687 688 /* Creates a reference property for a given PICL node */ 689 static int 690 add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name) 691 { 692 picl_prophdl_t proph; 693 ptree_propinfo_t propinfo; 694 int err; 695 696 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 697 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name, 698 NULL, NULL); 699 if (err != PICL_SUCCESS) { 700 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 701 return (err); 702 } 703 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph); 704 if (err != PICL_SUCCESS) { 705 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 706 return (err); 707 } 708 return (PICL_SUCCESS); 709 } 710 711 /* create an entry in the specified table */ 712 static int 713 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class) 714 { 715 int err; 716 ptree_propinfo_t prop; 717 picl_prophdl_t prophdl[2]; 718 719 /* first column is class */ 720 prop.version = PTREE_PROPINFO_VERSION; 721 prop.piclinfo.type = PICL_PTYPE_CHARSTRING; 722 prop.piclinfo.accessmode = PICL_READ; 723 prop.piclinfo.size = PICL_CLASSNAMELEN_MAX; 724 prop.read = NULL; 725 prop.write = NULL; 726 (void) strlcpy(prop.piclinfo.name, PICL_PROP_CLASS, 727 sizeof (prop.piclinfo.name)); 728 err = ptree_create_prop(&prop, class, &prophdl[0]); 729 if (err != PICL_SUCCESS) { 730 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err); 731 return (err); 732 } 733 734 /* second column is reference property */ 735 prop.version = PTREE_PROPINFO_VERSION; 736 prop.piclinfo.type = PICL_PTYPE_REFERENCE; 737 prop.piclinfo.accessmode = PICL_READ; 738 prop.piclinfo.size = sizeof (picl_nodehdl_t); 739 prop.read = NULL; 740 prop.write = NULL; 741 sprintf_buf2(prop.piclinfo.name, "_%s_", class); 742 err = ptree_create_prop(&prop, &refhdl, &prophdl[1]); 743 if (err != PICL_SUCCESS) { 744 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err); 745 return (err); 746 } 747 748 /* add row to table */ 749 err = ptree_add_row_to_table(tblhdl, 2, prophdl); 750 if (err != PICL_SUCCESS) 751 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err); 752 return (err); 753 } 754 755 /* create an empty table property */ 756 static int 757 create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name) 758 { 759 int err; 760 ptree_propinfo_t prop; 761 picl_prophdl_t tblprophdl; 762 763 err = ptree_create_table(tblhdlp); 764 if (err != PICL_SUCCESS) { 765 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err); 766 return (err); 767 } 768 prop.version = PTREE_PROPINFO_VERSION; 769 prop.piclinfo.type = PICL_PTYPE_TABLE; 770 prop.piclinfo.accessmode = PICL_READ; 771 prop.piclinfo.size = sizeof (picl_prophdl_t); 772 prop.read = NULL; 773 prop.write = NULL; 774 (void) strlcpy(prop.piclinfo.name, tbl_name, 775 sizeof (prop.piclinfo.name)); 776 err = ptree_create_and_add_prop(fruhdl, &prop, tblhdlp, &tblprophdl); 777 if (err != PICL_SUCCESS) 778 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err); 779 return (err); 780 } 781 782 /* 783 * The size of outfilename must be PATH_MAX 784 */ 785 static int 786 get_config_file(char *outfilename, char *fru) 787 { 788 char nmbuf[SYS_NMLN]; 789 char pname[PATH_MAX]; 790 int dir; 791 792 for (dir = 0; dir < 2; dir++) { 793 if (sysinfo(dir == 0 ? SI_PLATFORM : SI_MACHINE, 794 nmbuf, sizeof (nmbuf)) == -1) { 795 continue; 796 } 797 798 (void) snprintf(pname, PATH_MAX, PICLD_PLAT_PLUGIN_DIRF, nmbuf); 799 (void) strlcat(pname, CONFFILE_PREFIX, PATH_MAX); 800 (void) strlcat(pname, fru, PATH_MAX); 801 (void) strlcat(pname, CONFFILE_SUFFIX, PATH_MAX); 802 803 if (access(pname, R_OK) == 0) { 804 (void) strlcpy(outfilename, pname, PATH_MAX); 805 return (0); 806 } 807 } 808 809 (void) snprintf(pname, PATH_MAX, "%s/%s%s%s", 810 PICLD_COMMON_PLUGIN_DIR, CONFFILE_PREFIX, fru, 811 CONFFILE_SUFFIX); 812 813 if (access(pname, R_OK) == 0) { 814 (void) strlcpy(outfilename, pname, PATH_MAX); 815 return (0); 816 } 817 818 return (-1); 819 } 820 821 static void 822 remove_fru_parents(picl_nodehdl_t fruh) 823 { 824 char name[MAXPATHLEN]; 825 int retval; 826 picl_nodehdl_t nodeh; 827 picl_prophdl_t tableh; 828 picl_prophdl_t tblh; 829 picl_prophdl_t fruph; 830 831 retval = ptree_get_propval_by_name(fruh, PICL_PROP_NAME, name, 832 sizeof (name)); 833 if (retval != PICL_SUCCESS) { 834 syslog(LOG_ERR, EM_UNK_FRU); 835 return; 836 } 837 retval = ptree_get_prop_by_name(fruh, PICL_PROP_DEVICES, 838 &tableh); 839 840 if (retval != PICL_SUCCESS) { 841 /* no Devices table, nothing to do */ 842 return; 843 } 844 845 /* 846 * follow all reference properties in the second 847 * column of the table and delete any _fru_parent node 848 * at the referenced node. 849 */ 850 retval = ptree_get_propval(tableh, &tblh, sizeof (tblh)); 851 if (retval != PICL_SUCCESS) { 852 /* can't get value of table property */ 853 return; 854 } 855 /* get first col, first row */ 856 retval = ptree_get_next_by_col(tblh, &tblh); 857 if (retval != PICL_SUCCESS) { 858 /* no rows? */ 859 return; 860 } 861 /* 862 * starting at next col, get every entry in the column 863 */ 864 for (retval = ptree_get_next_by_row(tblh, &tblh); 865 retval == PICL_SUCCESS; 866 retval = ptree_get_next_by_col(tblh, &tblh)) { 867 /* 868 * should be a ref prop in our hands, 869 * get the target node handle 870 */ 871 retval = ptree_get_propval(tblh, &nodeh, 872 sizeof (nodeh)); 873 if (retval != PICL_SUCCESS) { 874 continue; 875 } 876 /* 877 * got the referenced node, has it got a 878 * _fru_parent property? 879 */ 880 retval = ptree_get_prop_by_name(nodeh, 881 PICL_REFPROP_FRU_PARENT, &fruph); 882 if (retval != PICL_SUCCESS) { 883 continue; 884 } 885 /* 886 * got a _fru_parent node reference delete it 887 */ 888 retval = ptree_delete_prop(fruph); 889 if (retval != PICL_SUCCESS) { 890 continue; 891 } 892 retval = ptree_destroy_prop(fruph); 893 if (retval != PICL_SUCCESS) { 894 continue; 895 } 896 } 897 } 898 899 static void 900 remove_tables(picl_nodehdl_t rootnd) 901 { 902 picl_nodehdl_t tableh; 903 int retval; 904 905 retval = ptree_get_prop_by_name(rootnd, PICL_PROP_DEVICES, &tableh); 906 907 if (retval == PICL_SUCCESS) { 908 /* 909 * found a Devices property, delete it 910 */ 911 if ((retval = ptree_delete_prop(tableh)) == PICL_SUCCESS) { 912 (void) ptree_destroy_prop(tableh); 913 } 914 } 915 916 /* 917 * is there a child node? 918 */ 919 retval = ptree_get_propval_by_name(rootnd, PICL_PROP_CHILD, &rootnd, 920 sizeof (rootnd)); 921 922 while (retval == PICL_SUCCESS) { 923 924 remove_tables(rootnd); 925 926 /* 927 * any siblings? 928 */ 929 retval = ptree_get_propval_by_name(rootnd, PICL_PROP_PEER, 930 &rootnd, sizeof (rootnd)); 931 } 932 } 933 934 /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */ 935 static void 936 frudr_completion_handler(char *ename, void *earg, size_t size) 937 { 938 picl_nodehdl_t fruh; 939 picl_nodehdl_t childh; 940 char nodename[PICL_PROPNAMELEN_MAX]; 941 int err; 942 943 if (strcmp(ename, PICL_FRU_REMOVED) == 0) { 944 /* 945 * now frudata has been notified that the node is to be 946 * removed, we can actually remove it 947 */ 948 fruh = NULL; 949 (void) nvlist_lookup_uint64(earg, 950 PICLEVENTARG_FRUHANDLE, &fruh); 951 if (fruh != NULL) { 952 /* 953 * first find name of the fru 954 */ 955 err = ptree_get_propval_by_name(fruh, PICL_PROP_PARENT, 956 &childh, sizeof (childh)); 957 if (err == PICL_SUCCESS) { 958 err = ptree_get_propval_by_name(childh, 959 PICL_PROP_NAME, nodename, 960 sizeof (nodename)); 961 } 962 if (err == PICL_SUCCESS) { 963 /* 964 * if it was a power supply, delete i2c node 965 */ 966 if (strncmp(nodename, PS_NAME, 967 PS_NAME_LEN) == 0) { 968 (void) delete_i2c_node(nodename); 969 } 970 971 /* 972 * is disk node, make thread re-evaluate led 973 * state 974 */ 975 if (strncmp(nodename, DISK_NAME, 976 DISK_NAME_LEN) == 0) { 977 disk_ready[nodename[DISK_NAME_LEN] - 978 '0'] = -1; 979 } 980 } 981 982 remove_fru_parents(fruh); 983 984 /* 985 * now we can delete the node 986 */ 987 err = ptree_delete_node(fruh); 988 if (err == PICL_SUCCESS) { 989 (void) ptree_destroy_node(fruh); 990 } else { 991 syslog(LOG_ERR, DELETE_PROP_FAIL, err); 992 } 993 } 994 } 995 nvlist_free(earg); 996 free(earg); 997 free(ename); 998 } 999 1000 /* 1001 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event 1002 */ 1003 static void 1004 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh) 1005 { 1006 nvlist_t *nvl; 1007 char *ev_name; 1008 1009 ev_name = strdup(ename); 1010 if (ev_name == NULL) 1011 return; 1012 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) { 1013 free(ev_name); 1014 return; 1015 } 1016 if (parenth != 0L && 1017 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) { 1018 free(ev_name); 1019 nvlist_free(nvl); 1020 return; 1021 } 1022 if (fruh != 0L && 1023 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) { 1024 free(ev_name); 1025 nvlist_free(nvl); 1026 return; 1027 } 1028 if (ptree_post_event(ev_name, nvl, sizeof (nvl), 1029 frudr_completion_handler) != 0) { 1030 free(ev_name); 1031 nvlist_free(nvl); 1032 } 1033 } 1034 1035 static void 1036 add_ps_to_platform(char *unit) 1037 { 1038 picl_nodehdl_t parent_hdl; 1039 picl_nodehdl_t child_hdl; 1040 ptree_propinfo_t info; 1041 int unit_size = 1 + strlen(unit); 1042 int res; 1043 char unit_addr[PICL_UNITADDR_LEN_MAX]; 1044 1045 if (ptree_get_node_by_path(PSU_PLATFORM, &parent_hdl) != PICL_SUCCESS) 1046 return; 1047 /* 1048 * seeprom nodes sit below this node, 1049 * is there one with the supplied unit address? 1050 */ 1051 res = ptree_get_propval_by_name(parent_hdl, PICL_PROP_CHILD, 1052 &child_hdl, sizeof (picl_nodehdl_t)); 1053 1054 while (res == PICL_SUCCESS) { 1055 res = ptree_get_propval_by_name(child_hdl, PICL_PROP_PEER, 1056 &child_hdl, sizeof (picl_nodehdl_t)); 1057 if ((res == PICL_SUCCESS) && 1058 ptree_get_propval_by_name(child_hdl, 1059 PICL_PROP_UNIT_ADDRESS, unit_addr, 1060 sizeof (unit_addr)) == PICL_SUCCESS) { 1061 unit_addr[sizeof (unit_addr) - 1] = '\0'; 1062 if (strcmp(unit_addr, unit) == 0) 1063 return; /* unit address exists already */ 1064 } 1065 } 1066 1067 /* 1068 * found platform location for PS seeprom node, create it 1069 */ 1070 if (ptree_create_and_add_node(parent_hdl, PS_PLATFORM_NAME, 1071 PICL_CLASS_SEEPROM, &child_hdl) != PICL_SUCCESS) 1072 return; 1073 if (ptree_init_propinfo(&info, PTREE_PROPINFO_VERSION, 1074 PICL_PTYPE_CHARSTRING, PICL_READ, unit_size, 1075 PICL_PROP_UNIT_ADDRESS, NULL, NULL) != PICL_SUCCESS) 1076 return; 1077 (void) ptree_create_and_add_prop(child_hdl, &info, unit, NULL); 1078 } 1079 1080 /* 1081 * handle EC_DR picl events 1082 */ 1083 /*ARGSUSED*/ 1084 static void 1085 frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie) 1086 { 1087 nvlist_t *nvlp; 1088 char *dtype; 1089 char *ap_id; 1090 char *hint; 1091 char path[MAXPATHLEN]; 1092 picl_nodehdl_t fruh; 1093 picl_nodehdl_t locnodeh; 1094 int err; 1095 int index; 1096 picl_nodehdl_t childh; 1097 char *fru_name; 1098 boolean_t rmc_flag = B_FALSE; 1099 1100 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0) { 1101 return; 1102 } 1103 1104 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) { 1105 return; 1106 } 1107 1108 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) { 1109 nvlist_free(nvlp); 1110 return; 1111 } 1112 1113 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) { 1114 nvlist_free(nvlp); 1115 return; 1116 } 1117 1118 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) { 1119 nvlist_free(nvlp); 1120 return; 1121 } 1122 1123 /* 1124 * check ap_id really is a hot-plug device 1125 */ 1126 if (strncmp(ap_id, PS_NAME, PS_NAME_LEN) == 0) { 1127 fru_name = PS_FRU_NAME; 1128 } else if (strncmp(ap_id, DISK_NAME, DISK_NAME_LEN) == 0) { 1129 fru_name = DISK_FRU_NAME; 1130 } else if (strncmp(ap_id, SCC_NAME, SCC_NAME_LEN) == 0) { 1131 fru_name = SCC_FRU_NAME; 1132 } else if (strncmp(ap_id, RMC_NAME, RMC_NAME_LEN) == 0) { 1133 fru_name = RMC_FRU_NAME; 1134 rmc_flag = B_TRUE; 1135 } else { 1136 nvlist_free(nvlp); 1137 return; 1138 } 1139 1140 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) { 1141 nvlist_free(nvlp); 1142 return; 1143 } 1144 1145 /* 1146 * OK - so this is an EC_DR event - let's handle it. 1147 */ 1148 if (rmc_flag && (sys_platform != PLAT_CHALUPA) && 1149 (sys_platform != PLAT_CHALUPA19)) 1150 sprintf_buf2(path, SYS_BOARD_PATH, ap_id); 1151 else { 1152 if ((sys_platform == PLAT_CHALUPA19) && 1153 (strncmp(ap_id, PS_NAME, PS_NAME_LEN) == 0)) { 1154 sprintf_buf2(path, CHASSIS_LOC_PATH, 1155 ps_apid_to_nodename(ap_id)); 1156 } 1157 else 1158 sprintf_buf2(path, CHASSIS_LOC_PATH, ap_id); 1159 } 1160 1161 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) { 1162 nvlist_free(nvlp); 1163 return; 1164 } 1165 1166 /* 1167 * now either add or delete the fru node as appropriate. If no 1168 * hint, treat as insert and update the tree if necessary. 1169 */ 1170 if (strcmp(hint, DR_HINT_REMOVE) == 0) { 1171 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD, 1172 &fruh, sizeof (picl_nodehdl_t)) == PICL_SUCCESS) { 1173 /* 1174 * fru was there - but has gone away 1175 */ 1176 post_frudr_event(PICL_FRU_REMOVED, NULL, fruh); 1177 } 1178 } else if (rmc_flag) { 1179 /* 1180 * An event on the RMC location, just pass it on 1181 * it's not really a PICL_FRU_ADDED event, so offer 1182 * the child handle as well (if it exists). 1183 */ 1184 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD, 1185 &fruh, sizeof (picl_nodehdl_t)) != PICL_SUCCESS) { 1186 fruh = NULL; 1187 } 1188 post_frudr_event(PICL_FRU_ADDED, locnodeh, fruh); 1189 } else { 1190 /* 1191 * fru has been inserted (or may need to update) 1192 * if node already there, then just return 1193 */ 1194 childh = find_child_by_name(locnodeh, fru_name); 1195 if (childh != NULL) { 1196 nvlist_free(nvlp); 1197 return; 1198 } 1199 1200 /* 1201 * create requested fru node 1202 */ 1203 err = ptree_create_and_add_node(locnodeh, fru_name, 1204 PICL_CLASS_FRU, &childh); 1205 if (err != PICL_SUCCESS) { 1206 syslog(LOG_ERR, ADD_NODE_FAIL, ap_id, err); 1207 nvlist_free(nvlp); 1208 return; 1209 } 1210 1211 /* 1212 * power supplies have operational status and fruid - 1213 * add OperationalStatus property and create i2c device node 1214 * before posting fru_added event 1215 */ 1216 if (strncmp(ap_id, PS_NAME, PS_NAME_LEN) == 0) { 1217 index = find_vol_prop_by_name( 1218 ps_apid_to_nodename(ap_id)); 1219 if (index >= 0) 1220 add_op_status_to_node(childh, 1221 &idprop->idp[index].volprop); 1222 (void) create_i2c_node(ap_id); 1223 add_ps_to_platform(ps_name_to_unitaddr(ap_id)); 1224 } 1225 1226 /* 1227 * now post event 1228 */ 1229 post_frudr_event(PICL_FRU_ADDED, locnodeh, NULL); 1230 } 1231 nvlist_free(nvlp); 1232 } 1233 1234 /* 1235 * Handle PICL_FRU_ADDED events. 1236 * These events are posted by the frudr_evhandler of this plugin in response to 1237 * PICLEVENT_DR_AP_STATE_CHANGE events. The sequence is as follows: 1238 * 1) frudr_evhandler catches PICLEVENT_DR_AP_STATE_CHANGE and creates a 1239 * child node below the relevant location. 1240 * 2) frudr_evhandler posts a PICL_FRU_ADDED event. 1241 * 3) envmon catches PICL_FRU_ADDED event, gropes the RMC configuration 1242 * and creates platform tree nodes (primarily for PSUs). (If the event 1243 * is for the RMC itself, envmon deletes existing platform nodes and 1244 * rebuilds from scratch.) 1245 * 4) this plugin catches PICL_FRU_ADDED event, looks for a related 1246 * configuration file and parses it. This adds Fru data properties (etc.). 1247 * 5) frudata catches the event and updates its FRUID data cache. 1248 */ 1249 /*ARGSUSED*/ 1250 static void 1251 fru_add_handler(const char *ename, const void *earg, size_t size, void *cookie) 1252 { 1253 int retval; 1254 picl_nodehdl_t locnodeh; 1255 picl_nodehdl_t rooth; 1256 char path[MAXPATHLEN]; 1257 char *fru_name; 1258 1259 if (strcmp(ename, PICL_FRU_ADDED) != 0) 1260 return; 1261 1262 retval = nvlist_lookup_uint64((nvlist_t *)earg, 1263 PICLEVENTARG_PARENTHANDLE, &locnodeh); 1264 1265 if (retval != PICL_SUCCESS) 1266 return; 1267 1268 retval = ptree_get_propval_by_name(locnodeh, PICL_PROP_NAME, 1269 path, sizeof (path)); 1270 1271 if (retval != PICL_SUCCESS) 1272 return; 1273 1274 fru_name = strdup(path); 1275 1276 if (fru_name == NULL) 1277 return; 1278 1279 /* 1280 * We're about to parse a fru-specific .conf file to populate 1281 * picl nodes relating to the dynamically added component. In the 1282 * case of the RMC, there is a problem: all of its /platform tree 1283 * nodes have just been replaced by envmon. It is now necessary to 1284 * repopulate Devices tables in /frutree. 1285 * picld_pluginutil_parse_config_file doesn't handle repopulating 1286 * existing tables, so as a work round, delete all tables found 1287 * under /frutree. This works on Enchilada Server as the tables 1288 * are all created from parsing a .conf file, and we're about to 1289 * redo that action. 1290 */ 1291 if (strcmp(fru_name, RMC_NAME) == 0) { 1292 rmc_state_event(); 1293 retval = ptree_get_node_by_path(FRUTREE_PATH, &rooth); 1294 if (retval == PICL_SUCCESS) { 1295 remove_tables(rooth); 1296 } 1297 } 1298 1299 /* 1300 * Re-establish the HPU(FRU) volatile properties. 1301 * This needs to be done before the .conf file is parsed because 1302 * it has a side effect of re-creating any missing power-supply 1303 * fru node. The .conf file can then hang properties beneath. 1304 */ 1305 opst_init(); 1306 1307 /* 1308 * see if there's a .conf file for this fru 1309 */ 1310 if (get_config_file(path, fru_name) == 0) { 1311 if ((ptree_get_root(&rooth) != PICL_SUCCESS) || 1312 (picld_pluginutil_parse_config_file(rooth, path) != 1313 PICL_SUCCESS)) { 1314 syslog(LOG_ERR, PARSE_CONF_FAIL, path); 1315 } 1316 } 1317 1318 free(fru_name); 1319 } 1320 1321 /* 1322 * Handle PICLEVENT_SYSEVENT_DEVICE_ADDED events. 1323 */ 1324 /*ARGSUSED*/ 1325 static void 1326 frutree_evhandler(const char *ename, const void *earg, size_t size, 1327 void *cookie) 1328 { 1329 nvlist_t *nvlp; 1330 picl_nodehdl_t rooth; 1331 char path[MAXPATHLEN]; 1332 char *fru_name; 1333 char *dtype; 1334 char *dpath; 1335 char *ptr; 1336 char *ptr2; 1337 int done = B_FALSE; 1338 1339 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) != 0) 1340 return; 1341 1342 if (nvlist_unpack((char *)earg, size, &nvlp, NULL)) 1343 return; 1344 1345 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) { 1346 nvlist_free(nvlp); 1347 return; 1348 } 1349 1350 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) { 1351 nvlist_free(nvlp); 1352 return; 1353 } 1354 1355 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DEVFS_PATH, &dpath)) { 1356 nvlist_free(nvlp); 1357 return; 1358 } 1359 1360 fru_name = strdup(dpath); 1361 1362 if (fru_name == NULL) { 1363 nvlist_free(nvlp); 1364 return; 1365 } 1366 1367 nvlist_free(nvlp); 1368 1369 /* 1370 * fru_name is of the form 1371 * "/pci@1e,600000/usb@a/mouse@2" 1372 * or 1373 * "/pci@1e,600000/usb@a/device@2/mouse@0" 1374 * reduce it to "usb-a-2" 1375 */ 1376 ptr = fru_name; 1377 if (*ptr == '/') { 1378 ptr++; 1379 ptr = strchr(ptr, '/'); 1380 if (ptr != NULL) { 1381 ptr++; 1382 (void) memmove(fru_name, ptr, strlen(ptr) + 1); 1383 ptr = strchr(fru_name, '@'); 1384 if (ptr != NULL) { 1385 *ptr = '-'; 1386 ptr++; 1387 ptr = strchr(ptr, '/'); 1388 if (ptr != NULL) { 1389 *ptr = '-'; 1390 ptr++; 1391 ptr2 = ptr; 1392 ptr = strchr(ptr, '@'); 1393 if (ptr != NULL) { 1394 ptr++; 1395 (void) memmove(ptr2, ptr, 1396 strlen(ptr) + 1); 1397 ptr2 = strchr(ptr2, '/'); 1398 if (ptr2 != NULL) { 1399 *ptr2 = '\0'; 1400 } 1401 done = B_TRUE; 1402 } 1403 } 1404 } 1405 } 1406 } 1407 if (done == B_FALSE) { 1408 free(fru_name); 1409 return; 1410 } 1411 1412 /* 1413 * see if there's a .conf file for this fru 1414 */ 1415 if (get_config_file(path, fru_name) == 0) { 1416 if ((ptree_get_root(&rooth) != PICL_SUCCESS) || 1417 (picld_pluginutil_parse_config_file(rooth, path) != 1418 PICL_SUCCESS)) { 1419 syslog(LOG_ERR, PARSE_CONF_FAIL, path); 1420 } 1421 } 1422 1423 free(fru_name); 1424 } 1425 1426 static int 1427 set_led(char *name, char *ptr, char *value) 1428 { 1429 char path[MAXPATHLEN]; 1430 picl_prophdl_t proph; 1431 ptree_propinfo_t propinfo; 1432 picl_prophdl_t tableh; 1433 picl_nodehdl_t locnodeh; 1434 picl_nodehdl_t nodeh; 1435 picl_prophdl_t tblh; 1436 int retval; 1437 char *value_ptr; 1438 char label[PICL_PROPNAMELEN_MAX]; 1439 char class[PICL_PROPNAMELEN_MAX]; 1440 1441 /* find the location node */ 1442 sprintf_buf2(path, CHASSIS_LOC_PATH, name); 1443 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) 1444 return (PICL_FAILURE); 1445 1446 /* 1447 * if no fru node, then turn led off 1448 */ 1449 if (find_child_by_name(locnodeh, DISK_FRU_NAME) != NULL) 1450 value_ptr = value; 1451 else 1452 value_ptr = PICL_PROPVAL_OFF; 1453 1454 /* get its Devices table */ 1455 if (ptree_get_prop_by_name(locnodeh, PICL_PROP_DEVICES, &tableh) != 1456 PICL_SUCCESS) 1457 return (PICL_FAILURE); 1458 if (ptree_get_propval(tableh, &tblh, sizeof (tblh)) != PICL_SUCCESS) 1459 return (PICL_FAILURE); 1460 1461 /* get first col, first row */ 1462 if (ptree_get_next_by_col(tblh, &tblh) != PICL_SUCCESS) 1463 return (PICL_FAILURE); 1464 1465 /* 1466 * starting at next col, get every entry in the column 1467 */ 1468 for (retval = ptree_get_next_by_row(tblh, &tblh); 1469 retval == PICL_SUCCESS; 1470 retval = ptree_get_next_by_col(tblh, &tblh)) { 1471 /* 1472 * get the target node handle 1473 */ 1474 if (ptree_get_propval(tblh, &nodeh, sizeof (nodeh)) 1475 != PICL_SUCCESS) 1476 continue; 1477 1478 /* 1479 * check it's a led 1480 */ 1481 if (ptree_get_propval_by_name(nodeh, PICL_PROP_CLASSNAME, 1482 class, sizeof (class)) != PICL_SUCCESS) 1483 continue; 1484 if (strcmp(class, "led") != 0) 1485 continue; 1486 1487 /* 1488 * check its the right led 1489 */ 1490 if (ptree_get_propval_by_name(nodeh, PICL_PROP_LABEL, 1491 label, sizeof (label)) != PICL_SUCCESS) 1492 continue; 1493 if (strcmp(label, ptr) == 0) { 1494 /* 1495 * set it 1496 */ 1497 if (ptree_get_prop_by_name(nodeh, PICL_PROP_STATE, 1498 &proph) != PICL_SUCCESS) 1499 continue; 1500 if (ptree_get_propinfo(proph, &propinfo) != 1501 PICL_SUCCESS) 1502 continue; 1503 retval = ptree_update_propval_by_name(nodeh, 1504 PICL_PROP_STATE, value_ptr, propinfo.piclinfo.size); 1505 return (retval); 1506 } 1507 } 1508 return (PICL_FAILURE); 1509 } 1510 1511 /* 1512 * function to find first node of specified class beneath supplied node 1513 */ 1514 static int 1515 get_node_by_class(picl_nodehdl_t nodeh, const char *classname, 1516 picl_nodehdl_t *foundnodeh) 1517 { 1518 int err; 1519 char clname[PICL_CLASSNAMELEN_MAX+1]; 1520 picl_nodehdl_t childh; 1521 1522 /* 1523 * go through the children 1524 */ 1525 err = ptree_get_propval_by_name(nodeh, PICL_PROP_CHILD, &childh, 1526 sizeof (picl_nodehdl_t)); 1527 1528 while (err == PICL_SUCCESS) { 1529 err = ptree_get_propval_by_name(childh, PICL_PROP_CLASSNAME, 1530 clname, sizeof (clname)); 1531 1532 if ((err == PICL_SUCCESS) && (strcmp(clname, classname) == 0)) { 1533 *foundnodeh = childh; 1534 return (PICL_SUCCESS); 1535 } 1536 1537 err = get_node_by_class(childh, classname, foundnodeh); 1538 if (err == PICL_SUCCESS) 1539 return (PICL_SUCCESS); 1540 1541 err = ptree_get_propval_by_name(childh, PICL_PROP_PEER, 1542 &childh, sizeof (picl_nodehdl_t)); 1543 } 1544 1545 return (PICL_NODENOTFOUND); 1546 } 1547 1548 /* 1549 * get system-controller node 1550 */ 1551 static int 1552 get_sys_controller_node(picl_nodehdl_t *nodeh) 1553 { 1554 int err; 1555 1556 /* get platform node */ 1557 err = ptree_get_node_by_path(PICL_NODE_ROOT PICL_NODE_PLATFORM, nodeh); 1558 if (err != PICL_SUCCESS) 1559 return (err); 1560 err = get_node_by_class(*nodeh, PICL_CLASS_SERVICE_PROCESSOR, nodeh); 1561 return (err); 1562 } 1563 1564 /* 1565 * create pathname string for system-controller device 1566 */ 1567 static char * 1568 create_sys_controller_pathname(picl_nodehdl_t sysconh) 1569 { 1570 char *ptr; 1571 char namebuf[PATH_MAX]; 1572 size_t len; 1573 DIR *dirp; 1574 struct dirent *dp; 1575 struct stat statbuf; 1576 1577 /* 1578 * prefix devfs-path name with /devices 1579 */ 1580 (void) strlcpy(namebuf, DEV_PREFIX, PATH_MAX); 1581 1582 /* 1583 * append devfs-path property 1584 */ 1585 len = strlen(namebuf); 1586 if (ptree_get_propval_by_name(sysconh, str_devfs_path, namebuf + len, 1587 sizeof (namebuf) - len) != PICL_SUCCESS) { 1588 return (NULL); 1589 } 1590 1591 /* 1592 * locate final component of name 1593 */ 1594 ptr = strrchr(namebuf, '/'); 1595 if (ptr == NULL) 1596 return (NULL); 1597 *ptr = '\0'; /* terminate at end of directory path */ 1598 len = strlen(ptr + 1); /* length of terminal name */ 1599 dirp = opendir(namebuf); 1600 if (dirp == NULL) { 1601 return (NULL); 1602 } 1603 *ptr++ = '/'; /* restore '/' and advance to final name */ 1604 1605 while ((dp = readdir(dirp)) != NULL) { 1606 /* 1607 * look for a name which starts with the string at *ptr 1608 */ 1609 if (strlen(dp->d_name) < len) 1610 continue; /* skip short names */ 1611 if (strncmp(dp->d_name, ptr, len) == 0) { 1612 /* 1613 * Got a match, restore full pathname and stat the 1614 * entry. Reject if not a char device 1615 */ 1616 (void) strlcpy(ptr, dp->d_name, 1617 sizeof (namebuf) - (ptr - namebuf)); 1618 if (stat(namebuf, &statbuf) < 0) 1619 continue; /* reject if can't stat it */ 1620 if (!S_ISCHR(statbuf.st_mode)) 1621 continue; /* not a character device */ 1622 /* 1623 * go with this entry 1624 */ 1625 (void) closedir(dirp); 1626 return (strdup(namebuf)); 1627 } 1628 } 1629 (void) closedir(dirp); 1630 return (NULL); 1631 } 1632 1633 /* 1634 * create pathname string for bezel leds device 1635 */ 1636 static char * 1637 create_bezel_leds_pathname(const char *dirpath, const char *devname) 1638 { 1639 char namebuf[PATH_MAX]; 1640 size_t lendirpath; 1641 size_t len; 1642 DIR *dirp; 1643 struct dirent *dp; 1644 struct stat statbuf; 1645 1646 /* 1647 * start with directory name 1648 */ 1649 (void) strlcpy(namebuf, dirpath, PATH_MAX); 1650 1651 /* 1652 * append devfs-path property 1653 */ 1654 lendirpath = strlen(namebuf); 1655 dirp = opendir(namebuf); 1656 if (dirp == NULL) { 1657 return (NULL); 1658 } 1659 1660 len = strlen(devname); 1661 1662 while ((dp = readdir(dirp)) != NULL) { 1663 /* 1664 * look for a name which starts with the gpio string 1665 */ 1666 if (strlen(dp->d_name) < len) 1667 continue; /* skip short names */ 1668 if (strncmp(dp->d_name, devname, len) == 0) { 1669 /* 1670 * Got a match, restore full pathname and stat the 1671 * entry. Reject if not a char device 1672 */ 1673 (void) strlcpy(namebuf + lendirpath, dp->d_name, 1674 sizeof (namebuf) - lendirpath); 1675 if (stat(namebuf, &statbuf) < 0) 1676 continue; /* reject if can't stat it */ 1677 if (!S_ISCHR(statbuf.st_mode)) 1678 continue; /* not a character device */ 1679 /* 1680 * go with this entry 1681 */ 1682 (void) closedir(dirp); 1683 return (strdup(namebuf)); 1684 } 1685 } 1686 (void) closedir(dirp); 1687 return (NULL); 1688 } 1689 1690 /* 1691 * initialise structure associated with nodes requiring OperationalStatus 1692 */ 1693 static void 1694 opst_init(void) 1695 { 1696 int res; 1697 int index = 0; 1698 int fd; 1699 int entries = 0; 1700 int err = 0; 1701 boolean_t rmc_flag; 1702 boolean_t ps_flag; 1703 boolean_t disk_flag; 1704 size_t len; 1705 envmon_sysinfo_t sysinfo; 1706 envmon_hpu_t hpu; 1707 1708 if (idprop != NULL) { 1709 /* 1710 * This must be a restart, clean up earlier allocation 1711 */ 1712 free(idprop); 1713 idprop = NULL; 1714 } 1715 1716 if (sc_device_name == NULL) 1717 err = 1; 1718 else { 1719 fd = open(sc_device_name, O_RDONLY); 1720 1721 if (fd < 0) { 1722 syslog(LOG_ERR, EM_NO_SC_DEV); 1723 err = 1; 1724 } 1725 } 1726 1727 if (err == 0) { 1728 res = ioctl(fd, ENVMONIOCSYSINFO, &sysinfo); 1729 1730 if (res < 0) { 1731 syslog(LOG_ERR, EM_NO_SYSINFO, strerror(errno)); 1732 (void) close(fd); 1733 err = 1; 1734 } 1735 } 1736 1737 if (err == 0) { 1738 entries = sysinfo.maxHPU; 1739 len = offsetof(idp_lkup_t, idp) + entries * sizeof (id_props_t); 1740 idprop = calloc(len, 1); 1741 if (idprop == NULL) { 1742 (void) close(fd); 1743 err = 1; 1744 } 1745 } 1746 1747 if (err == 0) { 1748 idprop->maxnum = entries; 1749 hpu.id.name[0] = '\0'; /* request for first name */ 1750 res = ioctl(fd, ENVMONIOCHPU, &hpu); 1751 1752 /* 1753 * The HPU node for the RMC is a special case. Its handle is 1754 * generated by the rmclomv driver. Rather than building 1755 * knowledge of its frutree hierarchic name into the driver, we 1756 * put that knowledge here. 1757 */ 1758 while ((res == 0) && (index < entries) && 1759 (hpu.next_id.name[0] != '\0')) { 1760 hpu.id = hpu.next_id; 1761 res = ioctl(fd, ENVMONIOCHPU, &hpu); 1762 1763 if ((res == 0) && 1764 ((hpu.sensor_status & ENVMON_NOT_PRESENT) == 0)) { 1765 add_op_status(&hpu, &index); 1766 } 1767 } 1768 1769 idprop->num = index; 1770 (void) close(fd); 1771 } 1772 } 1773 1774 static void 1775 disk_leds_init(void) 1776 { 1777 int err = 0, i; 1778 1779 if (!g_mutex_init) { 1780 if ((pthread_cond_init(&g_cv, NULL) == 0) && 1781 (pthread_cond_init(&g_cv_ack, NULL) == 0) && 1782 (pthread_mutex_init(&g_mutex, NULL) == 0)) { 1783 g_mutex_init = B_TRUE; 1784 } else { 1785 return; 1786 } 1787 } 1788 1789 /* 1790 * Initialise to -1 so the led thread will set correctly. 1791 * Do this before creating the disk_leds thread, 1792 * so there's no race. 1793 */ 1794 for (i = 0; i < N_DISKS; i++) 1795 disk_ready[i] = -1; 1796 1797 if (ledsthr_created) { 1798 /* 1799 * this is a restart, wake up sleeping threads 1800 */ 1801 err = pthread_mutex_lock(&g_mutex); 1802 if (err != 0) { 1803 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno)); 1804 return; 1805 } 1806 g_finish_now = B_FALSE; 1807 (void) pthread_cond_broadcast(&g_cv); 1808 (void) pthread_mutex_unlock(&g_mutex); 1809 } else { 1810 if ((pthread_attr_init(&ledsthr_attr) != 0) || 1811 (pthread_attr_setscope(&ledsthr_attr, 1812 PTHREAD_SCOPE_SYSTEM) != 0)) 1813 return; 1814 if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr, 1815 disk_leds_thread, NULL)) != 0) { 1816 syslog(LOG_ERR, EM_THREAD_CREATE_FAILED, 1817 strerror(errno)); 1818 return; 1819 } 1820 ledsthr_created = B_TRUE; 1821 } 1822 } 1823 1824 static void 1825 disk_leds_fini(void) 1826 { 1827 int err, i; 1828 1829 /* 1830 * turn the leds off as we'll no longer be monitoring them 1831 */ 1832 for (i = 0; i < N_DISKS; i++) 1833 (void) set_led(disk_name[i], REMOK_LED, PICL_PROPVAL_OFF); 1834 1835 /* 1836 * disk_leds_thread() never started or an error occured so 1837 * that it's not running 1838 */ 1839 if (!disk_leds_thread_running) 1840 return; 1841 1842 /* 1843 * tell led thread to pause 1844 */ 1845 if (!ledsthr_created) 1846 return; 1847 err = pthread_mutex_lock(&g_mutex); 1848 if (err != 0) { 1849 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(errno)); 1850 return; 1851 } 1852 g_finish_now = B_TRUE; 1853 disk_leds_thread_ack = B_FALSE; 1854 (void) pthread_cond_broadcast(&g_cv); 1855 1856 /* 1857 * and wait for them to acknowledge 1858 */ 1859 while (!disk_leds_thread_ack) { 1860 (void) pthread_cond_wait(&g_cv_ack, &g_mutex); 1861 } 1862 (void) pthread_mutex_unlock(&g_mutex); 1863 } 1864 1865 static void 1866 update_disk_node(char *fruname, char *devpath) 1867 { 1868 picl_nodehdl_t slotndh; 1869 picl_nodehdl_t diskndh; 1870 picl_nodehdl_t devhdl; 1871 picl_prophdl_t tblhdl; 1872 picl_prophdl_t tblhdl2; 1873 picl_prophdl_t tblproph; 1874 int err; 1875 char path[MAXPATHLEN]; 1876 1877 sprintf_buf2(path, CHASSIS_LOC_PATH, fruname); 1878 if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) { 1879 return; 1880 } 1881 diskndh = find_child_by_name(slotndh, DISK_FRU_NAME); 1882 if (diskndh == NULL) { 1883 return; 1884 } 1885 err = ptree_get_node_by_path(devpath, &devhdl); 1886 if (err == PICL_SUCCESS) { 1887 err = ptree_get_propval_by_name(diskndh, 1888 PICL_PROP_DEVICES, &tblhdl, sizeof (tblhdl)); 1889 if (err != PICL_SUCCESS) 1890 return; 1891 err = ptree_get_next_by_col(tblhdl, &tblhdl2); 1892 if (err != PICL_SUCCESS) { 1893 err = create_table_entry(tblhdl, devhdl, 1894 PICL_CLASS_BLOCK); 1895 if (err != PICL_SUCCESS) 1896 return; 1897 err = add_prop_ref(devhdl, diskndh, 1898 PICL_REFPROP_FRU_PARENT); 1899 if (err != PICL_SUCCESS) 1900 return; 1901 } 1902 } else { 1903 /* 1904 * no mechanism for deleting row - so delete 1905 * whole table and start again 1906 */ 1907 err = ptree_get_prop_by_name(diskndh, PICL_PROP_DEVICES, 1908 &tblproph); 1909 if (err != PICL_SUCCESS) 1910 return; 1911 err = ptree_delete_prop(tblproph); 1912 if (err != PICL_SUCCESS) 1913 return; 1914 (void) ptree_destroy_prop(tblproph); 1915 err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES); 1916 if (err != PICL_SUCCESS) 1917 return; 1918 } 1919 } 1920 1921 static int 1922 get_raid_config(raid_config_t *config) 1923 { 1924 int fd; 1925 1926 switch (sys_platform) { 1927 case PLAT_CHALUPA: 1928 case PLAT_CHALUPA19: 1929 fd = open(V440_DISK_DEVCTL, O_RDONLY); 1930 break; 1931 default: 1932 fd = -1; 1933 break; 1934 } 1935 1936 if (fd == -1) { 1937 syslog(LOG_ERR, "%s", strerror(errno)); 1938 return (1); 1939 } 1940 1941 /* 1942 * We are running on chalupa, so we know just a single 1943 * RAID volume is supported. We can go ahead and 1944 * explicitly request the unitid 0 RAID volume. 1945 */ 1946 config->unitid = 0; 1947 if (ioctl(fd, RAID_GETCONFIG, config)) { 1948 syslog(LOG_ERR, "%s", strerror(errno)); 1949 (void) close(fd); 1950 return (1); 1951 } 1952 1953 (void) close(fd); 1954 return (0); 1955 } 1956 1957 /* 1958 * We will light the OK2REMOVE LED for disks configured 1959 * into a raid if (and only if) the driver reports 1960 * that the disk has failed. 1961 */ 1962 static void 1963 raid_ok2rem_policy(raid_config_t config) 1964 { 1965 int i; 1966 for (i = 0; i < config.ndisks; i++) { 1967 int d = config.disk[i]; 1968 int dstatus = config.diskstatus[i]; 1969 1970 switch (dstatus) { 1971 case RAID_DISKSTATUS_MISSING: 1972 /* If LED is on, turn it off */ 1973 if (disk_ready[d] == B_FALSE) { 1974 if (set_led(disk_name[d], REMOK_LED, 1975 PICL_PROPVAL_OFF) == PICL_SUCCESS) { 1976 disk_ready[d] = B_TRUE; 1977 } 1978 } 1979 break; 1980 case RAID_DISKSTATUS_GOOD: 1981 if (disk_ready[d] != B_TRUE) { 1982 if (set_led(disk_name[d], REMOK_LED, 1983 PICL_PROPVAL_OFF) == PICL_SUCCESS) { 1984 disk_ready[d] = B_TRUE; 1985 } 1986 } 1987 break; 1988 case RAID_DISKSTATUS_FAILED: 1989 if (disk_ready[d] != B_FALSE) { 1990 if (set_led(disk_name[d], REMOK_LED, 1991 PICL_PROPVAL_ON) == PICL_SUCCESS) { 1992 disk_ready[d] = B_FALSE; 1993 } 1994 } 1995 break; 1996 default: 1997 break; 1998 } 1999 } 2000 } 2001 2002 static void 2003 check_raid(int *d0, int *d1) 2004 { 2005 raid_config_t raid_config; 2006 int raid_exists = 0; 2007 2008 if (!get_raid_config(&raid_config)) { 2009 raid_exists = raid_config.ndisks; 2010 } else { 2011 return; 2012 } 2013 2014 if (raid_exists) { 2015 *d0 = raid_config.disk[0]; 2016 *d1 = raid_config.disk[1]; 2017 raid_ok2rem_policy(raid_config); 2018 } 2019 } 2020 2021 /*ARGSUSED*/ 2022 static void * 2023 disk_leds_thread(void *args) 2024 { 2025 int c; 2026 int i; 2027 char **disk_dev; 2028 2029 devctl_hdl_t dhdl; 2030 2031 int n_disks = 0, 2032 do_raid = 0, 2033 err = 0; 2034 uint_t statep = 0; 2035 2036 static char *mpxu_devs[] = { 2037 "/pci@1c,600000/scsi@2/sd@0,0", 2038 "/pci@1c,600000/scsi@2/sd@1,0", 2039 "/pci@1c,600000/scsi@2/sd@2,0", 2040 "/pci@1c,600000/scsi@2/sd@3,0" 2041 }; 2042 2043 static char *ents_devs[] = { 2044 "/pci@1d,700000/scsi@4/sd@0,0", 2045 "/pci@1d,700000/scsi@4/sd@1,0", 2046 "/pci@1d,700000/scsi@4/sd@2,0", 2047 "/pci@1d,700000/scsi@4/sd@3,0", 2048 "/pci@1d,700000/scsi@4/sd@8,0", 2049 "/pci@1d,700000/scsi@4/sd@9,0", 2050 "/pci@1d,700000/scsi@4/sd@a,0", 2051 "/pci@1d,700000/scsi@4/sd@b,0" 2052 }; 2053 2054 static char *v440_devs[] = { 2055 "/pci@1f,700000/scsi@2/sd@0,0", 2056 "/pci@1f,700000/scsi@2/sd@1,0", 2057 "/pci@1f,700000/scsi@2/sd@2,0", 2058 "/pci@1f,700000/scsi@2/sd@3,0" 2059 }; 2060 2061 static char *n210_devs[] = { 2062 "/pci@1c,600000/LSILogic,sas@1/sd@0,0", 2063 "/pci@1c,600000/LSILogic,sas@1/sd@1,0" 2064 }; 2065 2066 char *ddev[N_DISKS]; /* "/devices" */ 2067 char *pdev[N_DISKS]; /* "/platform" */ 2068 2069 switch (sys_platform) { 2070 2071 case PLAT_ENTS: 2072 disk_dev = ents_devs; 2073 n_disks = N_ENTS_DISKS; 2074 break; 2075 2076 case PLAT_CHALUPA: 2077 case PLAT_CHALUPA19: 2078 do_raid = 1; 2079 disk_dev = v440_devs; 2080 n_disks = N_CHALUPA_DISKS; 2081 break; 2082 2083 case PLAT_SALSA19: 2084 disk_dev = n210_devs; 2085 n_disks = N_EN19_DISKS; 2086 break; 2087 2088 default: /* PLAT_ENXS/PLAT_EN19 */ 2089 disk_dev = mpxu_devs; 2090 n_disks = (sys_platform == PLAT_EN19) ? 2091 N_EN19_DISKS : N_MPXU_DISKS; 2092 } 2093 2094 /* 2095 * make up disk names 2096 */ 2097 2098 for (i = 0; i < n_disks; i++) { 2099 char buffer[MAXPATHLEN]; 2100 sprintf(buffer, "/devices%s", disk_dev[i]); 2101 ddev[i] = strdup(buffer); 2102 sprintf(buffer, "/platform%s", disk_dev[i]); 2103 pdev[i] = strdup(buffer); 2104 } 2105 2106 disk_leds_thread_running = B_TRUE; 2107 2108 for (;;) { 2109 int rdsk0 = -1; 2110 int rdsk1 = -1; 2111 2112 if (do_raid) 2113 check_raid(&rdsk0, &rdsk1); 2114 2115 for (i = 0; i < n_disks; i++) { 2116 /* 2117 * If it's one of the raid disks, we have already 2118 * applied the ok2remove policy. 2119 * If there was no raid, rdskN will be -1 and 2120 * so the check will fail and the default 2121 * okay2remove policy will be applied. 2122 */ 2123 if (i == rdsk0 || i == rdsk1) 2124 continue; 2125 2126 dhdl = devctl_device_acquire(ddev[i], 0); 2127 devctl_device_getstate(dhdl, &statep); 2128 devctl_release(dhdl); 2129 2130 if (statep & DEVICE_OFFLINE) { 2131 if (disk_ready[i] != B_FALSE) { 2132 update_disk_node(disk_name[i], pdev[i]); 2133 if (set_led(disk_name[i], REMOK_LED, 2134 PICL_PROPVAL_ON) == PICL_SUCCESS) 2135 disk_ready[i] = B_FALSE; 2136 } 2137 } else if (statep & DEVICE_ONLINE) { 2138 if (disk_ready[i] != B_TRUE) { 2139 update_disk_node(disk_name[i], pdev[i]); 2140 if (set_led(disk_name[i], REMOK_LED, 2141 PICL_PROPVAL_OFF) == PICL_SUCCESS) 2142 disk_ready[i] = B_TRUE; 2143 } 2144 } 2145 } 2146 2147 /* 2148 * wait a bit until we check again 2149 */ 2150 2151 (void) poll(NULL, 0, DISK_POLL_TIME); 2152 2153 /* 2154 * are we to stop? 2155 */ 2156 2157 (void) pthread_mutex_lock(&g_mutex); 2158 2159 while (g_finish_now) { 2160 /* 2161 * notify _fini routine that we've paused 2162 */ 2163 disk_leds_thread_ack = B_TRUE; 2164 (void) pthread_cond_signal(&g_cv_ack); 2165 2166 /* 2167 * and go to sleep in case we get restarted 2168 */ 2169 (void) pthread_cond_wait(&g_cv, &g_mutex); 2170 } 2171 (void) pthread_mutex_unlock(&g_mutex); 2172 } 2173 2174 return ((void *)err); 2175 } 2176 2177 /* 2178 * Given the powersupply name, convert to addr 2179 */ 2180 static int 2181 ps_name_to_addr(char *name) 2182 { 2183 int ps_addr = 0; 2184 if ((strcmp(name, PS0_NAME) == 0) || 2185 (strcmp(name, PSU0_NAME) == 0)) 2186 ps_addr = PS0_ADDR; 2187 else if ((strcmp(name, PS1_NAME) == 0) || 2188 (strcmp(name, PSU1_NAME) == 0)) 2189 ps_addr = PS1_ADDR; 2190 else if ((strcmp(name, PS2_NAME) == 0) || 2191 (strcmp(name, PSU2_NAME) == 0)) 2192 ps_addr = PS2_ADDR; 2193 else if ((strcmp(name, PS3_NAME) == 0) || 2194 (strcmp(name, PSU3_NAME) == 0)) 2195 ps_addr = PS3_ADDR; 2196 2197 return (ps_addr); 2198 } 2199 2200 /* 2201 * Given powersupply name, convert to unit addr 2202 */ 2203 static char * 2204 ps_name_to_unitaddr(char *name) 2205 { 2206 char *unitaddr; 2207 2208 if (strcmp(name, PS0_NAME) == 0) 2209 unitaddr = PS0_UNITADDR; 2210 else if (strcmp(name, PS1_NAME) == 0) 2211 unitaddr = PS1_UNITADDR; 2212 else if (strcmp(name, PS2_NAME) == 0) 2213 unitaddr = PS2_UNITADDR; 2214 else if (strcmp(name, PS3_NAME) == 0) 2215 unitaddr = PS3_UNITADDR; 2216 else 2217 unitaddr = NULL; 2218 2219 return (unitaddr); 2220 } 2221 2222 /* 2223 * converts apid to real FRU name in PICL tree. The 2224 * name of powersupply devices on chalupa19 are 2225 * PSU instead of PS 2226 */ 2227 static char * 2228 ps_apid_to_nodename(char *apid) 2229 { 2230 char *nodename; 2231 2232 if (sys_platform != PLAT_CHALUPA19) 2233 return (apid); 2234 2235 if (strcmp(apid, PS0_NAME) == 0) 2236 nodename = PSU0_NAME; 2237 else if (strcmp(apid, PS1_NAME) == 0) 2238 nodename = PSU1_NAME; 2239 else if (strcmp(apid, PS2_NAME) == 0) 2240 nodename = PSU2_NAME; 2241 else if (strcmp(apid, PS3_NAME) == 0) 2242 nodename = PSU3_NAME; 2243 else 2244 nodename = apid; 2245 2246 return (nodename); 2247 } 2248 2249 /* 2250 * Create SEEPROM node at insertion time. 2251 */ 2252 static int 2253 create_i2c_node(char *ap_id) 2254 { 2255 int nd_reg[2]; 2256 devctl_ddef_t ddef_hdl; 2257 devctl_hdl_t bus_hdl; 2258 devctl_hdl_t dev_hdl; 2259 char dev_path[MAXPATHLEN]; 2260 2261 /* create seeprom node */ 2262 nd_reg[0] = 0; 2263 nd_reg[1] = ps_name_to_addr(ap_id); 2264 2265 bus_hdl = devctl_bus_acquire(PSU_I2C_BUS_DEV, 0); 2266 if (bus_hdl == NULL) 2267 return (DDI_FAILURE); 2268 2269 /* device definition properties */ 2270 ddef_hdl = devctl_ddef_alloc(PS_DEVICE_NAME, 0); 2271 (void) devctl_ddef_string(ddef_hdl, "compatible", "i2c-at24c64"); 2272 (void) devctl_ddef_string(ddef_hdl, "device_type", "seeprom"); 2273 (void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg); 2274 2275 /* create the device node */ 2276 if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl)) 2277 return (DDI_FAILURE); 2278 2279 if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL) 2280 return (DDI_FAILURE); 2281 2282 devctl_release(dev_hdl); 2283 devctl_ddef_free(ddef_hdl); 2284 devctl_release(bus_hdl); 2285 return (DDI_SUCCESS); 2286 } 2287 2288 /* 2289 * Delete SEEPROM node at insertion time. 2290 */ 2291 static void 2292 delete_i2c_node(char *ap_id) 2293 { 2294 devctl_hdl_t dev_hdl; 2295 char buf[MAXPATHLEN]; 2296 2297 sprintf_buf2(buf, PSU_DEV, ps_name_to_addr(ap_id)); 2298 dev_hdl = devctl_device_acquire(buf, 0); 2299 if (dev_hdl == NULL) { 2300 return; 2301 } 2302 2303 /* 2304 * If the seeprom driver is not loaded, calls to 2305 * devctl_device_remove fails for seeprom devices 2306 */ 2307 if (devctl_device_remove(dev_hdl)) { 2308 di_init_driver(SEEPROM_DRIVER_NAME, 0); 2309 devctl_device_remove(dev_hdl); 2310 } 2311 devctl_release(dev_hdl); 2312 } 2313 2314 static void 2315 add_op_status(envmon_hpu_t *hpu, int *index) 2316 { 2317 boolean_t rmc_flag; 2318 boolean_t ps_flag; 2319 boolean_t disk_flag; 2320 char node_name[MAXPATHLEN]; 2321 boolean_t flag; 2322 2323 rmc_flag = (strcmp(hpu->id.name, RMC_NAME) == 0); 2324 ps_flag = (strncmp(hpu->id.name, PS_NAME, 2325 PS_NAME_LEN) == 0); 2326 disk_flag = (strncmp(hpu->id.name, DISK_NAME, 2327 DISK_NAME_LEN) == 0); 2328 if (rmc_flag || ps_flag || disk_flag) { 2329 idprop->idp[*index].envhandle = hpu->id; 2330 flag = rmc_flag && ((sys_platform != PLAT_CHALUPA) && 2331 (sys_platform != PLAT_CHALUPA19)); 2332 sprintf_buf2(node_name, 2333 flag ? SYS_BOARD_PATH : CHASSIS_LOC_PATH, ps_flag ? 2334 ps_apid_to_nodename(hpu->id.name) : hpu->id.name); 2335 2336 add_op_status_by_name(node_name, disk_flag ? DISK_FRU_NAME : 2337 ps_flag ? PS_FRU_NAME : NULL, &idprop->idp[(*index)++].volprop); 2338 } 2339 } 2340