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