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