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