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