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