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 /* 28 * This plugin-in creates the FRU Hierarchy for the 29 * SUNW,Netra-T12 platform and manages the environmental sensors 30 * on the platform. 31 */ 32 33 #include <stdio.h> 34 #include <errno.h> 35 #include <syslog.h> 36 #include <strings.h> 37 #include <libintl.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <fcntl.h> 41 #include <picl.h> 42 #include <picltree.h> 43 #include <sys/stat.h> 44 #include <libnvpair.h> 45 #include <sys/param.h> 46 #include <kstat.h> 47 #include <config_admin.h> 48 #include <sys/sbd_ioctl.h> 49 #include <sys/sgfrutree.h> 50 #include <sys/sgenv.h> 51 #include <sys/ioccom.h> 52 #include <sys/lw8.h> 53 #include <sys/sysevent/dr.h> 54 #include <pthread.h> 55 #include <sys/obpdefs.h> 56 #include "libdevice.h" 57 #include "picldefs.h" 58 #define NDEBUG 59 #include <assert.h> 60 61 /* 62 * Plugin registration entry points 63 */ 64 static void piclfrutree_register(void); 65 static void piclfrutree_init(void); 66 static void piclfrutree_fini(void); 67 #pragma init(piclfrutree_register) 68 69 static picld_plugin_reg_t my_reg_info = { 70 PICLD_PLUGIN_VERSION_1, 71 PICLD_PLUGIN_CRITICAL, 72 "SUNW_Netra-T12_frutree", 73 piclfrutree_init, 74 piclfrutree_fini, 75 }; 76 77 /* 78 * Log message texts 79 */ 80 #define DEV_OPEN_FAIL gettext("piclfrutree_init: open of %s failed: %s") 81 #define ADD_NODES_FAIL gettext("piclfrutree_init: add_all_nodes failed: %d") 82 #define GET_ROOT_FAIL gettext("piclfrutree_init: ptree_get_root failed") 83 #define ADD_FRUTREE_FAIL gettext("piclfrutree_init: add frutree failed") 84 #define INVALID_PICL_CLASS gettext("add_subtree: invalid picl class 0x%x") 85 #define ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d") 86 #define GET_NEXT_BY_ROW_FAIL gettext("ptree_get_next_by_row %s failed: %d") 87 #define PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d") 88 #define GET_PROPVAL_FAIL gettext("ptree_get_propval failed: %d") 89 #define DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d") 90 #define DELETE_NODE_FAIL gettext("ptree_delete_node failed: %d") 91 #define ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d") 92 #define SGFRU_IOCTL_FAIL gettext("sgfru ioctl 0x%x handle 0x%llx failed: %s") 93 #define LED_IOCTL_FAIL gettext("led ioctl failed: %s") 94 #define MALLOC_FAIL gettext("piclfrutree: malloc failed") 95 #define NO_SC_FAIL gettext("piclfrutree: cannot find sc node") 96 #define NO_NODE_FAIL gettext("piclfrutree: cannot find node %s: %d") 97 #define KSTAT_FAIL gettext("piclfrutree: failure accessing kstats") 98 #define ADD_TBL_ENTRY_FAIL gettext("piclfrutree: cannot add entry to table") 99 #define PROP_LOOKUP_FAIL gettext("piclfrutree: cannot find %s property: %d") 100 #define EM_DI_INIT_FAIL gettext("frutree: di_init failed: %s") 101 #define EM_THREAD_CREATE_FAILED gettext("frutree: pthread_create failed: %s") 102 #define EM_MUTEX_FAIL gettext("frutree: pthread_mutex_lock returned: %s") 103 #define EM_POLL_FAIL gettext("frutree: poll() failed: %s") 104 #define DEVCTL_DEVICE_ACQUIRE_FAILED \ 105 gettext("frutree: devctl_device_acquire() failed: %s") 106 107 /* 108 * PICL property values 109 */ 110 #define PICL_PROPVAL_TRUE "true" 111 #define PICL_PROPVAL_SYSTEM "system" 112 #define PICL_PROPVAL_ON "ON" 113 #define PICL_PROPVAL_OFF "OFF" 114 #define PICL_PROPVAL_BLINKING "BLINKING" 115 #define PICL_PROPVAL_FLASHING "FLASHING" 116 #define PICL_PROPVAL_CHASSIS "chassis" 117 #define PICL_PROPVAL_AMBIENT "Ambient" 118 #define PICL_PROPVAL_DIE "Die" 119 #define PICL_PROPVAL_GREEN "green" 120 #define PICL_PROPVAL_AMBER "amber" 121 #define PICL_PROPVAL_OKAY "okay" 122 #define PICL_PROPVAL_FAILED "failed" 123 #define PICL_PROPVAL_WARNING "warning" 124 #define PICL_PROPVAL_DISABLED "disabled" 125 #define PICL_PROPVAL_UNKNOWN "unknown" 126 #define PICL_PROPVAL_SELF_REGULATING "self-regulating" 127 #define PICL_PROPVAL_PER_CENT "%" 128 #define PICL_PROP_BANK_STATUS "bank-status" 129 130 /* 131 * PICL property names 132 */ 133 #define PICL_PROP_LOW_WARNING_THRESHOLD "LowWarningThreshold" 134 135 /* 136 * Local defines 137 */ 138 #define MAX_LINE_SIZE 1024 139 #define MAX_TRIES 4 140 #define MAX_SPEED_UNIT_LEN 20 141 #define MAX_OPERATIONAL_STATUS_LEN 10 142 #define MAX_CONDITION_LEN 10 143 #define MAX_LABEL_LEN 256 144 #define MAX_STATE_LEN 10 145 #define MAX_STATE_SIZE 32 146 #define LED_PSEUDO_DEV "/devices/pseudo/lw8@0:lw8" 147 #define SC_DEV "/platform/ssm@0,0/pci@18,700000/bootbus-controller@4" 148 #define SC_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/bootbus-controller@3" 149 #define CPU_DEV "/platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0" 150 #define CPU_DEV2 "/platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0" 151 #define CPU_DEV3C0 "/platform/ssm@0,0/cmp@%x,0/cpu@0" 152 #define CPU_DEV3C1 "/platform/ssm@0,0/cmp@%x,0/cpu@1" 153 #define MEMORY_DEV "/platform/ssm@0,0/memory-controller@%x,400000" 154 #define IO_DEV "/platform/ssm@0,0/pci@%s" 155 #define DISK0_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@0,0" 156 #define DISK0_DEV "/platform" DISK0_BASE_PATH 157 #define DISK1_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@1,0" 158 #define DISK1_DEV "/platform" DISK1_BASE_PATH 159 #define DISK0_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@0,0" 160 #define DISK0_DEV_PCIX "/platform" DISK0_BASE_PATH_PCIX 161 #define DISK1_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@1,0" 162 #define DISK1_DEV_PCIX "/platform" DISK1_BASE_PATH_PCIX 163 #define TAPE_DEV "/platform/ssm@0,0/pci@18,600000/scsi@2/st@5,0" 164 #define TAPE_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/scsi@2/st@5,0" 165 #define DVD_DEV "/platform/ssm@0,0/pci@18,700000/ide@3/sd@0,0" 166 #define DVD_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/ide@2/sd@0,0" 167 #define CHASSIS_PATH "/frutree/chassis" 168 #define CHASSIS_LOC_PATH "/frutree/chassis/%s" 169 #define PROC_LOC_PATH "/frutree/chassis/SB%d/SB%d/P%d" 170 #define PROC_FRU_PATH "/frutree/chassis/SB%d/SB%d/P%d/P%d" 171 /* 172 * Calculate safari address to put in CPU_DEV/MEMORY_DEV string based on 173 * SBx/Py fru path name 174 */ 175 #define SB_P_TO_SAFARI_ADDR(sbname, pname) \ 176 ((pname[1] - '0') + (4 * (sbname[2] - '0'))) 177 #define SAFARI_ADDR_TO_SB(value) (value >> 2) 178 #define SAFARI_ADDR_TO_P(value) (value & 3) 179 #define AP_ID_PREAMBLE "ssm0:N0." 180 #define AP_ID_PREAMBLE_LEN 8 181 #define LABEL_PREAMBLE "N0/" 182 #define LABEL_PREAMBLE_LEN 3 183 /* 184 * work out type of fru based on name 185 */ 186 #define IS_ECACHE_NODE(name) (name[0] == 'E') 187 #define IS_DIMM_NODE(name) (name[0] == 'D' && name[1] != 'V') 188 #define IS_PROC_NODE(name) (name[0] == 'P' && name[1] != 'S') 189 #define IS_PSU_NODE(name) (name[0] == 'P' && name[1] == 'S') 190 #define IS_SB_NODE(name) (name[0] == 'S' && name[1] == 'B') 191 #define IS_IB_NODE(name) (name[0] == 'I') 192 #define IS_FT_NODE(name) (name[0] == 'F' && name[1] == 'T') 193 #define IS_FAN_NODE(name) (name[0] == 'F' && name[1] != 'T') 194 #define IS_RP_NODE(name) (name[0] == 'R') 195 /* 196 * rename sgfru driver's node_t to sgfrunode_t to avoid confusion 197 */ 198 #define sgfrunode_t node_t 199 200 /* 201 * disk_led data 202 */ 203 #define REMOK_LED "ok_to_remove" 204 #define FAULT_LED "fault" 205 #define POWER_LED "power" 206 207 /* 208 * 'struct lw8_disk' contains the per-disk metadata needed to 209 * manage the current state of one of the internal disks. 210 * 211 * 'lw8_disks[]' is an array that contains the metadata 212 * for N_DISKS disks. 213 * 214 * The d_fruname field of 'struct lw8_disk' is static. 215 * d_plat_path and d_devices_path are aliases for device-paths 216 * to the disk. They are logically static, as they are computed 217 * when the disk_leds_thread() thread does its initialization. 218 * 219 * d_state is the most interesting field, as it changes 220 * dynamically, based on whether the associated disk 221 * is currently Configured or Unconfigured (by DR). d_state 222 * is an optimization that minimizes per-disk actions such 223 * as setting of LEDs and updating the FRU Tree. 224 * 225 * A disk starts in a d_state of DISK_STATE_NOT_INIT 226 * and moves to DISK_STATE_READY when the disk is 227 * Configured (by DR) and it moves to DISK_STATE_NOT_READY 228 * when it is Unconfigured (by DR). 229 */ 230 typedef enum { 231 DISK_STATE_NOT_INIT, 232 DISK_STATE_READY, 233 DISK_STATE_NOT_READY 234 } disk_state_t; 235 236 struct lw8_disk { 237 char *d_fruname; /* FRU name */ 238 char *d_plat_path; /* /platform */ 239 char *d_devices_path; /* /devices */ 240 disk_state_t d_state; 241 }; 242 243 #define N_DISKS 2 244 static struct lw8_disk lw8_disks[N_DISKS] = { 245 {"DISK0", NULL, NULL, DISK_STATE_NOT_INIT}, 246 {"DISK1", NULL, NULL, DISK_STATE_NOT_INIT} }; 247 248 /* Duration of inactivity within disk_leds_thread() */ 249 #define THR_POLL_PERIOD 5000 /* milliseconds */ 250 251 static volatile boolean_t disk_leds_thread_ack = B_FALSE; 252 static pthread_t ledsthr_tid; 253 static pthread_attr_t ledsthr_attr; 254 static boolean_t ledsthr_created = B_FALSE; 255 static uint_t ledsthr_poll_period = 256 THR_POLL_PERIOD; 257 static boolean_t g_mutex_init = B_FALSE; 258 static pthread_cond_t g_cv; 259 static pthread_cond_t g_cv_ack; 260 static pthread_mutex_t g_mutex; 261 static volatile boolean_t g_wait_now = B_FALSE; 262 263 static void disk_leds_init(void); 264 static void disk_leds_fini(void); 265 static void *disk_leds_thread(void *args); 266 267 /* 268 * Tables to convert sgenv information 269 */ 270 static char *hpu_type_table[] = { "", "SSC", "SB", "RP", "FT", 271 "IB", "PS", "ID"}; 272 static char *hpu_fru_type_table[] = { "", "SSC", "CPU", "RP", "FT", 273 "PCIB", "PS", "ID"}; 274 static char *hpu_part_table[] = { "", "sbbc", "sdc", 275 "ar", "cbh", "dx", "cheetah", "1.5vdc", "3.3vdc", 276 "5vdc", "12vdc", "output", "current", "board", "sc-app", 277 "schizo", "fan", "input"}; 278 static char *hpu_sensor_table[] = { "", "", "current", 279 "temp", "cooling", "1.5vdc", "1.8vdc", "3.3vdc", "5vdc", 280 "12vdc", "48vdc", NULL, "2.4vdc"}; 281 static char *hpu_sensor_class_table[] = { "", "", PICL_CLASS_CURRENT_SENSOR, 282 PICL_CLASS_TEMPERATURE_SENSOR, PICL_CLASS_FAN, 283 PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR, 284 PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR, 285 PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_INDICATOR, 286 NULL, PICL_CLASS_VOLTAGE_SENSOR}; 287 static char *hpu_sensor_prop_table[] = { "", "", PICL_PROP_CURRENT, 288 PICL_PROP_TEMPERATURE, PICL_PROP_FAN_SPEED, PICL_PROP_VOLTAGE, 289 PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE, 290 PICL_PROP_VOLTAGE, PICL_PROP_CONDITION, NULL, PICL_PROP_VOLTAGE}; 291 static char *hpu_condition_table[] = {"unknown", "okay", "failing", 292 "failed", "unusable"}; 293 294 /* 295 * variables set up in init 296 */ 297 static picl_nodehdl_t frutreeh; 298 static picl_nodehdl_t sch = 0; 299 static int init_complete; 300 static int pcix_io = 0; 301 302 /* 303 * forward reference 304 */ 305 static int add_all_nodes(void); 306 static int remove_subtree(picl_nodehdl_t parh); 307 static int add_subtree(picl_nodehdl_t parh, fru_hdl_t fruparent); 308 static int add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 309 picl_nodehdl_t *childp); 310 static int add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 311 picl_nodehdl_t *childp); 312 static int add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 313 picl_nodehdl_t *childp); 314 static int add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 315 picl_nodehdl_t *childp); 316 static int add_led_nodes(picl_nodehdl_t nodeh, char *name, int position, 317 picl_prophdl_t tblhdl); 318 static int add_env_nodes(picl_nodehdl_t nodeh, char *nodename, 319 picl_prophdl_t tblhdl); 320 static int add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp, 321 picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name); 322 static int add_intermediate_location(picl_nodehdl_t *nodep, char *labelp, 323 char *slot_name); 324 static int add_pci_location(picl_nodehdl_t childh, char *parent_addr, 325 char bus_addr, char *slot_name); 326 static picl_nodehdl_t find_child_by_name(picl_nodehdl_t parh, char *name); 327 static int create_dimm_references(picl_nodehdl_t parh, int dimm_id, 328 picl_nodehdl_t nodeh, picl_prophdl_t tblhdl); 329 static int create_cpu_references(char *pname, picl_nodehdl_t nodeh, 330 picl_prophdl_t tblhdl); 331 static void post_frudr_event(char *ename, picl_nodehdl_t parenth, 332 picl_nodehdl_t fruh); 333 static int remove_references(picl_prophdl_t refprop, char *class); 334 static int remove_picl_node(picl_nodehdl_t nodeh); 335 static sgfrunode_t *get_node_children(fru_hdl_t fruparent, int *num_childrenp); 336 static int add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name); 337 static int add_prop_void(picl_nodehdl_t nodeh, char *name); 338 static int add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name); 339 static int add_prop_int(picl_nodehdl_t nodeh, int value, char *name); 340 static int add_prop_float(picl_nodehdl_t nodeh, float value, char *name); 341 static int add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name); 342 static void frudr_evhandler(const char *ename, const void *earg, 343 size_t size, void *cookie); 344 static void frumemcfg_evhandler(const char *ename, const void *earg, 345 size_t size, void *cookie); 346 static int add_sensor_prop(picl_nodehdl_t nodeh, char *class); 347 static int add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl, 348 char *nodename, char *class, char *prop_class, 349 picl_prophdl_t tblhdl, picl_nodehdl_t *sensorhdlp); 350 static int create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, 351 char *tbl_name); 352 static int create_table_entry(picl_prophdl_t tblhdl, 353 picl_nodehdl_t refhdl, char *class); 354 static int get_sensor_data(ptree_rarg_t *arg, void *result); 355 static int get_led(char *name, char *ptr, char *result); 356 static int get_led_data(ptree_rarg_t *arg, void *result); 357 static int set_led_data(ptree_warg_t *arg, const void *value); 358 static int get_cpu_status(ptree_rarg_t *arg, void *result); 359 static int add_board_status(picl_nodehdl_t nodeh, char *nodename); 360 static int get_board_status(ptree_rarg_t *arg, void *result); 361 static int get_op_status(ptree_rarg_t *arg, void *result); 362 363 #define sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2) 364 #define sprintf_buf3(buf, a1, a2, a3) \ 365 (void) snprintf(buf, sizeof (buf), a1, a2, a3) 366 #define sprintf_buf4(buf, a1, a2, a3, a4) \ 367 (void) snprintf(buf, sizeof (buf), a1, a2, a3, a4) 368 #define sprintf_buf5(buf, a1, a2, a3, a4, a5) \ 369 (void) snprintf(buf, sizeof (buf), a1, a2, a3, a4, a5) 370 /* 371 * This function is executed as part of .init when the plugin is 372 * dlopen()ed 373 */ 374 static void 375 piclfrutree_register(void) 376 { 377 (void) picld_plugin_register(&my_reg_info); 378 } 379 380 /* 381 * This function is the init entry point of the plugin. 382 * It initializes the /frutree tree 383 */ 384 static void 385 piclfrutree_init(void) 386 { 387 int err; 388 389 (void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE, 390 frudr_evhandler, NULL); 391 (void) ptree_register_handler(PICLEVENT_MC_ADDED, 392 frumemcfg_evhandler, NULL); 393 (void) ptree_register_handler(PICLEVENT_MC_REMOVED, 394 frumemcfg_evhandler, NULL); 395 init_complete = 0; 396 397 err = add_all_nodes(); 398 disk_leds_init(); 399 init_complete = 1; 400 if (err != PICL_SUCCESS) { 401 syslog(LOG_ERR, ADD_NODES_FAIL, err); 402 piclfrutree_fini(); 403 } 404 } 405 406 /* 407 * This function is the fini entry point of the plugin. 408 */ 409 static void 410 piclfrutree_fini(void) 411 { 412 (void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE, 413 frudr_evhandler, NULL); 414 (void) ptree_unregister_handler(PICLEVENT_MC_ADDED, 415 frumemcfg_evhandler, NULL); 416 (void) ptree_unregister_handler(PICLEVENT_MC_REMOVED, 417 frumemcfg_evhandler, NULL); 418 (void) remove_subtree(frutreeh); 419 disk_leds_fini(); 420 } 421 422 /* 423 * called from piclfrutree_init() to initialise picl frutree 424 */ 425 static int 426 add_all_nodes(void) 427 { 428 int err; 429 picl_nodehdl_t rooth; 430 431 /* Get the root node of the PICL tree */ 432 err = ptree_get_root(&rooth); 433 if (err != PICL_SUCCESS) { 434 syslog(LOG_ERR, GET_ROOT_FAIL); 435 return (err); 436 } 437 438 /* find sc node so we can create sensor nodes under it */ 439 440 err = ptree_get_node_by_path(SC_DEV, &sch); 441 if (err != PICL_SUCCESS) { 442 443 /* 444 * There is a XMITS/PCI-X IO Board assembly implements 445 * a different path for the the bootbus controller. 446 */ 447 err = ptree_get_node_by_path(SC_DEV_PCIX, &sch); 448 if (err == PICL_SUCCESS) 449 pcix_io = 1; 450 } 451 452 if (err != PICL_SUCCESS) { 453 syslog(LOG_ERR, NO_SC_FAIL); 454 return (err); 455 } 456 457 /* Create and add the root node of the FRU subtree */ 458 err = ptree_create_and_add_node(rooth, PICL_NODE_FRUTREE, 459 PICL_CLASS_PICL, &frutreeh); 460 if (err != PICL_SUCCESS) { 461 syslog(LOG_ERR, ADD_FRUTREE_FAIL); 462 return (err); 463 } 464 465 /* Recursively query the SC and add frutree nodes */ 466 return (add_subtree(frutreeh, ROOTPARENT)); 467 } 468 469 /* 470 * Recursive routine to add picl nodes to the frutree. Called from 471 * add_all_nodes() for the whole frutree at initialisation, and from 472 * frudr_evhandler() for portions of the frutree on DR insert events 473 */ 474 static int 475 add_subtree(picl_nodehdl_t parh, fru_hdl_t handle) 476 { 477 int err, i; 478 int num_children; 479 sgfrunode_t *cp, *fruchildren = NULL; 480 picl_nodehdl_t childh; 481 482 /* find children of the parent node */ 483 fruchildren = get_node_children(handle, &num_children); 484 if (fruchildren == NULL) 485 return (PICL_FAILURE); 486 487 /* for each child, add a new picl node */ 488 for (i = 0, cp = fruchildren; i < num_children; i++, cp++) { 489 /* 490 * Add the appropriate PICL class 491 */ 492 childh = 0; 493 err = add_picl_node(parh, cp, &childh); 494 if (err == PICL_NOTNODE) 495 continue; 496 if (err != PICL_SUCCESS) { 497 free(fruchildren); 498 return (err); 499 } 500 501 /* 502 * Recursively call this function based on has_children hint 503 */ 504 if (childh && cp->has_children) { 505 err = add_subtree(childh, cp->handle); 506 if (err != PICL_SUCCESS) { 507 free(fruchildren); 508 return (err); 509 } 510 } 511 } 512 free(fruchildren); 513 return (PICL_SUCCESS); 514 } 515 516 /* 517 * Recursive routine to remove picl nodes to the frutree. Called from 518 * piclfrutree_fini() for the whole frutree at termination, and from 519 * frudr_completion_handler() for portions of the frutree on DR remove events 520 */ 521 static int 522 remove_subtree(picl_nodehdl_t parh) 523 { 524 picl_nodehdl_t chdh; 525 526 for (;;) { 527 if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh, 528 sizeof (picl_nodehdl_t)) == PICL_SUCCESS) { 529 if (remove_subtree(chdh) != PICL_SUCCESS) 530 return (PICL_FAILURE); 531 } else { 532 return (remove_picl_node(parh)); 533 } 534 } 535 /* NOTREACHED */ 536 } 537 538 /* 539 * Add fru and location nodes with SC_handle property 540 * (aka, container handle, for frus). 541 * Return picl_nodehdl of created node in *childp. 542 */ 543 static int 544 add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 545 picl_nodehdl_t *childp) 546 { 547 switch (sgfrunode->class) { 548 case PSEUDO_FRU_CLASS: 549 return (add_chassis_node(parh, sgfrunode, childp)); 550 551 case FRU_CLASS: 552 return (add_fru_node(parh, sgfrunode, childp)); 553 554 case LOCATION_CLASS: 555 return (add_location_node(parh, sgfrunode, childp)); 556 557 default: 558 syslog(LOG_ERR, INVALID_PICL_CLASS, sgfrunode->class); 559 return (PICL_NOTNODE); 560 } 561 } 562 563 /* 564 * create chassis node 565 */ 566 static int 567 add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 568 picl_nodehdl_t *childp) 569 { 570 int err; 571 uint64_t handle = (uint64_t)sgfrunode->handle; 572 picl_prophdl_t tblhdl; 573 picl_nodehdl_t nodeh; 574 picl_nodehdl_t devhdl; 575 picl_nodehdl_t childh; 576 577 err = ptree_create_and_add_node(parh, PICL_PROPVAL_CHASSIS, 578 PICL_CLASS_FRU, &childh); 579 if (err != PICL_SUCCESS) { 580 syslog(LOG_ERR, ADD_NODE_FAIL, PICL_PROPVAL_CHASSIS, err); 581 return (err); 582 } 583 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE); 584 if (err != PICL_SUCCESS) 585 return (err); 586 587 /* 588 * add devices table to chassis node (may need references 589 * to led devices) 590 */ 591 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES); 592 if (err != PICL_SUCCESS) 593 return (err); 594 595 err = add_led_nodes(childh, "chassis", LOM_LED_POSITION_FRU, tblhdl); 596 if (err != PICL_SUCCESS) 597 return (err); 598 599 if (pcix_io) 600 err = ptree_get_node_by_path(DISK0_DEV_PCIX, &devhdl); 601 else 602 err = ptree_get_node_by_path(DISK0_DEV, &devhdl); 603 604 nodeh = childh; 605 if (err != PICL_SUCCESS) { 606 err = add_intermediate_location(&nodeh, "DISK0", "disk-slot"); 607 } else { 608 err = add_intermediate_nodes(&nodeh, "DISK0", &tblhdl, 609 "disk-slot", NULL); 610 if (err != PICL_SUCCESS) 611 return (err); 612 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT); 613 if (err != PICL_SUCCESS) 614 return (err); 615 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK); 616 } 617 if (err != PICL_SUCCESS) 618 return (err); 619 620 if (pcix_io) 621 err = ptree_get_node_by_path(DISK1_DEV_PCIX, &devhdl); 622 else 623 err = ptree_get_node_by_path(DISK1_DEV, &devhdl); 624 625 nodeh = childh; 626 if (err != PICL_SUCCESS) { 627 err = add_intermediate_location(&nodeh, "DISK1", "disk-slot"); 628 } else { 629 err = add_intermediate_nodes(&nodeh, "DISK1", &tblhdl, 630 "disk-slot", NULL); 631 if (err != PICL_SUCCESS) 632 return (err); 633 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT); 634 if (err != PICL_SUCCESS) 635 return (err); 636 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK); 637 } 638 if (err != PICL_SUCCESS) 639 return (err); 640 641 if (pcix_io) 642 err = ptree_get_node_by_path(TAPE_DEV_PCIX, &devhdl); 643 else 644 err = ptree_get_node_by_path(TAPE_DEV, &devhdl); 645 646 nodeh = childh; 647 if (err != PICL_SUCCESS) { 648 err = add_intermediate_location(&nodeh, "TAPE", "tape-slot"); 649 } else { 650 err = add_intermediate_nodes(&nodeh, "TAPE", &tblhdl, 651 "tape-slot", NULL); 652 if (err != PICL_SUCCESS) 653 return (err); 654 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT); 655 if (err != PICL_SUCCESS) 656 return (err); 657 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_TAPE); 658 } 659 if (err != PICL_SUCCESS) 660 return (err); 661 662 if (pcix_io) 663 err = ptree_get_node_by_path(DVD_DEV_PCIX, &devhdl); 664 else 665 err = ptree_get_node_by_path(DVD_DEV, &devhdl); 666 667 nodeh = childh; 668 if (err != PICL_SUCCESS) { 669 err = add_intermediate_location(&nodeh, "DVD", "dvd-slot"); 670 } else { 671 err = add_intermediate_nodes(&nodeh, "DVD", &tblhdl, 672 "dvd-slot", NULL); 673 if (err != PICL_SUCCESS) 674 return (err); 675 err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT); 676 if (err != PICL_SUCCESS) 677 return (err); 678 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_CDROM); 679 } 680 if (err != PICL_SUCCESS) 681 return (err); 682 683 if (pcix_io) { 684 /* 685 * The XMITS/PCI-X IO Assembly is layed out a bit differently. 686 */ 687 err = add_pci_location(childh, "19,600000", '1', "PCI0"); 688 if (err != PICL_SUCCESS) 689 return (err); 690 err = add_pci_location(childh, "19,600000", '2', "PCI1"); 691 if (err != PICL_SUCCESS) 692 return (err); 693 err = add_pci_location(childh, "19,700000", '1', "PCI2"); 694 if (err != PICL_SUCCESS) 695 return (err); 696 err = add_pci_location(childh, "19,700000", '2', "PCI3"); 697 if (err != PICL_SUCCESS) 698 return (err); 699 err = add_pci_location(childh, "18,600000", '1', "PCI4"); 700 if (err != PICL_SUCCESS) 701 return (err); 702 err = add_pci_location(childh, "18,600000", '2', "PCI5"); 703 if (err != PICL_SUCCESS) 704 return (err); 705 } else { 706 err = add_pci_location(childh, "18,700000", '1', "PCI0"); 707 if (err != PICL_SUCCESS) 708 return (err); 709 err = add_pci_location(childh, "18,700000", '2', "PCI1"); 710 if (err != PICL_SUCCESS) 711 return (err); 712 err = add_pci_location(childh, "19,700000", '1', "PCI2"); 713 if (err != PICL_SUCCESS) 714 return (err); 715 err = add_pci_location(childh, "19,700000", '2', "PCI3"); 716 if (err != PICL_SUCCESS) 717 return (err); 718 err = add_pci_location(childh, "19,700000", '3', "PCI4"); 719 if (err != PICL_SUCCESS) 720 return (err); 721 err = add_pci_location(childh, "18,600000", '1', "PCI5"); 722 if (err != PICL_SUCCESS) 723 return (err); 724 } 725 *childp = childh; 726 return (PICL_SUCCESS); 727 } 728 729 /* 730 * create fru node, based on sgfru node "sgfrunode" under parent parh. Return 731 * picl_nodehdl of created node in *childp. 732 */ 733 static int 734 add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 735 picl_nodehdl_t *childp) 736 { 737 int err; 738 picl_prophdl_t tblhdl; 739 picl_nodehdl_t childh; 740 uint64_t handle = (uint64_t)sgfrunode->handle; 741 char *nodename = sgfrunode->nodename; 742 743 /* 744 * if sgfrunode already there, then just carry on own the tree 745 */ 746 childh = find_child_by_name(parh, nodename); 747 if (childh != 0) { 748 /* 749 * for frus other than dimms and ecaches, update environmental 750 * sensors and board status if necessary 751 */ 752 if (IS_ECACHE_NODE(nodename)) { 753 *childp = childh; 754 return (PICL_SUCCESS); 755 } 756 if (IS_DIMM_NODE(nodename)) { 757 /* 758 * for dimms we just want status 759 */ 760 err = add_board_status(childh, nodename); 761 if (err != PICL_SUCCESS) 762 return (err); 763 *childp = childh; 764 return (PICL_SUCCESS); 765 } 766 err = add_board_status(childh, nodename); 767 if (err != PICL_SUCCESS) 768 return (err); 769 err = ptree_get_propval_by_name(childh, PICL_PROP_DEVICES, 770 &tblhdl, sizeof (tblhdl)); 771 if (err != PICL_SUCCESS) 772 return (err); 773 err = add_env_nodes(childh, nodename, tblhdl); 774 if (err != PICL_SUCCESS) 775 return (err); 776 *childp = childh; 777 return (PICL_SUCCESS); 778 } 779 780 /* 781 * create requested fru node 782 */ 783 err = ptree_create_and_add_node(parh, nodename, PICL_CLASS_FRU, 784 &childh); 785 if (err != PICL_SUCCESS) { 786 syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err); 787 return (err); 788 } 789 790 /* 791 * if sgfru has sent us a valid handle, then there is fruid information. 792 * create the SC_handle, and FRUDateAvailable properties for FRUID. 793 */ 794 if (handle != -1ULL) { 795 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE); 796 if (err != PICL_SUCCESS) 797 return (err); 798 err = add_prop_void(childh, PICL_PROP_FRUDATA_AVAIL); 799 if (err != PICL_SUCCESS) 800 return (err); 801 } 802 803 /* 804 * post fru added event to fru data plugin if this was due to 805 * a dr event - ie post-initialisation 806 */ 807 if (init_complete) 808 post_frudr_event(PICL_FRU_ADDED, parh, 0); 809 810 /* 811 * Create empty Devices table - we'll add lines to it as we go along 812 */ 813 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES); 814 if (err != PICL_SUCCESS) 815 return (err); 816 817 /* 818 * Ecache nodes don't have sensors - just set up FRUType 819 */ 820 if (IS_ECACHE_NODE(nodename)) { 821 err = add_prop_charstring(childh, "EEPROM", PICL_PROP_FRU_TYPE); 822 if (err != PICL_SUCCESS) 823 return (err); 824 *childp = childh; 825 return (PICL_SUCCESS); 826 } 827 828 /* 829 * Dimm nodes don't have sensors - just set up FRUType and 830 * also reference properties to memory module nodes and OpStatus 831 */ 832 if (IS_DIMM_NODE(nodename)) { 833 err = add_prop_charstring(childh, "DIMM", PICL_PROP_FRU_TYPE); 834 if (err != PICL_SUCCESS) 835 return (err); 836 err = create_dimm_references(parh, nodename[1] - '0', 837 childh, tblhdl); 838 if (err != PICL_SUCCESS) 839 return (err); 840 err = add_board_status(childh, nodename); 841 if (err != PICL_SUCCESS) 842 return (err); 843 *childp = childh; 844 return (PICL_SUCCESS); 845 } 846 847 /* 848 * not a Dimm or Ecache node - set up environmental info, 849 * board status and led info 850 */ 851 err = add_env_nodes(childh, nodename, tblhdl); 852 if (err != PICL_SUCCESS) 853 return (err); 854 855 err = add_board_status(childh, nodename); 856 if (err != PICL_SUCCESS) 857 return (err); 858 859 err = add_led_nodes(childh, nodename, LOM_LED_POSITION_FRU, tblhdl); 860 if (err != PICL_SUCCESS) 861 return (err); 862 863 *childp = childh; 864 return (PICL_SUCCESS); 865 } 866 867 /* 868 * create location node, based on sgfru node "sgfrunode" under parent parh. 869 * Return picl_nodehdl of created node in *childp. 870 */ 871 static int 872 add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode, 873 picl_nodehdl_t *childp) 874 { 875 int err; 876 uint64_t handle = (uint64_t)sgfrunode->handle; 877 char *labelp; 878 char label[MAX_LABEL_LEN]; 879 char *ptr; 880 picl_prophdl_t tblhdl; 881 picl_nodehdl_t childh; 882 883 /* 884 * strip "N0/" off the label if present (hang-over from wildcat) 885 */ 886 if (strncmp(sgfrunode->location_label, LABEL_PREAMBLE, 887 LABEL_PREAMBLE_LEN) == 0) 888 (void) strlcpy(label, &sgfrunode->location_label[ 889 LABEL_PREAMBLE_LEN], sizeof (label)); 890 else 891 (void) strlcpy(label, &sgfrunode->location_label[0], 892 sizeof (label)); 893 894 /* 895 * some of the locations returned by sgfru are actually of the form 896 * XX/YY/ZZ - we need to create multiple levels in the picl tree for 897 * these. 898 */ 899 labelp = label; 900 while ((ptr = strchr(labelp, '/')) != NULL) { 901 /* 902 * null end of this section of label 903 */ 904 *ptr = '\0'; 905 906 /* 907 * add intermediate nodes - parh will point to the created node 908 */ 909 if (IS_PROC_NODE(labelp)) { 910 err = add_intermediate_nodes(&parh, labelp, &tblhdl, 911 "cpu", "PROC"); 912 } else { 913 err = add_intermediate_nodes(&parh, labelp, &tblhdl, 914 NULL, NULL); 915 } 916 if (err != PICL_SUCCESS) 917 return (err); 918 /* 919 * if processor node, then create links to associated cpu node 920 * and OpStatus property 921 */ 922 if (IS_PROC_NODE(labelp)) { 923 err = create_cpu_references(labelp, parh, tblhdl); 924 if (err != PICL_SUCCESS) 925 return (err); 926 err = add_board_status(parh, labelp); 927 if (err != PICL_SUCCESS) 928 return (err); 929 } 930 labelp = ptr + 1; 931 932 /* 933 * set back to "/" 934 */ 935 *ptr = '/'; 936 } 937 938 /* 939 * if node already there, then just carry on down the tree 940 */ 941 childh = find_child_by_name(parh, labelp); 942 if (childh != 0) { 943 *childp = childh; 944 return (PICL_SUCCESS); 945 } 946 947 /* 948 * now just have the final level of the node left. First create it. 949 */ 950 err = ptree_create_and_add_node(parh, labelp, PICL_CLASS_LOCATION, 951 &childh); 952 if (err != PICL_SUCCESS) { 953 syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err); 954 return (err); 955 } 956 957 /* 958 * if sgfru has sent us a valid handle, then there is fruid information. 959 * create the SC_handle property for FRUID. 960 */ 961 if (handle != -1ULL) { 962 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE); 963 if (err != PICL_SUCCESS) 964 return (err); 965 } 966 967 /* create label property for location class */ 968 err = add_prop_charstring(childh, labelp, PICL_PROP_LABEL); 969 if (err != PICL_SUCCESS) 970 return (err); 971 972 /* create SlotType property where appropriate */ 973 if (IS_ECACHE_NODE(sgfrunode->nodename)) { 974 err = add_prop_charstring(childh, 975 "ecache", PICL_PROP_SLOT_TYPE); 976 /* 977 * For Ecache, don't need to add environmental info 978 * so return here 979 */ 980 *childp = childh; 981 return (err); 982 } else if (IS_DIMM_NODE(sgfrunode->nodename)) { 983 err = add_prop_charstring(childh, "memory-module", 984 PICL_PROP_SLOT_TYPE); 985 /* 986 * For Dimm, don't need to add environmental info 987 * so return here 988 */ 989 *childp = childh; 990 return (err); 991 } else if (IS_SB_NODE(sgfrunode->nodename)) { 992 err = add_prop_charstring(childh, "system-board", 993 PICL_PROP_SLOT_TYPE); 994 } else if (IS_PSU_NODE(sgfrunode->nodename)) { 995 err = add_prop_charstring(childh, "power-supply", 996 PICL_PROP_SLOT_TYPE); 997 } else if (IS_FT_NODE(sgfrunode->nodename)) { 998 err = add_prop_charstring(childh, "fan-tray", 999 PICL_PROP_SLOT_TYPE); 1000 } 1001 if (err != PICL_SUCCESS) 1002 return (err); 1003 1004 /* 1005 * add devices table to location node (may need 1006 * references to led devices) 1007 */ 1008 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES); 1009 if (err != PICL_SUCCESS) 1010 return (err); 1011 1012 err = add_led_nodes(childh, labelp, LOM_LED_POSITION_LOCATION, tblhdl); 1013 if (err != PICL_SUCCESS) 1014 return (err); 1015 *childp = childh; 1016 return (PICL_SUCCESS); 1017 } 1018 1019 /* 1020 * remove an individual picl node - called from remove_subtree() 1021 * also removes any sensor nodes pointed at by Devices table 1022 */ 1023 static int 1024 remove_picl_node(picl_nodehdl_t nodeh) 1025 { 1026 int err; 1027 picl_prophdl_t tblhdl; 1028 picl_prophdl_t nextprop; 1029 picl_prophdl_t refprop; 1030 char class[PICL_CLASSNAMELEN_MAX]; 1031 1032 /* 1033 * first scan Devices table so we can find any sensor nodes 1034 * we need to delete as well 1035 */ 1036 err = ptree_get_propval_by_name(nodeh, PICL_PROP_DEVICES, 1037 &tblhdl, sizeof (tblhdl)); 1038 1039 /* 1040 * If Devices table present, then read first column. 1041 * Devices table may be empty so don't treat this as an error 1042 */ 1043 if (err == PICL_SUCCESS && 1044 ptree_get_next_by_row(tblhdl, &nextprop) == PICL_SUCCESS) { 1045 /* find second column */ 1046 err = ptree_get_next_by_row(nextprop, &nextprop); 1047 if (err != PICL_SUCCESS) { 1048 syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, 1049 PICL_PROP_DEVICES, err); 1050 return (err); 1051 } 1052 1053 /* 1054 * walk down second column (ref ptr) 1055 * deleting the referenced nodes 1056 */ 1057 while (err == PICL_SUCCESS) { 1058 err = ptree_get_propval(nextprop, &refprop, 1059 sizeof (refprop)); 1060 if (err != PICL_SUCCESS) { 1061 syslog(LOG_ERR, GET_PROPVAL_FAIL, err); 1062 return (err); 1063 } 1064 1065 /* 1066 * don't delete memory-module nodes 1067 * or cpu nodes (they weren't created 1068 * by this plugin) 1069 */ 1070 err = ptree_get_propval_by_name(refprop, 1071 PICL_PROP_CLASSNAME, class, sizeof (class)); 1072 if (err == PICL_STALEHANDLE) { 1073 /* 1074 * if another plugin has already deleted the 1075 * node for us then that is ok 1076 */ 1077 err = ptree_get_next_by_col(nextprop, 1078 &nextprop); 1079 continue; 1080 } 1081 if (err != PICL_SUCCESS) { 1082 syslog(LOG_ERR, PROP_LOOKUP_FAIL, 1083 PICL_PROP_CLASSNAME, err); 1084 return (err); 1085 } 1086 if (strcmp(class, PICL_CLASS_MEMORY_MODULE) == 0 || 1087 strcmp(class, PICL_CLASS_CPU) == 0) { 1088 /* 1089 * but - do need to remove _fru_parent 1090 * property and Environment table (for cpu) 1091 */ 1092 err = remove_references(refprop, class); 1093 if (err != PICL_SUCCESS) 1094 return (err); 1095 } else { 1096 /* 1097 * sensor node - need to delete it 1098 */ 1099 err = ptree_delete_node(refprop); 1100 if (err != PICL_SUCCESS) { 1101 syslog(LOG_ERR, DELETE_PROP_FAIL, err); 1102 return (err); 1103 } 1104 (void) ptree_destroy_node(refprop); 1105 } 1106 err = ptree_get_next_by_col(nextprop, &nextprop); 1107 } 1108 } 1109 1110 /* 1111 * now we can remove the frutree node 1112 */ 1113 err = ptree_delete_node(nodeh); 1114 if (err != PICL_SUCCESS) { 1115 syslog(LOG_ERR, DELETE_PROP_FAIL, err); 1116 return (err); 1117 } 1118 (void) ptree_destroy_node(nodeh); 1119 return (PICL_SUCCESS); 1120 } 1121 1122 static int 1123 add_child_pci_references(picl_nodehdl_t nodeh, picl_prophdl_t tblhdl, 1124 picl_nodehdl_t devnodeh) 1125 { 1126 int err = PICL_SUCCESS; 1127 picl_nodehdl_t childnodeh; 1128 char class[PICL_CLASSNAMELEN_MAX]; 1129 1130 if (ptree_get_propval_by_name(devnodeh, PICL_PROP_CHILD, &childnodeh, 1131 sizeof (childnodeh)) != PICL_SUCCESS) { 1132 return (PICL_SUCCESS); 1133 } 1134 for (;;) { 1135 err = ptree_get_propval_by_name(childnodeh, 1136 PICL_PROP_CLASSNAME, class, sizeof (class)); 1137 if (err != PICL_SUCCESS) 1138 break; 1139 err = add_prop_ref(childnodeh, nodeh, PICL_REFPROP_FRU_PARENT); 1140 if (err != PICL_SUCCESS) 1141 break; 1142 err = create_table_entry(tblhdl, childnodeh, class); 1143 if (err != PICL_SUCCESS) 1144 break; 1145 err = add_child_pci_references(nodeh, tblhdl, childnodeh); 1146 if (err != PICL_SUCCESS) 1147 break; 1148 err = ptree_get_propval_by_name(childnodeh, 1149 PICL_PROP_PEER, &childnodeh, sizeof (picl_nodehdl_t)); 1150 if (err != PICL_SUCCESS) { 1151 err = PICL_SUCCESS; 1152 break; 1153 } 1154 } 1155 return (err); 1156 } 1157 1158 static int 1159 add_pci_location(picl_nodehdl_t childh, char *parent_addr, char bus_addr, 1160 char *slot_name) 1161 { 1162 int err; 1163 int got_one = 0; 1164 picl_nodehdl_t nodeh; 1165 picl_nodehdl_t devnodeh; 1166 picl_nodehdl_t devhdl; 1167 char addr[MAXPATHLEN]; 1168 char parent_path[MAXPATHLEN]; 1169 picl_prophdl_t tblhdl; 1170 char class[PICL_CLASSNAMELEN_MAX]; 1171 1172 /* 1173 * search for any device nodes whose BUS_ADDR or UNIT_ADDRESS 1174 * are appropriate for this pci slot 1175 */ 1176 sprintf_buf2(parent_path, IO_DEV, parent_addr); 1177 if (ptree_get_node_by_path(parent_path, &devhdl) == PICL_SUCCESS && 1178 ptree_get_propval_by_name(devhdl, PICL_PROP_CHILD, &devnodeh, 1179 sizeof (devnodeh)) == PICL_SUCCESS) { 1180 while (!got_one) { 1181 err = ptree_get_propval_by_name(devnodeh, 1182 PICL_PROP_BUS_ADDR, addr, sizeof (addr)); 1183 if (err == PICL_SUCCESS && addr[0] == bus_addr && 1184 (addr[1] == ',' || addr[1] == '\0')) { 1185 got_one = 1; 1186 break; 1187 } 1188 err = ptree_get_propval_by_name(devnodeh, 1189 PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr)); 1190 if (err == PICL_SUCCESS && addr[0] == bus_addr && 1191 (addr[1] == ',' || addr[1] == '\0')) { 1192 got_one = 1; 1193 break; 1194 } 1195 err = ptree_get_propval_by_name(devnodeh, 1196 PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t)); 1197 if (err != PICL_SUCCESS) 1198 break; 1199 } 1200 } 1201 nodeh = childh; 1202 if (got_one == 0) { 1203 /* 1204 * no devnodes for this slot. Create location node but 1205 * no fru node (empty slot) 1206 */ 1207 return (add_intermediate_location(&nodeh, slot_name, "pci")); 1208 } 1209 1210 /* 1211 * we've got the first devnode for this slot. Create the fru node 1212 * then walk along other nodes looking for further devnodes 1213 */ 1214 err = add_intermediate_nodes(&nodeh, slot_name, &tblhdl, "pci", NULL); 1215 if (err != PICL_SUCCESS) 1216 return (err); 1217 1218 for (;;) { 1219 if (((err = ptree_get_propval_by_name(devnodeh, 1220 PICL_PROP_BUS_ADDR, addr, sizeof (addr))) == 1221 PICL_SUCCESS && addr[0] == bus_addr && 1222 (addr[1] == ',' || addr[1] == '\0')) || 1223 ((err = ptree_get_propval_by_name(devnodeh, 1224 PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr))) == 1225 PICL_SUCCESS && addr[0] == bus_addr && 1226 (addr[1] == ',' || addr[1] == '\0'))) { 1227 err = ptree_get_propval_by_name(devnodeh, 1228 PICL_PROP_CLASSNAME, class, sizeof (class)); 1229 if (err != PICL_SUCCESS) 1230 break; 1231 err = add_prop_ref(devnodeh, nodeh, 1232 PICL_REFPROP_FRU_PARENT); 1233 if (err != PICL_SUCCESS) 1234 break; 1235 err = create_table_entry(tblhdl, devnodeh, class); 1236 if (err != PICL_SUCCESS) 1237 break; 1238 err = add_child_pci_references(nodeh, tblhdl, devnodeh); 1239 if (err != PICL_SUCCESS) 1240 break; 1241 } 1242 err = ptree_get_propval_by_name(devnodeh, 1243 PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t)); 1244 if (err != PICL_SUCCESS) { 1245 err = PICL_SUCCESS; 1246 break; 1247 } 1248 } 1249 return (err); 1250 } 1251 1252 /* 1253 * add intermediate location into frutree (ie a location that we know 1254 * exists but sgfru doesn't) 1255 */ 1256 static int 1257 add_intermediate_location(picl_nodehdl_t *nodep, char *labelp, char *slot_name) 1258 { 1259 int err; 1260 picl_nodehdl_t intermediate; 1261 picl_prophdl_t tblhdl; 1262 char parent_name[PICL_PROPNAMELEN_MAX]; 1263 1264 err = ptree_create_and_add_node(*nodep, labelp, PICL_CLASS_LOCATION, 1265 &intermediate); 1266 if (err != PICL_SUCCESS) { 1267 syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err); 1268 return (err); 1269 } 1270 1271 /* 1272 * create label property for location class 1273 */ 1274 err = add_prop_charstring(intermediate, labelp, PICL_PROP_LABEL); 1275 if (err != PICL_SUCCESS) 1276 return (err); 1277 1278 /* 1279 * add devices table to location node (may need references to led 1280 * devices) 1281 */ 1282 err = create_table(intermediate, &tblhdl, PICL_PROP_DEVICES); 1283 if (err != PICL_SUCCESS) 1284 return (err); 1285 1286 /* 1287 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9 1288 */ 1289 err = ptree_get_propval_by_name(*nodep, PICL_PROP_NAME, parent_name, 1290 sizeof (parent_name)); 1291 if (err != PICL_SUCCESS) 1292 return (err); 1293 if (strcmp(labelp, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0) 1294 err = add_led_nodes(intermediate, "FAN8", 1295 LOM_LED_POSITION_LOCATION, tblhdl); 1296 else if (strcmp(labelp, "FAN1") == 0 && strcmp(parent_name, "IB6") == 0) 1297 err = add_led_nodes(intermediate, "FAN9", 1298 LOM_LED_POSITION_LOCATION, tblhdl); 1299 else 1300 err = add_led_nodes(intermediate, labelp, 1301 LOM_LED_POSITION_LOCATION, tblhdl); 1302 if (err != PICL_SUCCESS) 1303 return (err); 1304 1305 if (slot_name) { 1306 err = add_prop_charstring(intermediate, slot_name, 1307 PICL_PROP_SLOT_TYPE); 1308 if (err != PICL_SUCCESS) 1309 return (err); 1310 } 1311 *nodep = intermediate; 1312 return (PICL_SUCCESS); 1313 } 1314 1315 /* 1316 * adds an intermediate location/fru pair into frutree 1317 */ 1318 static int 1319 add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp, 1320 picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name) 1321 { 1322 int err; 1323 picl_nodehdl_t intermediate; 1324 picl_nodehdl_t intermediate2; 1325 1326 /* 1327 * create intermediate location node (unless it has already been 1328 * created) 1329 */ 1330 intermediate = find_child_by_name(*nodep, labelp); 1331 if (intermediate == 0) { 1332 intermediate = *nodep; 1333 err = add_intermediate_location(&intermediate, labelp, 1334 slot_name); 1335 if (err != PICL_SUCCESS) { 1336 return (err); 1337 } 1338 } 1339 1340 /* 1341 * create intermediate fru node (unless it has already been 1342 * created) 1343 */ 1344 intermediate2 = find_child_by_name(intermediate, labelp); 1345 if (intermediate2 == 0) { 1346 /* 1347 * need to create intermediate fru node node 1348 */ 1349 err = ptree_create_and_add_node(intermediate, labelp, 1350 PICL_CLASS_FRU, &intermediate2); 1351 if (err != PICL_SUCCESS) { 1352 syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err); 1353 return (err); 1354 } 1355 1356 /* 1357 * Create empty Devices table 1358 */ 1359 err = create_table(intermediate2, tblhdlp, PICL_PROP_DEVICES); 1360 if (err != PICL_SUCCESS) 1361 return (err); 1362 1363 if (fru_name) { 1364 err = add_prop_charstring(intermediate2, fru_name, 1365 PICL_PROP_FRU_TYPE); 1366 if (err != PICL_SUCCESS) 1367 return (err); 1368 } 1369 } else { 1370 err = ptree_get_propval_by_name(intermediate2, 1371 PICL_PROP_DEVICES, tblhdlp, sizeof (*tblhdlp)); 1372 if (err != PICL_SUCCESS) 1373 return (err); 1374 } 1375 *nodep = intermediate2; 1376 return (PICL_SUCCESS); 1377 } 1378 1379 /* 1380 * need to remove _fru_parent property and Environment table (for cpu) 1381 */ 1382 static int 1383 remove_references(picl_prophdl_t refprop, char *class) 1384 { 1385 picl_prophdl_t platprop; 1386 int err; 1387 1388 err = ptree_get_prop_by_name(refprop, PICL_REFPROP_FRU_PARENT, 1389 &platprop); 1390 if (err != PICL_SUCCESS) { 1391 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1392 return (err); 1393 } 1394 err = ptree_delete_prop(platprop); 1395 if (err != PICL_SUCCESS) { 1396 syslog(LOG_ERR, DELETE_PROP_FAIL, err); 1397 return (err); 1398 } 1399 (void) ptree_destroy_prop(platprop); 1400 if (strcmp(class, PICL_CLASS_CPU) == 0) { 1401 err = ptree_get_prop_by_name(refprop, PICL_PROP_ENV, &platprop); 1402 if (err != PICL_SUCCESS) { 1403 /* 1404 * multi-core cpu is setup with only one cpu having 1405 * env table so ignore PICL_PROPNOTFOUND error. 1406 */ 1407 if (err == PICL_PROPNOTFOUND) { 1408 return (PICL_SUCCESS); 1409 } 1410 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_ENV, err); 1411 return (err); 1412 } 1413 err = ptree_delete_prop(platprop); 1414 if (err != PICL_SUCCESS) { 1415 syslog(LOG_ERR, DELETE_PROP_FAIL, err); 1416 return (err); 1417 } 1418 (void) ptree_destroy_prop(platprop); 1419 } 1420 return (PICL_SUCCESS); 1421 } 1422 1423 /* 1424 * subroutine for various functions. Finds immediate child of parh with 1425 * requested name if present. Otherwise returns NULL. 1426 */ 1427 static picl_nodehdl_t 1428 find_child_by_name(picl_nodehdl_t parh, char *name) 1429 { 1430 picl_nodehdl_t nodeh; 1431 int err; 1432 char nodename[PICL_PROPNAMELEN_MAX]; 1433 1434 err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD, 1435 &nodeh, sizeof (picl_nodehdl_t)); 1436 if (err != PICL_SUCCESS) 1437 return (0); 1438 for (;;) { 1439 err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename, 1440 sizeof (nodename)); 1441 if (err != PICL_SUCCESS) 1442 return (0); 1443 if (strcmp(name, nodename) == 0) { 1444 return (nodeh); 1445 } 1446 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER, 1447 &nodeh, sizeof (picl_nodehdl_t)); 1448 if (err != PICL_SUCCESS) 1449 return (0); 1450 } 1451 } 1452 1453 static int 1454 create_dimm_references(picl_nodehdl_t parh, int dimm_id, 1455 picl_nodehdl_t nodeh, picl_prophdl_t tblhdl) 1456 { 1457 int err; 1458 picl_nodehdl_t memctlhdl = 0; 1459 picl_nodehdl_t memgrphdl; 1460 picl_nodehdl_t memhdl; 1461 char name[MAXPATHLEN]; 1462 char sbname[PICL_PROPNAMELEN_MAX]; 1463 char pname[PICL_PROPNAMELEN_MAX]; 1464 char bname[PICL_PROPNAMELEN_MAX]; 1465 picl_nodehdl_t parentfruh; 1466 picl_nodehdl_t parentloch; 1467 int id; 1468 1469 /* 1470 * create reference properties for memory nodes 1471 * - first find names of ancestor frus - ie "SBx/Py/Bz" 1472 */ 1473 err = ptree_get_propval_by_name(parh, PICL_PROP_PARENT, &parentfruh, 1474 sizeof (picl_nodehdl_t)); 1475 if (err != PICL_SUCCESS) { 1476 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1477 return (err); 1478 } 1479 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, 1480 bname, sizeof (bname)); 1481 if (err != PICL_SUCCESS) { 1482 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err); 1483 return (err); 1484 } 1485 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT, 1486 &parentloch, sizeof (picl_nodehdl_t)); 1487 if (err != PICL_SUCCESS) { 1488 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1489 return (err); 1490 } 1491 err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT, 1492 &parentfruh, sizeof (picl_nodehdl_t)); 1493 if (err != PICL_SUCCESS) { 1494 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1495 return (err); 1496 } 1497 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, 1498 pname, sizeof (pname)); 1499 if (err != PICL_SUCCESS) { 1500 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err); 1501 return (err); 1502 } 1503 1504 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT, 1505 &parentloch, sizeof (picl_nodehdl_t)); 1506 if (err != PICL_SUCCESS) { 1507 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1508 return (err); 1509 } 1510 err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT, 1511 &parentfruh, sizeof (picl_nodehdl_t)); 1512 if (err != PICL_SUCCESS) { 1513 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1514 return (err); 1515 } 1516 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname, 1517 sizeof (sbname)); 1518 if (err != PICL_SUCCESS) { 1519 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err); 1520 return (err); 1521 } 1522 1523 /* 1524 * ok - we've now got name of system board node in sbname and 1525 * name of processor node in pname. 1526 * Now find corresponding memory-controller node if present 1527 */ 1528 sprintf_buf2(name, MEMORY_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname)); 1529 err = ptree_get_node_by_path(name, &memctlhdl); 1530 if (err != PICL_SUCCESS) 1531 return (PICL_SUCCESS); 1532 1533 /* 1534 * now find corresponding memory-module-group node if present 1535 */ 1536 err = ptree_get_propval_by_name(memctlhdl, PICL_PROP_CHILD, &memgrphdl, 1537 sizeof (picl_nodehdl_t)); 1538 if (err != PICL_SUCCESS) 1539 return (PICL_SUCCESS); 1540 1541 /* 1542 * check if this is the right bank - if not move on to sibling 1543 */ 1544 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID, 1545 &id, sizeof (int)); 1546 if (err != PICL_SUCCESS) 1547 return (PICL_SUCCESS); 1548 if (bname[1] != id + '0') { 1549 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_PEER, 1550 &memgrphdl, sizeof (picl_nodehdl_t)); 1551 if (err != PICL_SUCCESS) 1552 return (PICL_SUCCESS); 1553 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID, 1554 &id, sizeof (int)); 1555 if (err != PICL_SUCCESS) 1556 return (PICL_SUCCESS); 1557 if (bname[1] != id + '0') 1558 return (PICL_SUCCESS); 1559 } 1560 1561 /* 1562 * now find corresponding memory-module node if present 1563 */ 1564 err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_CHILD, &memhdl, 1565 sizeof (picl_nodehdl_t)); 1566 if (err != PICL_SUCCESS) 1567 return (PICL_SUCCESS); 1568 1569 /* 1570 * for each DIMM set up links with matching memory-module node 1571 */ 1572 for (;;) { 1573 err = ptree_get_propval_by_name(memhdl, PICL_PROP_ID, 1574 &id, sizeof (int)); 1575 if (err == PICL_SUCCESS && dimm_id == id) { 1576 err = add_prop_ref(memhdl, nodeh, 1577 PICL_REFPROP_FRU_PARENT); 1578 if (err != PICL_SUCCESS) 1579 return (err); 1580 err = create_table_entry(tblhdl, memhdl, 1581 PICL_CLASS_MEMORY_MODULE); 1582 if (err != PICL_SUCCESS) 1583 return (err); 1584 } 1585 err = ptree_get_propval_by_name(memhdl, PICL_PROP_PEER, 1586 &memhdl, sizeof (picl_nodehdl_t)); 1587 if (err != PICL_SUCCESS) 1588 break; 1589 } 1590 return (PICL_SUCCESS); 1591 } 1592 1593 static int 1594 create_cpu_references(char *pname, picl_nodehdl_t nodeh, picl_prophdl_t tblhdl) 1595 { 1596 int err; 1597 picl_nodehdl_t sensorhdl; 1598 picl_nodehdl_t parentloch; 1599 picl_nodehdl_t parentfruh; 1600 picl_nodehdl_t cpuhdl; 1601 picl_nodehdl_t cpuhdl1; 1602 picl_prophdl_t envtblhdl; 1603 picl_prophdl_t prophdl; 1604 char name[MAXPATHLEN]; 1605 char sbname[PICL_PROPNAMELEN_MAX]; 1606 1607 err = ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT, 1608 &parentloch, sizeof (picl_nodehdl_t)); 1609 if (err != PICL_SUCCESS) { 1610 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1611 return (err); 1612 } 1613 err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT, 1614 &parentfruh, sizeof (picl_nodehdl_t)); 1615 if (err != PICL_SUCCESS) { 1616 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 1617 return (err); 1618 } 1619 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname, 1620 sizeof (sbname)); 1621 if (err != PICL_SUCCESS) { 1622 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err); 1623 return (err); 1624 } 1625 1626 /* 1627 * Find corresponding cpu node if present. Note, this code will 1628 * attempt to find a corresponding cpu node, by searching for devices 1629 * of the types /platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0, 1630 * /platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0 or 1631 * /platform/ssm@0,0/cmp@%x,0/cpu@0 or 1. If we can not find 1632 * any such device, we return PICL_SUCCESS such that we 1633 * continue the construction of the remaining part of the 1634 * tree. We first check for UltraSPARC-III. If we do not 1635 * find such a device we check for UltraSPARC-III+. If 1636 * we are unsuccesful again we try one of the jaguar cores 1637 * /platform/ssm@0,0/cmp@%x,0/cpu@. If we do not find the 1638 * first one, there's no point in continuing and we just 1639 * return PICL_SUCCESS. Similarly if we find one core 1640 * but not the other, something must be wrong, so we 1641 * again just return PICL_SUCCESS without creating any 1642 * references. 1643 */ 1644 sprintf_buf2(name, CPU_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname)); 1645 1646 err = ptree_get_node_by_path(name, &cpuhdl); 1647 1648 if (err != PICL_SUCCESS) { 1649 sprintf_buf2(name, CPU_DEV2, 1650 SB_P_TO_SAFARI_ADDR(sbname, pname)); 1651 err = ptree_get_node_by_path(name, &cpuhdl); 1652 if (err != PICL_SUCCESS) { 1653 /* check for jaguar cores */ 1654 sprintf_buf2(name, CPU_DEV3C1, 1655 SB_P_TO_SAFARI_ADDR(sbname, pname)); 1656 err = ptree_get_node_by_path(name, &cpuhdl1); 1657 if (err != PICL_SUCCESS) 1658 return (PICL_SUCCESS); 1659 /* add fru parent reference for the second core */ 1660 err = ptree_get_prop_by_name(cpuhdl1, 1661 PICL_REFPROP_FRU_PARENT, &prophdl); 1662 if (err != PICL_SUCCESS) { 1663 err = add_prop_ref(cpuhdl1, nodeh, 1664 PICL_REFPROP_FRU_PARENT); 1665 if (err != PICL_SUCCESS) 1666 return (err); 1667 err = create_table_entry(tblhdl, cpuhdl1, 1668 PICL_CLASS_CPU); 1669 if (err != PICL_SUCCESS) 1670 return (err); 1671 } 1672 sprintf_buf2(name, CPU_DEV3C0, 1673 SB_P_TO_SAFARI_ADDR(sbname, pname)); 1674 err = ptree_get_node_by_path(name, &cpuhdl); 1675 if (err != PICL_SUCCESS) 1676 return (PICL_SUCCESS); 1677 1678 } 1679 } 1680 1681 /* 1682 * now create reference properties 1683 */ 1684 err = ptree_get_prop_by_name(cpuhdl, PICL_REFPROP_FRU_PARENT, &prophdl); 1685 if (err != PICL_SUCCESS) { 1686 err = add_prop_ref(cpuhdl, nodeh, PICL_REFPROP_FRU_PARENT); 1687 if (err != PICL_SUCCESS) 1688 return (err); 1689 err = create_table_entry(tblhdl, cpuhdl, PICL_CLASS_CPU); 1690 if (err != PICL_SUCCESS) 1691 return (err); 1692 } 1693 1694 /* 1695 * create Environment table on cpu node - with Die and Ambient 1696 * temperature sensors if present. If already there, delete and start 1697 * again 1698 */ 1699 err = ptree_get_prop_by_name(cpuhdl, PICL_PROP_ENV, &prophdl); 1700 if (err == PICL_SUCCESS) { 1701 err = ptree_delete_prop(prophdl); 1702 if (err != PICL_SUCCESS) 1703 return (err); 1704 (void) ptree_destroy_prop(prophdl); 1705 } 1706 err = create_table(cpuhdl, &envtblhdl, PICL_PROP_ENV); 1707 if (err != PICL_SUCCESS) 1708 return (err); 1709 1710 if (pcix_io) 1711 sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV_PCIX, sbname, 1712 (pname[1] - '0')); 1713 else 1714 sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV, sbname, 1715 (pname[1] - '0')); 1716 1717 err = ptree_get_node_by_path(name, &sensorhdl); 1718 if (err == PICL_SUCCESS) { 1719 err = create_table_entry(envtblhdl, sensorhdl, 1720 PICL_CLASS_TEMPERATURE_SENSOR); 1721 if (err != PICL_SUCCESS) 1722 return (err); 1723 } 1724 1725 if (pcix_io) 1726 sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV_PCIX, sbname, 1727 (pname[1] - '0')); 1728 else 1729 sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV, sbname, 1730 (pname[1] - '0')); 1731 1732 err = ptree_get_node_by_path(name, &sensorhdl); 1733 if (err == PICL_SUCCESS) { 1734 return (create_table_entry(envtblhdl, sensorhdl, 1735 PICL_CLASS_TEMPERATURE_SENSOR)); 1736 } 1737 return (PICL_SUCCESS); 1738 } 1739 1740 /* 1741 * subroutine of add_subtree - get a list of children of a parent node 1742 */ 1743 static sgfrunode_t * 1744 get_node_children(fru_hdl_t fruparent, int *num_childrenp) 1745 { 1746 int max_children, i; 1747 sgfrunode_t *fruchildren = NULL; 1748 child_info_t child_info; 1749 int frufd; 1750 1751 /* 1752 * Open the sgfru pseudo dev 1753 */ 1754 if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, 0)) == -1) { 1755 syslog(LOG_ERR, DEV_OPEN_FAIL, FRU_PSEUDO_DEV, strerror(errno)); 1756 return (NULL); 1757 } 1758 for (i = 1; i <= MAX_TRIES; i++) { 1759 max_children = i * MAX_NODE_CHILDREN; 1760 if ((fruchildren = calloc(max_children, 1761 sizeof (sgfrunode_t))) == NULL) { 1762 (void) close(frufd); 1763 syslog(LOG_ERR, MALLOC_FAIL); 1764 return (NULL); 1765 } 1766 child_info.fru_hdl = fruparent; 1767 child_info.fru_cnt = max_children; 1768 child_info.frus = (void *)fruchildren; 1769 if (ioctl(frufd, SGFRU_GETCHILDLIST, &child_info) == 0) { 1770 /* 1771 * got them - return success 1772 */ 1773 (void) close(frufd); 1774 *num_childrenp = child_info.fru_cnt; 1775 return (fruchildren); 1776 } 1777 free(fruchildren); 1778 1779 /* 1780 * if ENOMEM, need to calloc more space - so go round loop again 1781 * otherwise fail 1782 */ 1783 if (errno != ENOMEM) { 1784 (void) close(frufd); 1785 syslog(LOG_ERR, SGFRU_IOCTL_FAIL, SGFRU_GETCHILDLIST, 1786 fruparent, strerror(errno)); 1787 return (NULL); 1788 } 1789 } 1790 (void) close(frufd); 1791 syslog(LOG_ERR, MALLOC_FAIL); 1792 return (NULL); 1793 } 1794 1795 /* Creates an unsigned longlong property for a given PICL node */ 1796 static int 1797 add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name) 1798 { 1799 picl_prophdl_t proph; 1800 ptree_propinfo_t propinfo; 1801 int err; 1802 1803 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1804 PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (unsigned long long), 1805 PICL_PROP_SC_HANDLE, NULL, NULL); 1806 if (err != PICL_SUCCESS) { 1807 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 1808 return (err); 1809 } 1810 err = ptree_create_and_add_prop(nodeh, &propinfo, &handle, &proph); 1811 if (err != PICL_SUCCESS) { 1812 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 1813 return (err); 1814 } 1815 return (PICL_SUCCESS); 1816 } 1817 1818 /* Creates a void property for a given PICL node */ 1819 static int 1820 add_prop_void(picl_nodehdl_t nodeh, char *name) 1821 { 1822 picl_prophdl_t proph; 1823 ptree_propinfo_t propinfo; 1824 int err; 1825 1826 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1827 PICL_PTYPE_VOID, PICL_READ, 0, PICL_PROP_FRUDATA_AVAIL, NULL, NULL); 1828 if (err != PICL_SUCCESS) { 1829 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 1830 return (err); 1831 } 1832 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph); 1833 if (err != PICL_SUCCESS) { 1834 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 1835 return (err); 1836 } 1837 return (PICL_SUCCESS); 1838 } 1839 1840 /* Creates a reference property for a given PICL node */ 1841 static int 1842 add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name) 1843 { 1844 picl_prophdl_t proph; 1845 ptree_propinfo_t propinfo; 1846 int err; 1847 1848 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1849 PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name, 1850 NULL, NULL); 1851 if (err != PICL_SUCCESS) { 1852 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 1853 return (err); 1854 } 1855 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph); 1856 if (err != PICL_SUCCESS) { 1857 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 1858 return (err); 1859 } 1860 return (PICL_SUCCESS); 1861 } 1862 1863 /* Creates an integer property for a given PICL node */ 1864 static int 1865 add_prop_int(picl_nodehdl_t nodeh, int value, char *name) 1866 { 1867 picl_prophdl_t proph; 1868 ptree_propinfo_t propinfo; 1869 int err; 1870 1871 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1872 PICL_PTYPE_INT, PICL_READ, sizeof (int), name, NULL, NULL); 1873 if (err != PICL_SUCCESS) { 1874 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 1875 return (err); 1876 } 1877 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph); 1878 if (err != PICL_SUCCESS) { 1879 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 1880 return (err); 1881 } 1882 return (PICL_SUCCESS); 1883 } 1884 1885 /* Creates an integer property for a given PICL node */ 1886 static int 1887 add_prop_float(picl_nodehdl_t nodeh, float value, char *name) 1888 { 1889 picl_prophdl_t proph; 1890 ptree_propinfo_t propinfo; 1891 int err; 1892 1893 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1894 PICL_PTYPE_FLOAT, PICL_READ, sizeof (float), name, NULL, NULL); 1895 if (err != PICL_SUCCESS) { 1896 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 1897 return (err); 1898 } 1899 err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph); 1900 if (err != PICL_SUCCESS) { 1901 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 1902 return (err); 1903 } 1904 return (PICL_SUCCESS); 1905 } 1906 1907 /* Creates a charstring property for a given PICL node */ 1908 static int 1909 add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name) 1910 { 1911 picl_prophdl_t proph; 1912 ptree_propinfo_t propinfo; 1913 int err; 1914 1915 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 1916 PICL_PTYPE_CHARSTRING, PICL_READ, strlen(value) + 1, 1917 name, NULL, NULL); 1918 if (err != PICL_SUCCESS) { 1919 syslog(LOG_ERR, PROPINFO_FAIL, name, err); 1920 return (err); 1921 } 1922 err = ptree_create_and_add_prop(nodeh, &propinfo, value, &proph); 1923 if (err != PICL_SUCCESS) { 1924 syslog(LOG_ERR, ADD_PROP_FAIL, name, err); 1925 return (err); 1926 } 1927 return (PICL_SUCCESS); 1928 } 1929 1930 /* create an entry in the specified table */ 1931 static int 1932 create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class) 1933 { 1934 int err; 1935 ptree_propinfo_t prop; 1936 picl_prophdl_t prophdl[2]; 1937 1938 /* first column is class */ 1939 prop.version = PTREE_PROPINFO_VERSION; 1940 prop.piclinfo.type = PICL_PTYPE_CHARSTRING; 1941 prop.piclinfo.accessmode = PICL_READ; 1942 prop.piclinfo.size = PICL_CLASSNAMELEN_MAX; 1943 prop.read = NULL; 1944 prop.write = NULL; 1945 (void) strlcpy(prop.piclinfo.name, PICL_PROP_CLASS, 1946 sizeof (prop.piclinfo.name)); 1947 err = ptree_create_prop(&prop, class, &prophdl[0]); 1948 if (err != PICL_SUCCESS) { 1949 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err); 1950 return (err); 1951 } 1952 1953 /* second column is refernce property */ 1954 prop.version = PTREE_PROPINFO_VERSION; 1955 prop.piclinfo.type = PICL_PTYPE_REFERENCE; 1956 prop.piclinfo.accessmode = PICL_READ; 1957 prop.piclinfo.size = sizeof (picl_nodehdl_t); 1958 prop.read = NULL; 1959 prop.write = NULL; 1960 sprintf_buf2(prop.piclinfo.name, "_%s_", class); 1961 err = ptree_create_prop(&prop, &refhdl, &prophdl[1]); 1962 if (err != PICL_SUCCESS) { 1963 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err); 1964 return (err); 1965 } 1966 1967 /* add row to table */ 1968 err = ptree_add_row_to_table(tblhdl, 2, prophdl); 1969 if (err != PICL_SUCCESS) 1970 syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err); 1971 return (err); 1972 } 1973 1974 /* create an empty table property */ 1975 static int 1976 create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name) 1977 { 1978 int err; 1979 ptree_propinfo_t prop; 1980 picl_prophdl_t tblprophdl; 1981 1982 err = ptree_create_table(tblhdlp); 1983 if (err != PICL_SUCCESS) { 1984 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err); 1985 return (err); 1986 } 1987 prop.version = PTREE_PROPINFO_VERSION; 1988 prop.piclinfo.type = PICL_PTYPE_TABLE; 1989 prop.piclinfo.accessmode = PICL_READ; 1990 prop.piclinfo.size = sizeof (picl_prophdl_t); 1991 prop.read = NULL; 1992 prop.write = NULL; 1993 (void) strlcpy(prop.piclinfo.name, tbl_name, 1994 sizeof (prop.piclinfo.name)); 1995 err = ptree_create_and_add_prop(fruhdl, &prop, tblhdlp, &tblprophdl); 1996 if (err != PICL_SUCCESS) 1997 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err); 1998 return (err); 1999 } 2000 2001 static void 2002 frudr_add_subtree(picl_nodehdl_t parh) 2003 { 2004 fru_hdl_t sgfruhdl; 2005 if (ptree_get_propval_by_name(parh, PICL_PROP_SC_HANDLE, 2006 &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) { 2007 return; 2008 } 2009 (void) add_subtree(parh, sgfruhdl); 2010 } 2011 2012 /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */ 2013 /*ARGSUSED*/ 2014 static void 2015 frudr_completion_handler(char *ename, void *earg, size_t size) 2016 { 2017 picl_nodehdl_t fruh; 2018 picl_nodehdl_t parh; 2019 2020 if (strcmp(ename, PICL_FRU_REMOVED) == 0) { 2021 /* 2022 * now frudata has been notified that the node is to be 2023 * removed, we can actually remove it 2024 */ 2025 fruh = 0; 2026 (void) nvlist_lookup_uint64(earg, 2027 PICLEVENTARG_FRUHANDLE, &fruh); 2028 if (fruh != 0) { 2029 (void) remove_subtree(fruh); 2030 2031 /* 2032 * Now repopulate the frutree with current data. 2033 */ 2034 parh = 0; 2035 (void) nvlist_lookup_uint64(earg, 2036 PICLEVENTARG_PARENTHANDLE, &parh); 2037 if (parh != 0) { 2038 frudr_add_subtree(parh); 2039 } 2040 } 2041 } 2042 nvlist_free(earg); 2043 free(earg); 2044 free(ename); 2045 } 2046 2047 /* 2048 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event 2049 */ 2050 static void 2051 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh) 2052 { 2053 nvlist_t *nvl; 2054 char *ev_name; 2055 2056 ev_name = strdup(ename); 2057 if (ev_name == NULL) 2058 return; 2059 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) { 2060 free(ev_name); 2061 return; 2062 } 2063 if (parenth != 0L && 2064 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) { 2065 free(ev_name); 2066 nvlist_free(nvl); 2067 return; 2068 } 2069 if (fruh != 0L && 2070 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) { 2071 free(ev_name); 2072 nvlist_free(nvl); 2073 return; 2074 } 2075 if (ptree_post_event(ev_name, nvl, sizeof (nvl), 2076 frudr_completion_handler) != 0) { 2077 free(ev_name); 2078 nvlist_free(nvl); 2079 } 2080 } 2081 2082 /* 2083 * updates the picl node 'loc' with the new fru handle (PICL_PROP_SC_HANDLE) 2084 * (helper function for frudr_evhandler, when a stale fru handle is 2085 * detected) 2086 */ 2087 static void 2088 update_fru_hdl(picl_nodehdl_t loc, fru_hdl_t newsgfruhdl) 2089 { 2090 picl_prophdl_t schproph; 2091 int err; 2092 2093 err = ptree_get_prop_by_name(loc, PICL_PROP_SC_HANDLE, &schproph); 2094 if (err == PICL_SUCCESS) { 2095 if (ptree_delete_prop(schproph) == PICL_SUCCESS) { 2096 (void) ptree_destroy_prop(schproph); 2097 } 2098 } 2099 (void) add_prop_ull(loc, (uint64_t)newsgfruhdl, PICL_PROP_SC_HANDLE); 2100 } 2101 2102 /* 2103 * Get the fru handle of loc by iterating through the parent's children. 2104 * Sets fruhdl and returns PICL_SUCCESS unless an error is encountered. 2105 */ 2106 static int 2107 get_fruhdl_from_parent(picl_nodehdl_t loc, fru_hdl_t *fruhdl) 2108 { 2109 picl_nodehdl_t parlocnodeh; 2110 fru_hdl_t parsgfruhdl; 2111 sgfrunode_t *cp; 2112 sgfrunode_t *fruchildren; 2113 char nodename[PICL_PROPNAMELEN_MAX]; 2114 int err; 2115 int num_children; 2116 int i; 2117 2118 err = ptree_get_propval_by_name(loc, PICL_PROP_NAME, (void *)nodename, 2119 PICL_PROPNAMELEN_MAX); 2120 if (err != PICL_SUCCESS) 2121 return (err); 2122 err = ptree_get_propval_by_name(loc, PICL_PROP_PARENT, &parlocnodeh, 2123 sizeof (picl_nodehdl_t)); 2124 if (err != PICL_SUCCESS) 2125 return (err); 2126 if ((err = ptree_get_propval_by_name(parlocnodeh, PICL_PROP_SC_HANDLE, 2127 &parsgfruhdl, sizeof (parsgfruhdl))) != PICL_SUCCESS) 2128 return (err); 2129 /* find children of the parent node */ 2130 fruchildren = get_node_children(parsgfruhdl, &num_children); 2131 if (fruchildren == NULL) 2132 return (PICL_FAILURE); 2133 for (i = 0, cp = fruchildren; i < num_children; i++, cp++) { 2134 /* find the child we're interested in */ 2135 if (strcmp(cp->nodename, nodename) == 0) { 2136 *fruhdl = cp->handle; 2137 free(fruchildren); 2138 return (PICL_SUCCESS); 2139 } 2140 } 2141 free(fruchildren); 2142 return (PICL_FAILURE); 2143 } 2144 2145 /* 2146 * handle EC_DR picl events 2147 */ 2148 /*ARGSUSED*/ 2149 static void 2150 frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie) 2151 { 2152 nvlist_t *nvlp; 2153 char *dtype; 2154 char *ap_id; 2155 char *hint; 2156 char path[MAXPATHLEN]; 2157 picl_nodehdl_t fruh; 2158 picl_nodehdl_t locnodeh; 2159 fru_hdl_t sgfruhdl; 2160 fru_hdl_t sgfruhdl_from_parent; 2161 2162 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0) 2163 return; 2164 2165 if (nvlist_unpack((char *)earg, size, &nvlp, 0)) 2166 return; 2167 2168 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) { 2169 nvlist_free(nvlp); 2170 return; 2171 } 2172 2173 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) { 2174 nvlist_free(nvlp); 2175 return; 2176 } 2177 2178 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) { 2179 nvlist_free(nvlp); 2180 return; 2181 } 2182 2183 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) { 2184 nvlist_free(nvlp); 2185 return; 2186 } 2187 2188 if (strncmp(ap_id, AP_ID_PREAMBLE, AP_ID_PREAMBLE_LEN) != 0) { 2189 nvlist_free(nvlp); 2190 return; 2191 } 2192 2193 /* 2194 * OK - so this is an EC_DR event - let's handle it. 2195 */ 2196 sprintf_buf2(path, CHASSIS_LOC_PATH, &ap_id[AP_ID_PREAMBLE_LEN]); 2197 2198 /* 2199 * special case - SSC arrival means that SSC has been reset - we 2200 * need to flush the cached sgfru handles 2201 */ 2202 if (strcmp(&ap_id[AP_ID_PREAMBLE_LEN], "SSC1") == 0) { 2203 picl_nodehdl_t chdh; 2204 picl_nodehdl_t peerh; 2205 picl_nodehdl_t parh; 2206 int got_peer; 2207 char label[MAX_LABEL_LEN]; 2208 int err; 2209 sgfrunode_t *sgfruchassisp = NULL; 2210 int num_children; 2211 picl_prophdl_t schproph; 2212 2213 /* find existing chassis node */ 2214 if (ptree_get_node_by_path(CHASSIS_PATH, &parh) != 2215 PICL_SUCCESS) { 2216 nvlist_free(nvlp); 2217 return; 2218 } 2219 2220 /* find new chassis sgfru node */ 2221 sgfruchassisp = get_node_children(ROOTPARENT, &num_children); 2222 if (sgfruchassisp == NULL || num_children != 1) { 2223 nvlist_free(nvlp); 2224 return; 2225 } 2226 2227 /* update chassis SC_HANDLE property */ 2228 err = ptree_get_prop_by_name(parh, PICL_PROP_SC_HANDLE, 2229 &schproph); 2230 if (err != PICL_SUCCESS) { 2231 nvlist_free(nvlp); 2232 return; 2233 } 2234 err = ptree_delete_prop(schproph); 2235 if (err != PICL_SUCCESS) { 2236 nvlist_free(nvlp); 2237 return; 2238 } 2239 (void) ptree_destroy_prop(schproph); 2240 err = add_prop_ull(parh, sgfruchassisp->handle, 2241 PICL_PROP_SC_HANDLE); 2242 if (err != PICL_SUCCESS) { 2243 nvlist_free(nvlp); 2244 return; 2245 } 2246 2247 /* 2248 * remove all subtrees except DISK, TAPE, DVD and PCI subtrees 2249 */ 2250 if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh, 2251 sizeof (picl_nodehdl_t)) == PICL_SUCCESS) { 2252 for (;;) { 2253 if (ptree_get_propval_by_name(chdh, 2254 PICL_PROP_PEER, &peerh, 2255 sizeof (picl_nodehdl_t)) != PICL_SUCCESS) 2256 got_peer = 0; 2257 else 2258 got_peer = 1; 2259 err = ptree_get_propval_by_name(chdh, 2260 PICL_PROP_LABEL, label, sizeof (label)); 2261 if (err == PICL_SUCCESS) { 2262 if (strncmp(label, "DISK", 2263 strlen("DISK")) != 0 && 2264 strncmp(label, "TAPE", 2265 strlen("TAPE")) != 0 && 2266 strncmp(label, "PCI", 2267 strlen("PCI")) != 0 && 2268 strncmp(label, "DVD", 2269 strlen("DVD")) != 0) { 2270 (void) remove_subtree(chdh); 2271 } 2272 } 2273 if (got_peer == 0) 2274 break; 2275 chdh = peerh; 2276 } 2277 } 2278 2279 /* add new subtrees */ 2280 (void) add_subtree(parh, sgfruchassisp->handle); 2281 free(sgfruchassisp); 2282 2283 nvlist_free(nvlp); 2284 return; 2285 } 2286 2287 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) { 2288 nvlist_free(nvlp); 2289 return; 2290 } 2291 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_SC_HANDLE, 2292 &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) { 2293 nvlist_free(nvlp); 2294 return; 2295 } 2296 2297 /* 2298 * now either add or delete the fru node as appropriate. If no 2299 * hint, treat as insert - add_subtree will update the tree if 2300 * necessary. 2301 */ 2302 if (strcmp(hint, DR_HINT_REMOVE) == 0) { 2303 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD, 2304 &fruh, sizeof (picl_nodehdl_t)) != PICL_PROPNOTFOUND) { 2305 /* 2306 * fru was there - but has gone away 2307 */ 2308 post_frudr_event(PICL_FRU_REMOVED, locnodeh, fruh); 2309 } 2310 } else { 2311 /* 2312 * fru has been inserted (or may need to update) 2313 * 2314 * sgfruhdl may be stale due to hotplugging. We check this 2315 * by getting the fru_hdl_t from the parent's children 2316 * and compare it to the cached value in sgfruhdl. If we 2317 * have a stale handle, we update the cached value and 2318 * use it in the call to add_subtree. 2319 */ 2320 if (get_fruhdl_from_parent(locnodeh, &sgfruhdl_from_parent) == 2321 PICL_SUCCESS) { 2322 if (sgfruhdl != sgfruhdl_from_parent) { 2323 update_fru_hdl(locnodeh, sgfruhdl_from_parent); 2324 sgfruhdl = sgfruhdl_from_parent; 2325 } 2326 } 2327 2328 (void) add_subtree(locnodeh, sgfruhdl); 2329 } 2330 nvlist_free(nvlp); 2331 } 2332 2333 /* 2334 * handle memcfg picl events - need to update reference properties 2335 */ 2336 /*ARGSUSED*/ 2337 static void 2338 frumemcfg_evhandler(const char *ename, const void *earg, size_t size, 2339 void *cookie) 2340 { 2341 picl_nodehdl_t nodeh; 2342 picl_nodehdl_t lochdl; 2343 picl_nodehdl_t fruhdl; 2344 picl_nodehdl_t memgrphdl; 2345 picl_nodehdl_t memhdl; 2346 picl_prophdl_t tblhdl; 2347 picl_prophdl_t tblproph; 2348 nvlist_t *nvlp; 2349 char addr[MAXPATHLEN]; 2350 char bname[PICL_PROPNAMELEN_MAX]; 2351 picl_nodehdl_t banklochdl; 2352 picl_nodehdl_t bankfruhdl; 2353 char label[MAX_LABEL_LEN]; 2354 int err; 2355 int id; 2356 char *ptr; 2357 int value; 2358 char buf[MAX_LINE_SIZE]; 2359 2360 if (strcmp(ename, PICLEVENT_MC_ADDED) != 0 && 2361 strcmp(ename, PICLEVENT_MC_REMOVED) != 0) 2362 return; 2363 2364 /* 2365 * find corresponding frutree dimm nodes 2366 */ 2367 if (nvlist_unpack((char *)earg, size, &nvlp, 0)) 2368 return; 2369 if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh)) { 2370 nvlist_free(nvlp); 2371 return; 2372 } 2373 nvlist_free(nvlp); 2374 err = ptree_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, addr, 2375 sizeof (addr)); 2376 if (err != PICL_SUCCESS) 2377 return; 2378 ptr = strchr(addr, ','); 2379 if (ptr == NULL) 2380 return; 2381 *ptr = '\0'; 2382 value = strtol(addr, NULL, 16); 2383 sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value), 2384 SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value), 2385 SAFARI_ADDR_TO_P(value)); 2386 err = ptree_get_node_by_path(buf, &fruhdl); 2387 if (err != PICL_SUCCESS) 2388 return; 2389 err = ptree_get_propval_by_name(fruhdl, PICL_PROP_CHILD, 2390 &banklochdl, sizeof (banklochdl)); 2391 if (err != PICL_SUCCESS) 2392 return; 2393 2394 /* 2395 * walk through the DIMM locations 2396 */ 2397 for (;;) { 2398 err = ptree_get_propval_by_name(banklochdl, PICL_PROP_CHILD, 2399 &bankfruhdl, sizeof (bankfruhdl)); 2400 if (err != PICL_SUCCESS) 2401 goto next_bank; 2402 err = ptree_get_propval_by_name(bankfruhdl, PICL_PROP_CHILD, 2403 &lochdl, sizeof (lochdl)); 2404 if (err != PICL_SUCCESS) 2405 goto next_bank; 2406 for (;;) { 2407 err = ptree_get_propval_by_name(lochdl, PICL_PROP_CHILD, 2408 &fruhdl, sizeof (fruhdl)); 2409 if (err != PICL_SUCCESS) 2410 goto next_dimm; 2411 2412 /* 2413 * this is a frutree dimm node corresponding to the 2414 * memory controller that has been added/deleted 2415 * - so create/delete reference properties 2416 */ 2417 if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) { 2418 /* 2419 * find bank name 2420 */ 2421 err = ptree_get_propval_by_name(fruhdl, 2422 PICL_PROP_DEVICES, &tblhdl, 2423 sizeof (tblhdl)); 2424 if (err != PICL_SUCCESS) 2425 goto next_dimm; 2426 err = ptree_get_propval_by_name(lochdl, 2427 PICL_PROP_LABEL, label, sizeof (label)); 2428 if (err != PICL_SUCCESS) 2429 goto next_dimm; 2430 2431 err = ptree_get_propval_by_name(bankfruhdl, 2432 PICL_PROP_NAME, bname, sizeof (bname)); 2433 if (err != PICL_SUCCESS) 2434 goto next_dimm; 2435 2436 /* 2437 * find memory group node 2438 */ 2439 err = ptree_get_propval_by_name(nodeh, 2440 PICL_PROP_CHILD, &memgrphdl, 2441 sizeof (memgrphdl)); 2442 if (err != PICL_SUCCESS) 2443 goto next_dimm; 2444 2445 /* 2446 * check if this is the right bank - if not 2447 * move on to sibling 2448 */ 2449 err = ptree_get_propval_by_name(memgrphdl, 2450 PICL_PROP_ID, &id, sizeof (id)); 2451 if (err != PICL_SUCCESS) 2452 goto next_dimm; 2453 if (bname[1] != id + '0') { 2454 err = 2455 ptree_get_propval_by_name(memgrphdl, 2456 PICL_PROP_PEER, &memgrphdl, 2457 sizeof (memgrphdl)); 2458 if (err != PICL_SUCCESS) 2459 goto next_dimm; 2460 err = 2461 ptree_get_propval_by_name(memgrphdl, 2462 PICL_PROP_ID, &id, sizeof (id)); 2463 if (err != PICL_SUCCESS) 2464 goto next_dimm; 2465 if (bname[1] != id + '0') 2466 goto next_dimm; 2467 } 2468 2469 /* 2470 * got the right bank - now create appropriate 2471 * link 2472 */ 2473 err = ptree_get_propval_by_name(memgrphdl, 2474 PICL_PROP_CHILD, &memhdl, 2475 sizeof (memhdl)); 2476 if (err != PICL_SUCCESS) 2477 goto next_dimm; 2478 for (;;) { 2479 err = ptree_get_propval_by_name(memhdl, 2480 PICL_PROP_ID, &id, sizeof (id)); 2481 if (err != PICL_SUCCESS) 2482 goto next_dimm; 2483 if (label[1] == ('0' + id)) { 2484 err = add_prop_ref(memhdl, 2485 fruhdl, 2486 PICL_REFPROP_FRU_PARENT); 2487 if (err != PICL_SUCCESS) 2488 return; 2489 err = create_table_entry(tblhdl, 2490 memhdl, 2491 PICL_CLASS_MEMORY_MODULE); 2492 if (err != PICL_SUCCESS) 2493 return; 2494 } 2495 err = ptree_get_propval_by_name(memhdl, 2496 PICL_PROP_PEER, 2497 &memhdl, sizeof (memhdl)); 2498 if (err == PICL_PROPNOTFOUND) 2499 break; 2500 if (err != PICL_SUCCESS) 2501 return; 2502 } 2503 } else if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0) { 2504 /* 2505 * XXX - no mechanism for deleting row - so 2506 * delete whole tabel and start again 2507 */ 2508 err = ptree_get_prop_by_name(fruhdl, 2509 PICL_PROP_DEVICES, &tblproph); 2510 if (err == PICL_SUCCESS) { 2511 err = ptree_delete_prop(tblproph); 2512 if (err != PICL_SUCCESS) 2513 return; 2514 (void) ptree_destroy_prop(tblproph); 2515 } 2516 err = create_table(fruhdl, &tblhdl, 2517 PICL_PROP_DEVICES); 2518 if (err != PICL_SUCCESS) 2519 return; 2520 } 2521 next_dimm: 2522 err = ptree_get_propval_by_name(lochdl, 2523 PICL_PROP_PEER, &lochdl, sizeof (lochdl)); 2524 if (err == PICL_PROPNOTFOUND) 2525 break; 2526 if (err != PICL_SUCCESS) 2527 return; 2528 } 2529 next_bank: 2530 err = ptree_get_propval_by_name(banklochdl, 2531 PICL_PROP_PEER, &banklochdl, sizeof (banklochdl)); 2532 if (err == PICL_PROPNOTFOUND) 2533 break; 2534 if (err != PICL_SUCCESS) 2535 return; 2536 } 2537 /* 2538 * We don't get an event to say that cpu nodes have been added/ 2539 * deleted (in fact as things stand they are never deleted). However 2540 * we know that all cpus must be configured before the MC_ADDED event 2541 * we are handling here. So if the cpu links haven't been set up yet 2542 * then we do it now. 2543 */ 2544 if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) { 2545 sprintf_buf4(buf, PROC_LOC_PATH, SAFARI_ADDR_TO_SB(value), 2546 SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value)); 2547 err = ptree_get_node_by_path(buf, &lochdl); 2548 if (err != PICL_SUCCESS) 2549 return; 2550 sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value), 2551 SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value), 2552 SAFARI_ADDR_TO_P(value)); 2553 err = ptree_get_node_by_path(buf, &fruhdl); 2554 if (err != PICL_SUCCESS) 2555 return; 2556 sprintf_buf2(buf, "P%d", SAFARI_ADDR_TO_P(value)); 2557 err = ptree_get_propval_by_name(fruhdl, 2558 PICL_PROP_DEVICES, &tblhdl, sizeof (tblhdl)); 2559 if (err != PICL_SUCCESS) 2560 return; 2561 (void) create_cpu_references(buf, fruhdl, tblhdl); 2562 } 2563 } 2564 2565 /* 2566 * subroutine for add_env_nodes(), and add_led_node(). Adds a sensor 2567 * node under the sc node in the platform tree, of name "nodename" and 2568 * class "class". Also add UnitAddress property (always 0 as the nodenames 2569 * are unique anyway). Add reference property back to parent fru/location node 2570 * in frutree and a Devices table entry pointing to this node from the 2571 * parent fru/location node in frutree. 2572 */ 2573 static int 2574 add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl, char *nodename, 2575 char *class, char *prop_class, picl_prophdl_t tblhdl, 2576 picl_nodehdl_t *sensorhdlp) 2577 { 2578 int err; 2579 2580 err = ptree_create_and_add_node(sch, nodename, class, sensorhdlp); 2581 if (err != PICL_SUCCESS) { 2582 syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err); 2583 return (err); 2584 } 2585 2586 err = create_table_entry(tblhdl, *sensorhdlp, class); 2587 if (err != PICL_SUCCESS) 2588 return (err); 2589 2590 err = add_sensor_prop(*sensorhdlp, prop_class); 2591 if (err != PICL_SUCCESS) 2592 return (err); 2593 2594 err = add_prop_charstring(*sensorhdlp, "0", PICL_PROP_UNIT_ADDRESS); 2595 if (err != PICL_SUCCESS) 2596 return (err); 2597 2598 if (fruhdl != 0) { 2599 err = add_prop_ref(*sensorhdlp, fruhdl, 2600 PICL_REFPROP_FRU_PARENT); 2601 } else { 2602 err = add_prop_ref(*sensorhdlp, lochdl, 2603 PICL_REFPROP_LOC_PARENT); 2604 } 2605 return (err); 2606 } 2607 2608 /* 2609 * subroutine for add_sensor_node()/add_env_nodes(). Used for adding dynamic 2610 * properties 2611 */ 2612 static int 2613 add_sensor_prop(picl_nodehdl_t nodeh, char *class) 2614 { 2615 ptree_propinfo_t propinfo; 2616 int err; 2617 2618 if (strcmp(class, PICL_PROP_TEMPERATURE) == 0) { 2619 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2620 PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE, 2621 sizeof (int), class, get_sensor_data, NULL); 2622 } else if (strcmp(class, PICL_PROP_FAN_SPEED) == 0) { 2623 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2624 PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE, 2625 sizeof (int), class, get_sensor_data, NULL); 2626 } else if (strcmp(class, PICL_PROP_FAN_SPEED_UNIT) == 0) { 2627 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2628 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE, 2629 MAX_SPEED_UNIT_LEN, class, get_sensor_data, NULL); 2630 } else if (strcmp(class, PICL_PROP_CONDITION) == 0) { 2631 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2632 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE, 2633 MAX_CONDITION_LEN, class, get_sensor_data, NULL); 2634 } else if (strcmp(class, PICL_PROP_STATE) == 0) { 2635 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2636 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_WRITE + 2637 PICL_VOLATILE, MAX_STATE_LEN, class, get_led_data, 2638 set_led_data); 2639 } else { 2640 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 2641 PICL_PTYPE_FLOAT, PICL_READ + PICL_VOLATILE, 2642 sizeof (float), class, get_sensor_data, NULL); 2643 } 2644 if (err != PICL_SUCCESS) { 2645 syslog(LOG_ERR, PROPINFO_FAIL, class, err); 2646 return (err); 2647 } 2648 2649 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL); 2650 if (err != PICL_SUCCESS) { 2651 syslog(LOG_ERR, ADD_PROP_FAIL, class, err); 2652 return (err); 2653 } 2654 return (PICL_SUCCESS); 2655 } 2656 2657 /* 2658 * Get requested kstat 2659 */ 2660 static int 2661 open_kstat(char *name, void **ptr, kstat_ctl_t **kcp) 2662 { 2663 kstat_t *info_ksp; 2664 2665 *kcp = kstat_open(); 2666 if (*kcp == NULL) { 2667 syslog(LOG_ERR, KSTAT_FAIL); 2668 return (PICL_FAILURE); 2669 } 2670 info_ksp = kstat_lookup(*kcp, NULL, -1, name); 2671 if (info_ksp == NULL) { 2672 kstat_close(*kcp); 2673 syslog(LOG_ERR, KSTAT_FAIL); 2674 return (PICL_FAILURE); 2675 } 2676 if (kstat_read(*kcp, info_ksp, NULL) == -1) { 2677 kstat_close(*kcp); 2678 syslog(LOG_ERR, KSTAT_FAIL); 2679 return (PICL_FAILURE); 2680 } 2681 *ptr = info_ksp; 2682 return (PICL_SUCCESS); 2683 } 2684 2685 /* 2686 * dimm status - uses bank-status property on memory-controller node 2687 */ 2688 2689 static int 2690 get_dimm_status(ptree_rarg_t *arg, void *result) 2691 { 2692 int err; 2693 int i; 2694 picl_prophdl_t tblhdl; 2695 picl_prophdl_t nextprop; 2696 picl_prophdl_t refprop; 2697 picl_prophdl_t mmgprop; 2698 picl_prophdl_t mcprop; 2699 picl_prophdl_t bankprop; 2700 char nodename[PICL_PROPNAMELEN_MAX]; 2701 char class[PICL_CLASSNAMELEN_MAX]; 2702 char bankname[PICL_PROPNAMELEN_MAX]; 2703 char state[MAX_STATE_SIZE]; 2704 2705 /* 2706 * find the name of this node 2707 */ 2708 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, nodename, 2709 sizeof (nodename)); 2710 if (err != PICL_SUCCESS) { 2711 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err); 2712 return (err); 2713 } 2714 2715 /* 2716 * find the name of grandparent (dimm bank) node 2717 */ 2718 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &bankprop, 2719 sizeof (picl_nodehdl_t)); 2720 if (err != PICL_SUCCESS) { 2721 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 2722 return (err); 2723 } 2724 err = ptree_get_propval_by_name(bankprop, PICL_PROP_PARENT, &bankprop, 2725 sizeof (picl_nodehdl_t)); 2726 if (err != PICL_SUCCESS) { 2727 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 2728 return (err); 2729 } 2730 err = ptree_get_propval_by_name(bankprop, PICL_PROP_NAME, bankname, 2731 sizeof (bankname)); 2732 if (err != PICL_SUCCESS) { 2733 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err); 2734 return (err); 2735 } 2736 2737 /* 2738 * lookup memory-module node in Devices table 2739 */ 2740 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl, 2741 sizeof (tblhdl)); 2742 if (err != PICL_SUCCESS) { 2743 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err); 2744 return (err); 2745 } 2746 err = ptree_get_next_by_row(tblhdl, &nextprop); 2747 if (err != PICL_SUCCESS) { 2748 /* 2749 * if Devices table empty then dimm is unconfigured 2750 */ 2751 (void) strlcpy(result, PICL_PROPVAL_DISABLED, 2752 MAX_OPERATIONAL_STATUS_LEN); 2753 return (PICL_SUCCESS); 2754 } 2755 err = ptree_get_next_by_row(nextprop, &nextprop); 2756 if (err != PICL_SUCCESS) { 2757 syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err); 2758 return (err); 2759 } 2760 2761 /* 2762 * walk down second column (ref ptr) 2763 */ 2764 while (err == PICL_SUCCESS) { 2765 err = ptree_get_propval(nextprop, &refprop, sizeof (refprop)); 2766 if (err != PICL_SUCCESS) { 2767 syslog(LOG_ERR, GET_PROPVAL_FAIL, err); 2768 return (PICL_PROPVALUNAVAILABLE); 2769 } 2770 err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME, 2771 class, sizeof (class)); 2772 if (err == PICL_SUCCESS && strcmp(class, 2773 PICL_CLASS_MEMORY_MODULE) == 0) 2774 break; 2775 if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) { 2776 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME, 2777 err); 2778 return (err); 2779 } 2780 err = ptree_get_next_by_col(nextprop, &nextprop); 2781 if (err != PICL_SUCCESS) { 2782 /* 2783 * if no memory-module in Devices table 2784 * then dimm is unconfigured 2785 */ 2786 (void) strlcpy(result, PICL_PROPVAL_DISABLED, 2787 MAX_OPERATIONAL_STATUS_LEN); 2788 return (PICL_SUCCESS); 2789 } 2790 } 2791 2792 /* 2793 * we've finally found the associated memory-module 2794 * node. Now need to find the bank-status property on 2795 * its parent memory-controller. 2796 */ 2797 err = ptree_get_propval_by_name(refprop, PICL_PROP_PARENT, 2798 &mmgprop, sizeof (picl_nodehdl_t)); 2799 if (err != PICL_SUCCESS) { 2800 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 2801 return (err); 2802 } 2803 err = ptree_get_propval_by_name(mmgprop, PICL_PROP_PARENT, &mcprop, 2804 sizeof (picl_nodehdl_t)); 2805 if (err != PICL_SUCCESS) { 2806 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err); 2807 return (err); 2808 } 2809 err = ptree_get_propval_by_name(mcprop, PICL_PROP_BANK_STATUS, &tblhdl, 2810 sizeof (tblhdl)); 2811 if (err != PICL_SUCCESS) { 2812 (void) strlcpy(result, PICL_PROPVAL_UNKNOWN, 2813 MAX_OPERATIONAL_STATUS_LEN); 2814 return (PICL_SUCCESS); 2815 } 2816 2817 /* 2818 * bank-status is a table. Need to find the entry corresponding 2819 * to this node 2820 */ 2821 err = ptree_get_next_by_row(tblhdl, &nextprop); 2822 if (err != PICL_SUCCESS) { 2823 (void) strlcpy(result, PICL_PROPVAL_UNKNOWN, 2824 MAX_OPERATIONAL_STATUS_LEN); 2825 return (PICL_SUCCESS); 2826 } 2827 for (i = 0; i < 4; i++) { 2828 err = ptree_get_propval(nextprop, &state, sizeof (state)); 2829 if (err != PICL_SUCCESS) { 2830 (void) strlcpy(result, PICL_PROPVAL_UNKNOWN, 2831 MAX_OPERATIONAL_STATUS_LEN); 2832 return (err); 2833 } 2834 if ((i & 1) == (bankname[1] - '0')) { 2835 if (strcmp(state, "pass") == 0) { 2836 (void) strlcpy(result, PICL_PROPVAL_OKAY, 2837 MAX_OPERATIONAL_STATUS_LEN); 2838 } else if (strcmp(state, "fail") == 0) { 2839 (void) strlcpy(result, PICL_PROPVAL_FAILED, 2840 MAX_OPERATIONAL_STATUS_LEN); 2841 } else { 2842 (void) strlcpy(result, state, 2843 MAX_OPERATIONAL_STATUS_LEN); 2844 } 2845 break; 2846 } 2847 err = ptree_get_next_by_col(nextprop, &nextprop); 2848 if (err != PICL_SUCCESS) { 2849 (void) strlcpy(result, PICL_PROPVAL_OKAY, 2850 MAX_OPERATIONAL_STATUS_LEN); 2851 break; 2852 } 2853 } 2854 return (PICL_SUCCESS); 2855 } 2856 2857 /* 2858 * cpu status - uses State property on cpu node 2859 */ 2860 2861 static int 2862 get_cpu_status(ptree_rarg_t *arg, void *result) 2863 { 2864 int err; 2865 picl_prophdl_t tblhdl; 2866 picl_prophdl_t nextprop; 2867 picl_prophdl_t refprop; 2868 char class[PICL_CLASSNAMELEN_MAX]; 2869 char state[MAX_STATE_SIZE]; 2870 2871 /* 2872 * lookup cpu node in Devices table 2873 */ 2874 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl, 2875 sizeof (tblhdl)); 2876 if (err != PICL_SUCCESS) { 2877 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err); 2878 return (err); 2879 } 2880 err = ptree_get_next_by_row(tblhdl, &nextprop); 2881 if (err != PICL_SUCCESS) { 2882 /* 2883 * if Devices table empty then cpu is unconfigured 2884 */ 2885 (void) strlcpy(result, PICL_PROPVAL_DISABLED, 2886 MAX_OPERATIONAL_STATUS_LEN); 2887 return (PICL_SUCCESS); 2888 } 2889 err = ptree_get_next_by_row(nextprop, &nextprop); 2890 if (err != PICL_SUCCESS) { 2891 syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err); 2892 return (err); 2893 } 2894 2895 /* 2896 * walk down second column (ref ptr) 2897 */ 2898 while (err == PICL_SUCCESS) { 2899 err = ptree_get_propval(nextprop, &refprop, sizeof (refprop)); 2900 if (err != PICL_SUCCESS) { 2901 syslog(LOG_ERR, GET_PROPVAL_FAIL, err); 2902 return (err); 2903 } 2904 err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME, 2905 class, sizeof (class)); 2906 if (err == PICL_SUCCESS && strcmp(class, PICL_CLASS_CPU) == 0) 2907 break; 2908 if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) { 2909 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME, 2910 err); 2911 return (err); 2912 } 2913 err = ptree_get_next_by_col(nextprop, &nextprop); 2914 if (err != PICL_SUCCESS) { 2915 /* 2916 * if no cpu in Devices table 2917 * then cpu is unconfigured 2918 */ 2919 (void) strlcpy(result, PICL_PROPVAL_DISABLED, 2920 MAX_OPERATIONAL_STATUS_LEN); 2921 return (PICL_SUCCESS); 2922 } 2923 } 2924 2925 /* 2926 * we've finally found the associated cpu node. Now need to find its 2927 * status property if present (if not assume OK) 2928 */ 2929 err = ptree_get_propval_by_name(refprop, OBP_STATUS, 2930 state, sizeof (state)); 2931 if (err == PICL_SUCCESS) { 2932 if (strcmp(state, "fail") == 0) 2933 (void) strlcpy(result, PICL_PROPVAL_FAILED, 2934 MAX_OPERATIONAL_STATUS_LEN); 2935 else 2936 (void) strlcpy(result, state, 2937 MAX_OPERATIONAL_STATUS_LEN); 2938 return (PICL_SUCCESS); 2939 } 2940 2941 (void) strlcpy(result, PICL_PROPVAL_OKAY, MAX_OPERATIONAL_STATUS_LEN); 2942 return (PICL_SUCCESS); 2943 } 2944 2945 /* 2946 * system/io board condition - uses sgenv driver kstats 2947 */ 2948 2949 static int 2950 get_board_status(ptree_rarg_t *arg, void *result) 2951 { 2952 int err = PICL_SUCCESS; 2953 int i; 2954 sg_board_info_t *brd; 2955 char name[PICL_PROPNAMELEN_MAX]; 2956 char buf[PICL_PROPNAMELEN_MAX]; 2957 kstat_ctl_t *kc; 2958 kstat_t *board_info_ksp; 2959 2960 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name, 2961 sizeof (name)); 2962 if (err != PICL_SUCCESS) { 2963 return (err); 2964 } 2965 2966 err = open_kstat(SG_BOARD_STATUS_KSTAT_NAME, (void **)&board_info_ksp, 2967 &kc); 2968 if (err != PICL_SUCCESS) { 2969 return (err); 2970 } 2971 2972 brd = board_info_ksp->ks_data; 2973 for (i = 0; i < SGENV_NUM_BOARD_READINGS(board_info_ksp); i++, brd++) { 2974 /* 2975 * check this kstat matches the name of the node 2976 */ 2977 if (SG_BOARD_IS_CPU_TYPE(brd->board_num)) { 2978 sprintf_buf3(buf, "%s%d", 2979 SG_HPU_TYPE_CPU_BOARD_ID, brd->board_num); 2980 } else { 2981 sprintf_buf3(buf, "%s%d", 2982 SG_HPU_TYPE_PCI_IO_BOARD_ID, brd->board_num); 2983 } 2984 if (strncmp(buf, name, strlen(buf)) != 0) 2985 continue; 2986 2987 /* 2988 * ok - got the right kstat - get it's value 2989 * note that values 0-4 are defined in sbdp_mbox.h 2990 */ 2991 if (brd->condition >= 0 && brd->condition < 5) 2992 (void) strlcpy(result, 2993 hpu_condition_table[brd->condition], 2994 MAX_OPERATIONAL_STATUS_LEN); 2995 kstat_close(kc); 2996 return (PICL_SUCCESS); 2997 } 2998 kstat_close(kc); 2999 return (PICL_PROPVALUNAVAILABLE); 3000 } 3001 3002 static int 3003 get_op_status(ptree_rarg_t *arg, void *result) 3004 { 3005 int err = PICL_SUCCESS; 3006 char name[PICL_PROPNAMELEN_MAX]; 3007 char value[MAX_STATE_LEN]; 3008 char parent_name[PICL_PROPNAMELEN_MAX]; 3009 picl_nodehdl_t loch; 3010 picl_nodehdl_t parentfruh; 3011 3012 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name, 3013 sizeof (name)); 3014 if (err != PICL_SUCCESS) { 3015 return (err); 3016 } 3017 3018 /* 3019 * handle dimms, cpus and system boards specially 3020 */ 3021 if (IS_PROC_NODE(name)) { 3022 return (get_cpu_status(arg, result)); 3023 } else if (IS_DIMM_NODE(name)) { 3024 return (get_dimm_status(arg, result)); 3025 } else if (IS_SB_NODE(name) || IS_IB_NODE(name)) { 3026 return (get_board_status(arg, result)); 3027 } 3028 3029 /* 3030 * otherwise OperationalStatus is derived from the fault led state 3031 */ 3032 3033 /* 3034 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9 3035 */ 3036 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &loch, 3037 sizeof (loch)); 3038 if (err != PICL_SUCCESS) 3039 return (PICL_PROPVALUNAVAILABLE); 3040 err = ptree_get_propval_by_name(loch, PICL_PROP_PARENT, &parentfruh, 3041 sizeof (parentfruh)); 3042 if (err != PICL_SUCCESS) 3043 return (PICL_PROPVALUNAVAILABLE); 3044 err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, parent_name, 3045 sizeof (parent_name)); 3046 if (err != PICL_SUCCESS) 3047 return (PICL_PROPVALUNAVAILABLE); 3048 if (strcmp(name, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0) { 3049 if (get_led("FAN8", FAULT_LED, value) != PICL_SUCCESS) { 3050 return (PICL_PROPVALUNAVAILABLE); 3051 } 3052 } else if (strcmp(name, "FAN1") == 0 && strcmp(parent_name, 3053 "IB6") == 0) { 3054 if (get_led("FAN9", FAULT_LED, value) != PICL_SUCCESS) { 3055 return (PICL_PROPVALUNAVAILABLE); 3056 } 3057 } else { 3058 if (get_led(name, FAULT_LED, value) != PICL_SUCCESS) { 3059 return (PICL_PROPVALUNAVAILABLE); 3060 } 3061 } 3062 if (strcmp(value, PICL_PROPVAL_ON) == 0) 3063 (void) strlcpy(result, PICL_PROPVAL_FAILED, 3064 MAX_OPERATIONAL_STATUS_LEN); 3065 else 3066 (void) strlcpy(result, PICL_PROPVAL_OKAY, 3067 MAX_OPERATIONAL_STATUS_LEN); 3068 return (PICL_SUCCESS); 3069 } 3070 3071 static int 3072 add_board_status(picl_nodehdl_t nodeh, char *nodename) 3073 { 3074 ptree_propinfo_t propinfo; 3075 int err; 3076 picl_prophdl_t prophdl; 3077 3078 /* 3079 * check if OperationalStatus property already created for this fru 3080 */ 3081 err = ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS, 3082 &prophdl); 3083 if (err == PICL_SUCCESS) 3084 return (PICL_SUCCESS); 3085 3086 /* 3087 * put operational status on dimms, cpus, SBs, IBs, PSUs, FTs, Fans, RPs 3088 */ 3089 if (IS_DIMM_NODE(nodename) || IS_PROC_NODE(nodename) || 3090 IS_SB_NODE(nodename) || IS_IB_NODE(nodename) || 3091 IS_PSU_NODE(nodename) || IS_FT_NODE(nodename) || 3092 IS_FAN_NODE(nodename) || IS_RP_NODE(nodename)) { 3093 err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION, 3094 PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE, 3095 MAX_OPERATIONAL_STATUS_LEN, PICL_PROP_OPERATIONAL_STATUS, 3096 get_op_status, NULL); 3097 if (err != PICL_SUCCESS) { 3098 syslog(LOG_ERR, PROPINFO_FAIL, 3099 PICL_PROP_OPERATIONAL_STATUS, err); 3100 return (err); 3101 } 3102 err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL); 3103 if (err != PICL_SUCCESS) { 3104 syslog(LOG_ERR, ADD_PROP_FAIL, 3105 PICL_PROP_OPERATIONAL_STATUS, err); 3106 return (err); 3107 } 3108 } 3109 return (PICL_SUCCESS); 3110 } 3111 3112 /* 3113 * environmental information handling - uses sgenv driver kstats 3114 */ 3115 3116 static int 3117 add_env_nodes(picl_nodehdl_t nodeh, char *nodename, picl_prophdl_t tblhdl) 3118 { 3119 int err = PICL_SUCCESS; 3120 env_sensor_t *env; 3121 int i; 3122 picl_prophdl_t tblhdl2; 3123 picl_prophdl_t frutype; 3124 char fruname[PICL_PROPNAMELEN_MAX]; 3125 char buf[PICL_PROPNAMELEN_MAX]; 3126 char id[PICL_PROPNAMELEN_MAX]; 3127 float scale; 3128 picl_nodehdl_t childh; 3129 picl_nodehdl_t sensorhdl; 3130 kstat_ctl_t *kc; 3131 kstat_t *env_info_ksp; 3132 3133 err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc); 3134 if (err != PICL_SUCCESS) { 3135 return (err); 3136 } 3137 3138 env = env_info_ksp->ks_data; 3139 for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) { 3140 /* 3141 * check values from kstat entry are within valid range 3142 */ 3143 if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT) 3144 continue; 3145 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB) 3146 continue; 3147 if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC) 3148 continue; 3149 if ((env->sd_id.id.hpu_type >> 8) >= 3150 (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8)) 3151 continue; 3152 if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT) 3153 continue; 3154 3155 /* 3156 * does this kstat entry belong to this fru? 3157 * Note sc reports RPS as 10 and 12 via env messages 3158 * but by 0 and 2 via fru messages, so correct here 3159 */ 3160 if ((env->sd_id.id.hpu_type >> 8) == 3161 (SG_HPU_TYPE_REPEATER_BOARD >> 8)) { 3162 sprintf_buf3(fruname, "%s%d", 3163 hpu_type_table[env->sd_id.id.hpu_type >> 8], 3164 env->sd_id.id.hpu_slot - 10); 3165 } else { 3166 sprintf_buf3(fruname, "%s%d", 3167 hpu_type_table[env->sd_id.id.hpu_type >> 8], 3168 env->sd_id.id.hpu_slot); 3169 } 3170 if (strcmp(nodename, fruname) != 0) 3171 continue; 3172 3173 /* 3174 * set up FRUType. Note we only want to do this once per fru 3175 */ 3176 err = ptree_get_prop_by_name(nodeh, PICL_PROP_FRU_TYPE, 3177 &frutype); 3178 if (err != PICL_SUCCESS) { 3179 err = add_prop_charstring(nodeh, 3180 hpu_fru_type_table[env->sd_id.id.hpu_type >> 8], 3181 PICL_PROP_FRU_TYPE); 3182 if (err != PICL_SUCCESS) 3183 goto done; 3184 } 3185 3186 /* 3187 * create the sensor node with a sensible name 3188 */ 3189 switch (env->sd_id.id.sensor_type) { 3190 case SG_SENSOR_TYPE_TEMPERATURE: 3191 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) { 3192 sprintf_buf2(id, "t_ambient%d", 3193 env->sd_id.id.sensor_typenum); 3194 } else { 3195 sprintf_buf3(id, "t_%s%d", 3196 hpu_part_table[env->sd_id.id.sensor_part], 3197 env->sd_id.id.sensor_partnum); 3198 } 3199 break; 3200 case SG_SENSOR_TYPE_CURRENT: 3201 sprintf_buf3(id, "i_%s%d", 3202 hpu_part_table[env->sd_id.id.sensor_part], 3203 env->sd_id.id.sensor_partnum); 3204 break; 3205 case SG_SENSOR_TYPE_COOLING: 3206 sprintf_buf3(id, "ft_%s%d", 3207 hpu_part_table[env->sd_id.id.sensor_part], 3208 env->sd_id.id.sensor_partnum); 3209 break; 3210 default: /* voltage */ 3211 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) { 3212 sprintf_buf3(id, "v_%s%d", 3213 hpu_sensor_table[env->sd_id.id.sensor_type], 3214 env->sd_id.id.sensor_typenum); 3215 } else { 3216 sprintf_buf3(id, "v_%s%d", 3217 hpu_part_table[env->sd_id.id.sensor_part], 3218 env->sd_id.id.sensor_partnum); 3219 } 3220 break; 3221 } 3222 3223 /* 3224 * check if sensor node has already been created 3225 */ 3226 sprintf_buf3(buf, "%s_%s", nodename, id); 3227 if (find_child_by_name(sch, buf) != 0) 3228 continue; 3229 3230 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_COOLING) { 3231 /* 3232 * create individual fan_unit nodes 3233 */ 3234 childh = nodeh; 3235 sprintf_buf2(fruname, "FAN%d", 3236 env->sd_id.id.sensor_partnum); 3237 err = add_intermediate_nodes(&childh, fruname, 3238 &tblhdl2, "fan-unit", "FAN"); 3239 if (err != PICL_SUCCESS) 3240 goto done; 3241 err = add_board_status(childh, fruname); 3242 if (err != PICL_SUCCESS) 3243 goto done; 3244 } else if (env->sd_id.id.sensor_part == 3245 SG_SENSOR_PART_CHEETAH || 3246 ((env->sd_id.id.hpu_type >> 8) == 3247 (SG_HPU_TYPE_CPU_BOARD >> 8) && 3248 (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_TEMPERATURE) && 3249 (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD))) { 3250 /* 3251 * put sensors under individual processor nodes 3252 */ 3253 childh = nodeh; 3254 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) 3255 sprintf_buf2(fruname, "P%d", 3256 env->sd_id.id.sensor_typenum); 3257 else 3258 sprintf_buf2(fruname, "P%d", 3259 env->sd_id.id.sensor_partnum); 3260 err = add_intermediate_nodes(&childh, fruname, 3261 &tblhdl2, "cpu", "PROC"); 3262 if (err != PICL_SUCCESS) 3263 goto done; 3264 } else { 3265 childh = nodeh; 3266 tblhdl2 = tblhdl; 3267 } 3268 err = add_sensor_node(childh, 0, buf, 3269 hpu_sensor_class_table[env->sd_id.id.sensor_type], 3270 hpu_sensor_prop_table[env->sd_id.id.sensor_type], 3271 tblhdl2, &sensorhdl); 3272 if (err != PICL_SUCCESS) 3273 goto done; 3274 3275 /* 3276 * add additional properties 3277 */ 3278 switch (env->sd_id.id.sensor_type) { 3279 case SG_SENSOR_TYPE_COOLING: 3280 err = add_prop_charstring(sensorhdl, id, 3281 PICL_PROP_LABEL); 3282 if (err != PICL_SUCCESS) 3283 goto done; 3284 /* 3285 * add threshold at 75% of full speed 3286 */ 3287 err = add_prop_int(sensorhdl, 75, 3288 PICL_PROP_LOW_WARNING_THRESHOLD); 3289 if (err != PICL_SUCCESS) 3290 goto done; 3291 err = add_sensor_prop(sensorhdl, 3292 PICL_PROP_FAN_SPEED_UNIT); 3293 if (err != PICL_SUCCESS) 3294 goto done; 3295 continue; 3296 case SG_SENSOR_TYPE_TEMPERATURE: 3297 if ((env->sd_id.id.hpu_type >> 8 == 3298 (SG_HPU_TYPE_CPU_BOARD >> 8)) && 3299 (env->sd_id.id.sensor_part == 3300 SG_SENSOR_PART_BOARD)) { 3301 err = add_prop_charstring(sensorhdl, 3302 PICL_PROPVAL_AMBIENT, PICL_PROP_LABEL); 3303 if (err != PICL_SUCCESS) 3304 goto done; 3305 } else if (env->sd_id.id.sensor_part == 3306 SG_SENSOR_PART_CHEETAH) { 3307 err = add_prop_charstring(sensorhdl, 3308 PICL_PROPVAL_DIE, PICL_PROP_LABEL); 3309 if (err != PICL_SUCCESS) 3310 goto done; 3311 } else { 3312 err = add_prop_charstring(sensorhdl, id, 3313 PICL_PROP_LABEL); 3314 if (err != PICL_SUCCESS) 3315 goto done; 3316 } 3317 err = add_prop_int(sensorhdl, env->sd_lo_warn / 3318 SG_TEMPERATURE_SCALE, PICL_PROP_LOW_WARNING); 3319 if (err != PICL_SUCCESS) 3320 goto done; 3321 err = add_prop_int(sensorhdl, env->sd_lo / 3322 SG_TEMPERATURE_SCALE, PICL_PROP_LOW_SHUTDOWN); 3323 if (err != PICL_SUCCESS) 3324 goto done; 3325 err = add_prop_int(sensorhdl, env->sd_hi_warn / 3326 SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_WARNING); 3327 if (err != PICL_SUCCESS) 3328 goto done; 3329 err = add_prop_int(sensorhdl, env->sd_hi / 3330 SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_SHUTDOWN); 3331 if (err != PICL_SUCCESS) 3332 goto done; 3333 continue; 3334 case SG_SENSOR_TYPE_1_5_VDC: 3335 scale = SG_1_5_VDC_SCALE; 3336 break; 3337 case SG_SENSOR_TYPE_1_8_VDC: 3338 scale = SG_1_8_VDC_SCALE; 3339 break; 3340 case SG_SENSOR_TYPE_2_5_VDC: 3341 scale = SG_2_5_VDC_SCALE; 3342 break; 3343 case SG_SENSOR_TYPE_3_3_VDC: 3344 scale = SG_3_3_VDC_SCALE; 3345 break; 3346 case SG_SENSOR_TYPE_5_VDC: 3347 scale = SG_5_VDC_SCALE; 3348 break; 3349 case SG_SENSOR_TYPE_12_VDC: 3350 scale = SG_12_VDC_SCALE; 3351 break; 3352 case SG_SENSOR_TYPE_48_VDC: 3353 /* 3354 * The 48VDC sensor is just an indicator - doesn't 3355 * give reading or thresholds 3356 */ 3357 err = add_prop_charstring(sensorhdl, id, 3358 PICL_PROP_LABEL); 3359 if (err != PICL_SUCCESS) 3360 goto done; 3361 continue; 3362 case SG_SENSOR_TYPE_CURRENT: 3363 scale = SG_CURRENT_SCALE; 3364 break; 3365 } 3366 err = add_prop_charstring(sensorhdl, id, PICL_PROP_LABEL); 3367 if (err != PICL_SUCCESS) 3368 goto done; 3369 err = add_prop_float(sensorhdl, (float)env->sd_lo_warn / scale, 3370 PICL_PROP_LOW_WARNING); 3371 if (err != PICL_SUCCESS) 3372 goto done; 3373 err = add_prop_float(sensorhdl, (float)env->sd_lo / scale, 3374 PICL_PROP_LOW_SHUTDOWN); 3375 if (err != PICL_SUCCESS) 3376 goto done; 3377 err = add_prop_float(sensorhdl, (float)env->sd_hi_warn / scale, 3378 PICL_PROP_HIGH_WARNING); 3379 if (err != PICL_SUCCESS) 3380 goto done; 3381 err = add_prop_float(sensorhdl, (float)env->sd_hi / scale, 3382 PICL_PROP_HIGH_SHUTDOWN); 3383 if (err != PICL_SUCCESS) 3384 goto done; 3385 } 3386 done: 3387 kstat_close(kc); 3388 return (err); 3389 } 3390 3391 static int 3392 get_sensor_data(ptree_rarg_t *arg, void *result) 3393 { 3394 int err; /* return code */ 3395 kstat_ctl_t *kc; 3396 char name[PICL_PROPNAMELEN_MAX]; 3397 ptree_propinfo_t propinfo; 3398 int i; 3399 env_sensor_t *env; 3400 char buf[PICL_PROPNAMELEN_MAX]; 3401 char buf1[PICL_PROPNAMELEN_MAX]; 3402 kstat_t *env_info_ksp; 3403 3404 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name, 3405 sizeof (name)); 3406 if (err != PICL_SUCCESS) 3407 return (err); 3408 err = ptree_get_propinfo(arg->proph, &propinfo); 3409 if (err != PICL_SUCCESS) 3410 return (err); 3411 3412 err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc); 3413 if (err != PICL_SUCCESS) { 3414 return (err); 3415 } 3416 3417 env = env_info_ksp->ks_data; 3418 for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) { 3419 /* 3420 * check kstat values are within range 3421 */ 3422 if (SG_INFO_VALUESTATUS(env->sd_infostamp) != SG_INFO_VALUE_OK) 3423 continue; 3424 if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT) 3425 continue; 3426 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB) 3427 continue; 3428 if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC) 3429 continue; 3430 if ((env->sd_id.id.hpu_type >> 8) >= 3431 (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8)) 3432 continue; 3433 if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT) 3434 continue; 3435 3436 /* 3437 * check this kstat matches the name of the node 3438 * note sc reports RPS as 10 and 12 via env messages 3439 * but by 0 and 2 via fru messages, so correct here 3440 */ 3441 if ((env->sd_id.id.hpu_type >> 8) == 3442 (SG_HPU_TYPE_REPEATER_BOARD >> 8)) 3443 sprintf_buf3(buf, "%s%d", 3444 hpu_type_table[env->sd_id.id.hpu_type >> 8], 3445 env->sd_id.id.hpu_slot - 10); 3446 else 3447 sprintf_buf3(buf, "%s%d", 3448 hpu_type_table[env->sd_id.id.hpu_type >> 8], 3449 env->sd_id.id.hpu_slot); 3450 switch (env->sd_id.id.sensor_type) { 3451 case SG_SENSOR_TYPE_TEMPERATURE: 3452 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) { 3453 sprintf_buf3(buf1, "%s_t_ambient%d", 3454 buf, env->sd_id.id.sensor_typenum); 3455 } else { 3456 sprintf_buf4(buf1, "%s_t_%s%d", buf, 3457 hpu_part_table[env->sd_id.id.sensor_part], 3458 env->sd_id.id.sensor_partnum); 3459 } 3460 break; 3461 case SG_SENSOR_TYPE_CURRENT: 3462 sprintf_buf4(buf1, "%s_i_%s%d", buf, 3463 hpu_part_table[env->sd_id.id.sensor_part], 3464 env->sd_id.id.sensor_partnum); 3465 break; 3466 case SG_SENSOR_TYPE_COOLING: 3467 sprintf_buf4(buf1, "%s_ft_%s%d", buf, 3468 hpu_part_table[env->sd_id.id.sensor_part], 3469 env->sd_id.id.sensor_partnum); 3470 break; 3471 default: /* voltage */ 3472 if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) { 3473 sprintf_buf4(buf1, "%s_v_%s%d", buf, 3474 hpu_sensor_table[env->sd_id.id.sensor_type], 3475 env->sd_id.id.sensor_typenum); 3476 } else { 3477 sprintf_buf4(buf1, "%s_v_%s%d", buf, 3478 hpu_part_table[env->sd_id.id.sensor_part], 3479 env->sd_id.id.sensor_partnum); 3480 } 3481 break; 3482 } 3483 if (strcmp(buf1, name) != 0) 3484 continue; 3485 3486 /* 3487 * ok - this is the kstat we want - update 3488 * Condition, or sensor reading as requested 3489 */ 3490 if (strcmp(propinfo.piclinfo.name, PICL_PROP_CONDITION) == 0) { 3491 switch (SG_GET_SENSOR_STATUS(env->sd_status)) { 3492 case SG_SENSOR_STATUS_OK: 3493 (void) strlcpy(result, PICL_PROPVAL_OKAY, 3494 MAX_CONDITION_LEN); 3495 break; 3496 case SG_SENSOR_STATUS_LO_WARN: 3497 case SG_SENSOR_STATUS_HI_WARN: 3498 (void) strlcpy(result, PICL_PROPVAL_WARNING, 3499 MAX_CONDITION_LEN); 3500 break; 3501 case SG_SENSOR_STATUS_LO_DANGER: 3502 case SG_SENSOR_STATUS_HI_DANGER: 3503 (void) strlcpy(result, PICL_PROPVAL_FAILED, 3504 MAX_CONDITION_LEN); 3505 break; 3506 default: 3507 kstat_close(kc); 3508 return (PICL_PROPVALUNAVAILABLE); 3509 } 3510 kstat_close(kc); 3511 return (PICL_SUCCESS); 3512 } 3513 switch (env->sd_id.id.sensor_type) { 3514 case SG_SENSOR_TYPE_TEMPERATURE: 3515 *(int *)result = env->sd_value / SG_TEMPERATURE_SCALE; 3516 break; 3517 case SG_SENSOR_TYPE_1_5_VDC: 3518 *(float *)result = 3519 (float)env->sd_value / (float)SG_1_5_VDC_SCALE; 3520 break; 3521 case SG_SENSOR_TYPE_1_8_VDC: 3522 *(float *)result = 3523 (float)env->sd_value / (float)SG_1_8_VDC_SCALE; 3524 break; 3525 case SG_SENSOR_TYPE_2_5_VDC: 3526 *(float *)result = 3527 (float)env->sd_value / (float)SG_2_5_VDC_SCALE; 3528 break; 3529 case SG_SENSOR_TYPE_3_3_VDC: 3530 *(float *)result = 3531 (float)env->sd_value / (float)SG_3_3_VDC_SCALE; 3532 break; 3533 case SG_SENSOR_TYPE_5_VDC: 3534 *(float *)result = 3535 (float)env->sd_value / (float)SG_5_VDC_SCALE; 3536 break; 3537 case SG_SENSOR_TYPE_12_VDC: 3538 *(float *)result = 3539 (float)env->sd_value / (float)SG_12_VDC_SCALE; 3540 break; 3541 case SG_SENSOR_TYPE_CURRENT: 3542 *(float *)result = 3543 (float)env->sd_value / (float)SG_CURRENT_SCALE; 3544 break; 3545 case SG_SENSOR_TYPE_COOLING: 3546 if (strcmp(propinfo.piclinfo.name, 3547 PICL_PROP_FAN_SPEED_UNIT) == 0) { 3548 if (SG_GET_SENSOR_STATUS(env->sd_status) == 3549 SG_SENSOR_STATUS_FAN_LOW) { 3550 (void) strlcpy(result, 3551 PICL_PROPVAL_SELF_REGULATING, 3552 MAX_SPEED_UNIT_LEN); 3553 } else { 3554 (void) strlcpy(result, 3555 PICL_PROPVAL_PER_CENT, 3556 MAX_SPEED_UNIT_LEN); 3557 } 3558 } else { 3559 switch (SG_GET_SENSOR_STATUS(env->sd_status)) { 3560 case SG_SENSOR_STATUS_FAN_HIGH: 3561 *(int *)result = 100; 3562 break; 3563 case SG_SENSOR_STATUS_FAN_FAIL: 3564 case SG_SENSOR_STATUS_FAN_OFF: 3565 *(int *)result = 0; 3566 break; 3567 default: 3568 case SG_SENSOR_STATUS_FAN_LOW: 3569 kstat_close(kc); 3570 return (PICL_PROPVALUNAVAILABLE); 3571 } 3572 } 3573 break; 3574 default: 3575 kstat_close(kc); 3576 return (PICL_PROPVALUNAVAILABLE); 3577 } 3578 kstat_close(kc); 3579 return (PICL_SUCCESS); 3580 } 3581 kstat_close(kc); 3582 return (PICL_PROPVALUNAVAILABLE); 3583 } 3584 3585 /* 3586 * led information handling - uses lw8 driver 3587 */ 3588 3589 static int 3590 add_led_nodes(picl_nodehdl_t nodeh, char *name, int position, 3591 picl_prophdl_t tblhdl) 3592 { 3593 int err; 3594 int ledfd; 3595 lom_get_led_t lom_get_led; 3596 picl_nodehdl_t sensorhdl; 3597 char buf[PICL_PROPNAMELEN_MAX]; 3598 3599 /* 3600 * Open the lw8 pseudo dev to get the led information 3601 */ 3602 if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) { 3603 syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno)); 3604 return (PICL_SUCCESS); 3605 } 3606 bzero(&lom_get_led, sizeof (lom_get_led)); 3607 (void) strlcpy(lom_get_led.location, name, 3608 sizeof (lom_get_led.location)); 3609 if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) { 3610 (void) close(ledfd); 3611 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno)); 3612 return (PICL_FAILURE); 3613 } 3614 while (lom_get_led.next_id[0] != '\0') { 3615 (void) strlcpy(lom_get_led.id, lom_get_led.next_id, 3616 sizeof (lom_get_led.id)); 3617 lom_get_led.next_id[0] = '\0'; 3618 lom_get_led.position = LOM_LED_POSITION_FRU; 3619 if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) { 3620 (void) close(ledfd); 3621 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno)); 3622 return (PICL_FAILURE); 3623 } 3624 sprintf_buf3(buf, "%s_%s", name, lom_get_led.id); 3625 if (position != lom_get_led.position) 3626 continue; 3627 if (position == LOM_LED_POSITION_LOCATION) { 3628 err = add_sensor_node(0, nodeh, buf, PICL_CLASS_LED, 3629 PICL_PROP_STATE, tblhdl, &sensorhdl); 3630 } else { 3631 err = add_sensor_node(nodeh, 0, buf, PICL_CLASS_LED, 3632 PICL_PROP_STATE, tblhdl, &sensorhdl); 3633 } 3634 if (err != PICL_SUCCESS) { 3635 (void) close(ledfd); 3636 return (err); 3637 } 3638 if (strcmp(name, "chassis") == 0 && strcmp(lom_get_led.id, 3639 "locator") == 0) { 3640 err = add_prop_charstring(sensorhdl, PICL_PROPVAL_TRUE, 3641 PICL_PROP_IS_LOCATOR); 3642 if (err != PICL_SUCCESS) { 3643 (void) close(ledfd); 3644 return (err); 3645 } 3646 err = add_prop_charstring(sensorhdl, 3647 PICL_PROPVAL_SYSTEM, PICL_PROP_LOCATOR_NAME); 3648 if (err != PICL_SUCCESS) { 3649 (void) close(ledfd); 3650 return (err); 3651 } 3652 } 3653 err = add_prop_charstring(sensorhdl, lom_get_led.id, 3654 PICL_PROP_LABEL); 3655 if (err != PICL_SUCCESS) { 3656 (void) close(ledfd); 3657 return (err); 3658 } 3659 err = add_prop_charstring(sensorhdl, lom_get_led.color, 3660 PICL_PROP_COLOR); 3661 if (err != PICL_SUCCESS) { 3662 (void) close(ledfd); 3663 return (err); 3664 } 3665 } 3666 (void) close(ledfd); 3667 return (PICL_SUCCESS); 3668 } 3669 3670 static int 3671 get_led(char *name, char *ptr, char *result) 3672 { 3673 int ledfd; 3674 lom_get_led_t lom_get_led; 3675 3676 /* 3677 * Open the lw8 pseudo dev to get the led information 3678 */ 3679 if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) { 3680 syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno)); 3681 return (PICL_FAILURE); 3682 } 3683 bzero(&lom_get_led, sizeof (lom_get_led)); 3684 (void) strlcpy(lom_get_led.location, name, 3685 sizeof (lom_get_led.location)); 3686 (void) strlcpy(lom_get_led.id, ptr, sizeof (lom_get_led.id)); 3687 if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) { 3688 (void) close(ledfd); 3689 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno)); 3690 return (PICL_PROPVALUNAVAILABLE); 3691 } 3692 if (lom_get_led.status == LOM_LED_STATUS_ON) 3693 (void) strlcpy(result, PICL_PROPVAL_ON, MAX_STATE_LEN); 3694 else if (lom_get_led.status == LOM_LED_STATUS_FLASHING) 3695 (void) strlcpy(result, PICL_PROPVAL_FLASHING, MAX_STATE_LEN); 3696 else if (lom_get_led.status == LOM_LED_STATUS_BLINKING) 3697 (void) strlcpy(result, PICL_PROPVAL_BLINKING, MAX_STATE_LEN); 3698 else 3699 (void) strlcpy(result, PICL_PROPVAL_OFF, MAX_STATE_LEN); 3700 (void) close(ledfd); 3701 return (PICL_SUCCESS); 3702 } 3703 3704 static int 3705 get_led_data(ptree_rarg_t *arg, void *result) 3706 { 3707 int rc; /* return code */ 3708 char name[PICL_PROPNAMELEN_MAX]; 3709 char *ptr; 3710 3711 rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name, 3712 sizeof (name)); 3713 if (rc != PICL_SUCCESS) 3714 return (rc); 3715 3716 ptr = strchr(name, '_'); 3717 *ptr++ = '\0'; /* now name is fru name, ptr is led name */ 3718 return (get_led(name, ptr, (char *)result)); 3719 } 3720 3721 static int 3722 set_led(char *name, char *ptr, char *value) 3723 { 3724 int ledfd; 3725 lom_set_led_t lom_set_led; 3726 3727 /* 3728 * Open the lw8 pseudo dev to set the led information 3729 */ 3730 if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) { 3731 syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno)); 3732 return (PICL_FAILURE); 3733 } 3734 bzero(&lom_set_led, sizeof (lom_set_led)); 3735 (void) strlcpy(lom_set_led.location, name, 3736 sizeof (lom_set_led.location)); 3737 (void) strlcpy(lom_set_led.id, ptr, sizeof (lom_set_led.id)); 3738 if (strcmp(value, PICL_PROPVAL_ON) == 0) { 3739 lom_set_led.status = LOM_LED_STATUS_ON; 3740 } else if (strcmp(value, PICL_PROPVAL_FLASHING) == 0) { 3741 lom_set_led.status = LOM_LED_STATUS_FLASHING; 3742 } else if (strcmp(value, PICL_PROPVAL_BLINKING) == 0) { 3743 lom_set_led.status = LOM_LED_STATUS_BLINKING; 3744 } else { 3745 lom_set_led.status = LOM_LED_STATUS_OFF; 3746 } 3747 if (ioctl(ledfd, LOMIOCSETLED, &lom_set_led) == -1) { 3748 (void) close(ledfd); 3749 syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno)); 3750 return (PICL_PROPVALUNAVAILABLE); 3751 } 3752 (void) close(ledfd); 3753 return (PICL_SUCCESS); 3754 } 3755 3756 static int 3757 set_led_data(ptree_warg_t *arg, const void *value) 3758 { 3759 int rc; /* return code */ 3760 char name[PICL_PROPNAMELEN_MAX]; 3761 char *ptr; 3762 3763 rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name, 3764 sizeof (name)); 3765 if (rc != PICL_SUCCESS) 3766 return (rc); 3767 3768 ptr = strchr(name, '_'); 3769 *ptr++ = '\0'; /* now name is fru name, ptr is led name */ 3770 return (set_led(name, ptr, (char *)value)); 3771 } 3772 3773 static void 3774 disk_leds_init(void) 3775 { 3776 int err = 0, i; 3777 3778 if (!g_mutex_init) { 3779 if ((pthread_cond_init(&g_cv, NULL) == 0) && 3780 (pthread_cond_init(&g_cv_ack, NULL) == 0) && 3781 (pthread_mutex_init(&g_mutex, NULL) == 0)) { 3782 g_mutex_init = B_TRUE; 3783 } else { 3784 return; 3785 } 3786 } 3787 3788 if (ledsthr_created) { 3789 /* 3790 * this is a restart, wake up sleeping threads 3791 */ 3792 err = pthread_mutex_lock(&g_mutex); 3793 if (err != 0) { 3794 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err)); 3795 return; 3796 } 3797 g_wait_now = B_FALSE; 3798 (void) pthread_cond_broadcast(&g_cv); 3799 (void) pthread_mutex_unlock(&g_mutex); 3800 } else { 3801 if ((pthread_attr_init(&ledsthr_attr) != 0) || 3802 (pthread_attr_setscope(&ledsthr_attr, 3803 PTHREAD_SCOPE_SYSTEM) != 0)) 3804 return; 3805 if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr, 3806 disk_leds_thread, NULL)) != 0) { 3807 syslog(LOG_ERR, EM_THREAD_CREATE_FAILED, strerror(err)); 3808 return; 3809 } 3810 ledsthr_created = B_TRUE; 3811 } 3812 for (i = 0; i < N_DISKS; i++) { 3813 (void) set_led(lw8_disks[i].d_fruname, FAULT_LED, 3814 PICL_PROPVAL_OFF); 3815 } 3816 } 3817 3818 static void 3819 disk_leds_fini(void) 3820 { 3821 int err; 3822 3823 /* 3824 * tell led thread to pause 3825 */ 3826 if (!ledsthr_created) 3827 return; 3828 err = pthread_mutex_lock(&g_mutex); 3829 if (err != 0) { 3830 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err)); 3831 return; 3832 } 3833 g_wait_now = B_TRUE; 3834 disk_leds_thread_ack = B_FALSE; 3835 (void) pthread_cond_broadcast(&g_cv); 3836 3837 /* 3838 * and wait for the led thread to acknowledge 3839 */ 3840 while (!disk_leds_thread_ack) { 3841 (void) pthread_cond_wait(&g_cv_ack, &g_mutex); 3842 } 3843 (void) pthread_mutex_unlock(&g_mutex); 3844 } 3845 3846 static void 3847 update_disk_node(struct lw8_disk *diskp) 3848 { 3849 picl_nodehdl_t slotndh; 3850 picl_nodehdl_t diskndh; 3851 picl_nodehdl_t devhdl; 3852 picl_prophdl_t tblhdl; 3853 int err; 3854 char path[MAXPATHLEN]; 3855 char *fruname = diskp->d_fruname; 3856 3857 sprintf_buf2(path, CHASSIS_LOC_PATH, fruname); 3858 if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) { 3859 return; 3860 } 3861 diskndh = find_child_by_name(slotndh, fruname); 3862 err = ptree_get_node_by_path(diskp->d_plat_path, &devhdl); 3863 if (err == PICL_SUCCESS) { 3864 if (diskndh != 0) 3865 return; 3866 err = ptree_create_and_add_node(slotndh, fruname, 3867 PICL_CLASS_FRU, &diskndh); 3868 if (err != PICL_SUCCESS) { 3869 syslog(LOG_ERR, ADD_NODE_FAIL, fruname, err); 3870 return; 3871 } 3872 err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES); 3873 if (err != PICL_SUCCESS) 3874 return; 3875 err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK); 3876 if (err != PICL_SUCCESS) 3877 return; 3878 err = add_prop_ref(devhdl, diskndh, PICL_REFPROP_FRU_PARENT); 3879 if (err != PICL_SUCCESS) 3880 return; 3881 } else { 3882 if (diskndh == 0) 3883 return; 3884 err = ptree_delete_node(diskndh); 3885 if (err != PICL_SUCCESS) 3886 return; 3887 (void) ptree_destroy_node(diskndh); 3888 } 3889 } 3890 3891 /* 3892 * Implement a state machine in order to: 3893 * 3894 * o enable/disable disk LEDs 3895 * o add/delete the disk's node in the FRU tree 3896 * 3897 * The machine changes state based on the current, in-memory 3898 * state of the disk (eg, the d_state field of 'struct lw8_disk') 3899 * and libdevice's current view of whether the disk is 3900 * Configured or Unconfigured. 3901 * 3902 * If the new state is the same as the previous state, then 3903 * no side effects occur. Otherwise, the LEDs for the 3904 * disk are set and the disk's associated node in the 3905 * FRU Tree is added or deleted. 3906 */ 3907 static void 3908 set_disk_leds(struct lw8_disk *disk) 3909 { 3910 devctl_hdl_t dhdl; 3911 uint_t cur_state = 0; 3912 3913 dhdl = devctl_device_acquire(disk->d_devices_path, 0); 3914 if (dhdl == NULL) { 3915 int err = errno; 3916 syslog(LOG_ERR, DEVCTL_DEVICE_ACQUIRE_FAILED, 3917 strerror(err)); 3918 return; 3919 } 3920 devctl_device_getstate(dhdl, &cur_state); 3921 devctl_release(dhdl); 3922 3923 if ((cur_state & DEVICE_OFFLINE) != 0) { 3924 switch (disk->d_state) { 3925 default: 3926 /* 3927 * State machine should never get here. 3928 * When NDEBUG is defined, control will 3929 * fall through and force d_state to 3930 * match the semantics of "DEVICE_OFFLINE". 3931 * During development, NDEBUG can be undefined, 3932 * and this will fire an assertion. 3933 */ 3934 assert(0); 3935 /*FALLTHROUGH*/ 3936 3937 case DISK_STATE_NOT_INIT: 3938 case DISK_STATE_READY: 3939 disk->d_state = DISK_STATE_NOT_READY; 3940 3941 (void) set_led(disk->d_fruname, POWER_LED, 3942 PICL_PROPVAL_OFF); 3943 (void) set_led(disk->d_fruname, REMOK_LED, 3944 PICL_PROPVAL_ON); 3945 3946 update_disk_node(disk); 3947 break; 3948 3949 case DISK_STATE_NOT_READY: 3950 break; 3951 } 3952 } else if ((cur_state & DEVICE_ONLINE) != 0) { 3953 switch (disk->d_state) { 3954 default: 3955 /* 3956 * State machine should never get here. 3957 * When NDEBUG is defined, control will 3958 * fall through and force d_state to 3959 * match the semantics of "DEVICE_ONLINE". 3960 * During development, NDEBUG can be undefined, 3961 * and this will fire an assertion. 3962 */ 3963 assert(0); 3964 /*FALLTHROUGH*/ 3965 3966 case DISK_STATE_NOT_INIT: 3967 case DISK_STATE_NOT_READY: 3968 disk->d_state = DISK_STATE_READY; 3969 3970 (void) set_led(disk->d_fruname, REMOK_LED, 3971 PICL_PROPVAL_OFF); 3972 (void) set_led(disk->d_fruname, POWER_LED, 3973 PICL_PROPVAL_ON); 3974 3975 update_disk_node(disk); 3976 break; 3977 3978 case DISK_STATE_READY: 3979 break; 3980 } 3981 } 3982 } 3983 3984 /* 3985 * NOTE: this implementation of disk_leds_thread is based on the version in 3986 * plugins/sun4u/mpxu/frudr/piclfrudr.c (with V440 raid support removed). Some 3987 * day the source code layout and build environment should support common code 3988 * used by platform specific plugins, in which case LW8 support could be added 3989 * to the mpxu version (which would be moved to a common directory). 3990 */ 3991 /*ARGSUSED*/ 3992 static void * 3993 disk_leds_thread(void *args) 3994 { 3995 int i; 3996 int err = 0; 3997 int n_disks = N_DISKS; 3998 3999 static char *lw8_pci_devs[] = { 4000 DISK0_BASE_PATH, 4001 DISK1_BASE_PATH 4002 }; 4003 4004 static char *lw8_pcix_devs[] = { 4005 DISK0_BASE_PATH_PCIX, 4006 DISK1_BASE_PATH_PCIX 4007 }; 4008 4009 static char **lw8_devs; 4010 4011 if (pcix_io) { 4012 lw8_devs = lw8_pcix_devs; 4013 } else { 4014 lw8_devs = lw8_pci_devs; 4015 } 4016 4017 /* 4018 * create aliases for disk names 4019 */ 4020 for (i = 0; i < n_disks; i++) { 4021 char buffer[MAXPATHLEN]; 4022 4023 (void) snprintf(buffer, sizeof (buffer), "/devices%s", 4024 lw8_devs[i]); 4025 lw8_disks[i].d_devices_path = strdup(buffer); 4026 4027 (void) snprintf(buffer, sizeof (buffer), "/platform%s", 4028 lw8_devs[i]); 4029 lw8_disks[i].d_plat_path = strdup(buffer); 4030 } 4031 4032 for (;;) { 4033 for (i = 0; i < n_disks; i++) { 4034 set_disk_leds(&lw8_disks[i]); 4035 } 4036 4037 /* 4038 * wait a bit until we check again 4039 */ 4040 err = poll(NULL, 0, ledsthr_poll_period); 4041 if (err == -1) { 4042 err = errno; 4043 syslog(LOG_ERR, EM_POLL_FAIL, strerror(err)); 4044 break; 4045 } 4046 err = pthread_mutex_lock(&g_mutex); 4047 if (err != 0) { 4048 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err)); 4049 break; 4050 } 4051 if (g_wait_now != B_FALSE) { 4052 /* notify _fini routine that we've paused */ 4053 disk_leds_thread_ack = B_TRUE; 4054 (void) pthread_cond_signal(&g_cv_ack); 4055 /* and go to sleep in case we get restarted */ 4056 while (g_wait_now != B_FALSE) 4057 (void) pthread_cond_wait(&g_cv, &g_mutex); 4058 } 4059 (void) pthread_mutex_unlock(&g_mutex); 4060 } 4061 return ((void *)err); 4062 } 4063