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