cmd: remove sparc-only virtinfo
[unleashed.git] / usr / src / cmd / picl / plugins / sun4u / lw8 / frutree / piclfrutree.c
blobf4e14aa5647c9199c88ec804b0cba0ea443b3f50
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This plugin-in creates the FRU Hierarchy for the
31 * SUNW,Netra-T12 platform and manages the environmental sensors
32 * on the platform.
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>
64 * Plugin registration entry points
66 static void piclfrutree_register(void);
67 static void piclfrutree_init(void);
68 static void piclfrutree_fini(void);
69 #pragma init(piclfrutree_register)
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,
80 * Log message texts
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")
110 * PICL property values
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"
133 * PICL property names
135 #define PICL_PROP_LOW_WARNING_THRESHOLD "LowWarningThreshold"
138 * Local defines
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"
174 * Calculate safari address to put in CPU_DEV/MEMORY_DEV string based on
175 * SBx/Py fru path name
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
186 * work out type of fru based on name
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')
198 * rename sgfru driver's node_t to sgfrunode_t to avoid confusion
200 #define sgfrunode_t node_t
203 * disk_led data
205 #define REMOK_LED "ok_to_remove"
206 #define FAULT_LED "fault"
207 #define POWER_LED "power"
210 * 'struct lw8_disk' contains the per-disk metadata needed to
211 * manage the current state of one of the internal disks.
213 * 'lw8_disks[]' is an array that contains the metadata
214 * for N_DISKS disks.
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.
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.
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).
232 typedef enum {
233 DISK_STATE_NOT_INIT,
234 DISK_STATE_READY,
235 DISK_STATE_NOT_READY
236 } disk_state_t;
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;
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} };
250 /* Duration of inactivity within disk_leds_thread() */
251 #define THR_POLL_PERIOD 5000 /* milliseconds */
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;
265 static void disk_leds_init(void);
266 static void disk_leds_fini(void);
267 static void *disk_leds_thread(void *args);
270 * Tables to convert sgenv information
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"};
297 * variables set up in init
299 static picl_nodehdl_t frutreeh;
300 static picl_nodehdl_t sch = NULL;
301 static int init_complete;
302 static int pcix_io = 0;
305 * forward reference
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);
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)
373 * This function is executed as part of .init when the plugin is
374 * dlopen()ed
376 static void
377 piclfrutree_register(void)
379 (void) picld_plugin_register(&my_reg_info);
383 * This function is the init entry point of the plugin.
384 * It initializes the /frutree tree
386 static void
387 piclfrutree_init(void)
389 int err;
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;
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();
409 * This function is the fini entry point of the plugin.
411 static void
412 piclfrutree_fini(void)
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();
425 * called from piclfrutree_init() to initialise picl frutree
427 static int
428 add_all_nodes(void)
430 int err;
431 picl_nodehdl_t rooth;
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);
440 /* find sc node so we can create sensor nodes under it */
442 err = ptree_get_node_by_path(SC_DEV, &sch);
443 if (err != PICL_SUCCESS) {
446 * There is a XMITS/PCI-X IO Board assembly implements
447 * a different path for the the bootbus controller.
449 err = ptree_get_node_by_path(SC_DEV_PCIX, &sch);
450 if (err == PICL_SUCCESS)
451 pcix_io = 1;
454 if (err != PICL_SUCCESS) {
455 syslog(LOG_ERR, NO_SC_FAIL);
456 return (err);
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);
467 /* Recursively query the SC and add frutree nodes */
468 return (add_subtree(frutreeh, ROOTPARENT));
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
476 static int
477 add_subtree(picl_nodehdl_t parh, fru_hdl_t handle)
479 int err, i;
480 int num_children;
481 sgfrunode_t *cp, *fruchildren = NULL;
482 picl_nodehdl_t childh;
484 /* find children of the parent node */
485 fruchildren = get_node_children(handle, &num_children);
486 if (fruchildren == NULL)
487 return (PICL_FAILURE);
489 /* for each child, add a new picl node */
490 for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
492 * Add the appropriate PICL class
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);
504 * Recursively call this function based on has_children hint
506 if (childh && cp->has_children) {
507 err = add_subtree(childh, cp->handle);
508 if (err != PICL_SUCCESS) {
509 free(fruchildren);
510 return (err);
514 free(fruchildren);
515 return (PICL_SUCCESS);
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
523 static int
524 remove_subtree(picl_nodehdl_t parh)
526 picl_nodehdl_t chdh;
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));
537 /* NOTREACHED */
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.
545 static int
546 add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
547 picl_nodehdl_t *childp)
549 switch (sgfrunode->class) {
550 case PSEUDO_FRU_CLASS:
551 return (add_chassis_node(parh, sgfrunode, childp));
553 case FRU_CLASS:
554 return (add_fru_node(parh, sgfrunode, childp));
556 case LOCATION_CLASS:
557 return (add_location_node(parh, sgfrunode, childp));
559 default:
560 syslog(LOG_ERR, INVALID_PICL_CLASS, sgfrunode->class);
561 return (PICL_NOTNODE);
566 * create chassis node
568 static int
569 add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
570 picl_nodehdl_t *childp)
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;
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);
585 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
586 if (err != PICL_SUCCESS)
587 return (err);
590 * add devices table to chassis node (may need references
591 * to led devices)
593 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
594 if (err != PICL_SUCCESS)
595 return (err);
597 err = add_led_nodes(childh, "chassis", LOM_LED_POSITION_FRU, tblhdl);
598 if (err != PICL_SUCCESS)
599 return (err);
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);
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);
619 if (err != PICL_SUCCESS)
620 return (err);
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);
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);
640 if (err != PICL_SUCCESS)
641 return (err);
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);
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);
661 if (err != PICL_SUCCESS)
662 return (err);
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);
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);
682 if (err != PICL_SUCCESS)
683 return (err);
685 if (pcix_io) {
687 * The XMITS/PCI-X IO Assembly is layed out a bit differently.
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);
727 *childp = childh;
728 return (PICL_SUCCESS);
732 * create fru node, based on sgfru node "sgfrunode" under parent parh. Return
733 * picl_nodehdl of created node in *childp.
735 static int
736 add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
737 picl_nodehdl_t *childp)
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;
746 * if sgfrunode already there, then just carry on own the tree
748 childh = find_child_by_name(parh, nodename);
749 if (childh != NULL) {
751 * for frus other than dimms and ecaches, update environmental
752 * sensors and board status if necessary
754 if (IS_ECACHE_NODE(nodename)) {
755 *childp = childh;
756 return (PICL_SUCCESS);
758 if (IS_DIMM_NODE(nodename)) {
760 * for dimms we just want status
762 err = add_board_status(childh, nodename);
763 if (err != PICL_SUCCESS)
764 return (err);
765 *childp = childh;
766 return (PICL_SUCCESS);
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);
783 * create requested fru node
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);
793 * if sgfru has sent us a valid handle, then there is fruid information.
794 * create the SC_handle, and FRUDateAvailable properties for FRUID.
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);
806 * post fru added event to fru data plugin if this was due to
807 * a dr event - ie post-initialisation
809 if (init_complete)
810 post_frudr_event(PICL_FRU_ADDED, parh, NULL);
813 * Create empty Devices table - we'll add lines to it as we go along
815 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
816 if (err != PICL_SUCCESS)
817 return (err);
820 * Ecache nodes don't have sensors - just set up FRUType
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);
831 * Dimm nodes don't have sensors - just set up FRUType and
832 * also reference properties to memory module nodes and OpStatus
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);
850 * not a Dimm or Ecache node - set up environmental info,
851 * board status and led info
853 err = add_env_nodes(childh, nodename, tblhdl);
854 if (err != PICL_SUCCESS)
855 return (err);
857 err = add_board_status(childh, nodename);
858 if (err != PICL_SUCCESS)
859 return (err);
861 err = add_led_nodes(childh, nodename, LOM_LED_POSITION_FRU, tblhdl);
862 if (err != PICL_SUCCESS)
863 return (err);
865 *childp = childh;
866 return (PICL_SUCCESS);
870 * create location node, based on sgfru node "sgfrunode" under parent parh.
871 * Return picl_nodehdl of created node in *childp.
873 static int
874 add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
875 picl_nodehdl_t *childp)
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;
886 * strip "N0/" off the label if present (hang-over from wildcat)
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));
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.
901 labelp = label;
902 while ((ptr = strchr(labelp, '/')) != NULL) {
904 * null end of this section of label
906 *ptr = '\0';
909 * add intermediate nodes - parh will point to the created node
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);
918 if (err != PICL_SUCCESS)
919 return (err);
921 * if processor node, then create links to associated cpu node
922 * and OpStatus property
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);
932 labelp = ptr + 1;
935 * set back to "/"
937 *ptr = '/';
941 * if node already there, then just carry on down the tree
943 childh = find_child_by_name(parh, labelp);
944 if (childh != NULL) {
945 *childp = childh;
946 return (PICL_SUCCESS);
950 * now just have the final level of the node left. First create it.
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);
960 * if sgfru has sent us a valid handle, then there is fruid information.
961 * create the SC_handle property for FRUID.
963 if (handle != -1ULL) {
964 err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
965 if (err != PICL_SUCCESS)
966 return (err);
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);
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);
979 * For Ecache, don't need to add environmental info
980 * so return here
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);
988 * For Dimm, don't need to add environmental info
989 * so return here
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);
1003 if (err != PICL_SUCCESS)
1004 return (err);
1007 * add devices table to location node (may need
1008 * references to led devices)
1010 err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
1011 if (err != PICL_SUCCESS)
1012 return (err);
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);
1022 * remove an individual picl node - called from remove_subtree()
1023 * also removes any sensor nodes pointed at by Devices table
1025 static int
1026 remove_picl_node(picl_nodehdl_t nodeh)
1028 int err;
1029 picl_prophdl_t tblhdl;
1030 picl_prophdl_t nextprop;
1031 picl_prophdl_t refprop;
1032 char class[PICL_CLASSNAMELEN_MAX];
1035 * first scan Devices table so we can find any sensor nodes
1036 * we need to delete as well
1038 err = ptree_get_propval_by_name(nodeh, PICL_PROP_DEVICES,
1039 &tblhdl, sizeof (tblhdl));
1042 * If Devices table present, then read first column.
1043 * Devices table may be empty so don't treat this as an error
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);
1056 * walk down second column (ref ptr)
1057 * deleting the referenced nodes
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);
1068 * don't delete memory-module nodes
1069 * or cpu nodes (they weren't created
1070 * by this plugin)
1072 err = ptree_get_propval_by_name(refprop,
1073 PICL_PROP_CLASSNAME, class, sizeof (class));
1074 if (err == PICL_STALEHANDLE) {
1076 * if another plugin has already deleted the
1077 * node for us then that is ok
1079 err = ptree_get_next_by_col(nextprop,
1080 &nextprop);
1081 continue;
1083 if (err != PICL_SUCCESS) {
1084 syslog(LOG_ERR, PROP_LOOKUP_FAIL,
1085 PICL_PROP_CLASSNAME, err);
1086 return (err);
1088 if (strcmp(class, PICL_CLASS_MEMORY_MODULE) == 0 ||
1089 strcmp(class, PICL_CLASS_CPU) == 0) {
1091 * but - do need to remove _fru_parent
1092 * property and Environment table (for cpu)
1094 err = remove_references(refprop, class);
1095 if (err != PICL_SUCCESS)
1096 return (err);
1097 } else {
1099 * sensor node - need to delete it
1101 err = ptree_delete_node(refprop);
1102 if (err != PICL_SUCCESS) {
1103 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1104 return (err);
1106 (void) ptree_destroy_node(refprop);
1108 err = ptree_get_next_by_col(nextprop, &nextprop);
1113 * now we can remove the frutree node
1115 err = ptree_delete_node(nodeh);
1116 if (err != PICL_SUCCESS) {
1117 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1118 return (err);
1120 (void) ptree_destroy_node(nodeh);
1121 return (PICL_SUCCESS);
1124 static int
1125 add_child_pci_references(picl_nodehdl_t nodeh, picl_prophdl_t tblhdl,
1126 picl_nodehdl_t devnodeh)
1128 int err = PICL_SUCCESS;
1129 picl_nodehdl_t childnodeh;
1130 char class[PICL_CLASSNAMELEN_MAX];
1132 if (ptree_get_propval_by_name(devnodeh, PICL_PROP_CHILD, &childnodeh,
1133 sizeof (childnodeh)) != PICL_SUCCESS) {
1134 return (PICL_SUCCESS);
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;
1157 return (err);
1160 static int
1161 add_pci_location(picl_nodehdl_t childh, char *parent_addr, char bus_addr,
1162 char *slot_name)
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];
1175 * search for any device nodes whose BUS_ADDR or UNIT_ADDRESS
1176 * are appropriate for this pci slot
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;
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;
1197 err = ptree_get_propval_by_name(devnodeh,
1198 PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
1199 if (err != PICL_SUCCESS)
1200 break;
1203 nodeh = childh;
1204 if (got_one == 0) {
1206 * no devnodes for this slot. Create location node but
1207 * no fru node (empty slot)
1209 return (add_intermediate_location(&nodeh, slot_name, "pci"));
1213 * we've got the first devnode for this slot. Create the fru node
1214 * then walk along other nodes looking for further devnodes
1216 err = add_intermediate_nodes(&nodeh, slot_name, &tblhdl, "pci", NULL);
1217 if (err != PICL_SUCCESS)
1218 return (err);
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;
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;
1251 return (err);
1255 * add intermediate location into frutree (ie a location that we know
1256 * exists but sgfru doesn't)
1258 static int
1259 add_intermediate_location(picl_nodehdl_t *nodep, char *labelp, char *slot_name)
1261 int err;
1262 picl_nodehdl_t intermediate;
1263 picl_prophdl_t tblhdl;
1264 char parent_name[PICL_PROPNAMELEN_MAX];
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);
1274 * create label property for location class
1276 err = add_prop_charstring(intermediate, labelp, PICL_PROP_LABEL);
1277 if (err != PICL_SUCCESS)
1278 return (err);
1281 * add devices table to location node (may need references to led
1282 * devices)
1284 err = create_table(intermediate, &tblhdl, PICL_PROP_DEVICES);
1285 if (err != PICL_SUCCESS)
1286 return (err);
1289 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
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);
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);
1313 *nodep = intermediate;
1314 return (PICL_SUCCESS);
1318 * adds an intermediate location/fru pair into frutree
1320 static int
1321 add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
1322 picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name)
1324 int err;
1325 picl_nodehdl_t intermediate;
1326 picl_nodehdl_t intermediate2;
1329 * create intermediate location node (unless it has already been
1330 * created)
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);
1343 * create intermediate fru node (unless it has already been
1344 * created)
1346 intermediate2 = find_child_by_name(intermediate, labelp);
1347 if (intermediate2 == NULL) {
1349 * need to create intermediate fru node node
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);
1359 * Create empty Devices table
1361 err = create_table(intermediate2, tblhdlp, PICL_PROP_DEVICES);
1362 if (err != PICL_SUCCESS)
1363 return (err);
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);
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);
1377 *nodep = intermediate2;
1378 return (PICL_SUCCESS);
1382 * need to remove _fru_parent property and Environment table (for cpu)
1384 static int
1385 remove_references(picl_prophdl_t refprop, char *class)
1387 picl_prophdl_t platprop;
1388 int err;
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);
1396 err = ptree_delete_prop(platprop);
1397 if (err != PICL_SUCCESS) {
1398 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1399 return (err);
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) {
1406 * multi-core cpu is setup with only one cpu having
1407 * env table so ignore PICL_PROPNOTFOUND error.
1409 if (err == PICL_PROPNOTFOUND) {
1410 return (PICL_SUCCESS);
1412 syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_ENV, err);
1413 return (err);
1415 err = ptree_delete_prop(platprop);
1416 if (err != PICL_SUCCESS) {
1417 syslog(LOG_ERR, DELETE_PROP_FAIL, err);
1418 return (err);
1420 (void) ptree_destroy_prop(platprop);
1422 return (PICL_SUCCESS);
1426 * subroutine for various functions. Finds immediate child of parh with
1427 * requested name if present. Otherwise returns NULL.
1429 static picl_nodehdl_t
1430 find_child_by_name(picl_nodehdl_t parh, char *name)
1432 picl_nodehdl_t nodeh;
1433 int err;
1434 char nodename[PICL_PROPNAMELEN_MAX];
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);
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);
1455 static int
1456 create_dimm_references(picl_nodehdl_t parh, int dimm_id,
1457 picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
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;
1472 * create reference properties for memory nodes
1473 * - first find names of ancestor frus - ie "SBx/Py/Bz"
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);
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);
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);
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);
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);
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);
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);
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);
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
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);
1536 * now find corresponding memory-module-group node if present
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);
1544 * check if this is the right bank - if not move on to sibling
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);
1564 * now find corresponding memory-module node if present
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);
1572 * for each DIMM set up links with matching memory-module node
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);
1587 err = ptree_get_propval_by_name(memhdl, PICL_PROP_PEER,
1588 &memhdl, sizeof (picl_nodehdl_t));
1589 if (err != PICL_SUCCESS)
1590 break;
1592 return (PICL_SUCCESS);
1595 static int
1596 create_cpu_references(char *pname, picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
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];
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);
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);
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);
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.
1646 sprintf_buf2(name, CPU_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
1648 err = ptree_get_node_by_path(name, &cpuhdl);
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);
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);
1684 * now create reference properties
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);
1697 * create Environment table on cpu node - with Die and Ambient
1698 * temperature sensors if present. If already there, delete and start
1699 * again
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);
1708 err = create_table(cpuhdl, &envtblhdl, PICL_PROP_ENV);
1709 if (err != PICL_SUCCESS)
1710 return (err);
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'));
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);
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'));
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));
1739 return (PICL_SUCCESS);
1743 * subroutine of add_subtree - get a list of children of a parent node
1745 static sgfrunode_t *
1746 get_node_children(fru_hdl_t fruparent, int *num_childrenp)
1748 int max_children, i;
1749 sgfrunode_t *fruchildren = NULL;
1750 child_info_t child_info;
1751 int frufd;
1754 * Open the sgfru pseudo dev
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);
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);
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) {
1773 * got them - return success
1775 (void) close(frufd);
1776 *num_childrenp = child_info.fru_cnt;
1777 return (fruchildren);
1779 free(fruchildren);
1782 * if ENOMEM, need to calloc more space - so go round loop again
1783 * otherwise fail
1785 if (errno != ENOMEM) {
1786 (void) close(frufd);
1787 syslog(LOG_ERR, SGFRU_IOCTL_FAIL, SGFRU_GETCHILDLIST,
1788 fruparent, strerror(errno));
1789 return (NULL);
1792 (void) close(frufd);
1793 syslog(LOG_ERR, MALLOC_FAIL);
1794 return (NULL);
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)
1801 picl_prophdl_t proph;
1802 ptree_propinfo_t propinfo;
1803 int err;
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);
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);
1817 return (PICL_SUCCESS);
1820 /* Creates a void property for a given PICL node */
1821 static int
1822 add_prop_void(picl_nodehdl_t nodeh, char *name)
1824 picl_prophdl_t proph;
1825 ptree_propinfo_t propinfo;
1826 int err;
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);
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);
1839 return (PICL_SUCCESS);
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)
1846 picl_prophdl_t proph;
1847 ptree_propinfo_t propinfo;
1848 int err;
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);
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);
1862 return (PICL_SUCCESS);
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)
1869 picl_prophdl_t proph;
1870 ptree_propinfo_t propinfo;
1871 int err;
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);
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);
1884 return (PICL_SUCCESS);
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)
1891 picl_prophdl_t proph;
1892 ptree_propinfo_t propinfo;
1893 int err;
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);
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);
1906 return (PICL_SUCCESS);
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)
1913 picl_prophdl_t proph;
1914 ptree_propinfo_t propinfo;
1915 int err;
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);
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);
1929 return (PICL_SUCCESS);
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)
1936 int err;
1937 ptree_propinfo_t prop;
1938 picl_prophdl_t prophdl[2];
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);
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);
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);
1976 /* create an empty table property */
1977 static int
1978 create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
1980 int err;
1981 ptree_propinfo_t prop;
1982 picl_prophdl_t tblprophdl;
1984 err = ptree_create_table(tblhdlp);
1985 if (err != PICL_SUCCESS) {
1986 syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
1987 return (err);
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);
2003 static void
2004 frudr_add_subtree(picl_nodehdl_t parh)
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;
2011 (void) add_subtree(parh, sgfruhdl);
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)
2019 picl_nodehdl_t fruh;
2020 picl_nodehdl_t parh;
2022 if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
2024 * now frudata has been notified that the node is to be
2025 * removed, we can actually remove it
2027 fruh = NULL;
2028 (void) nvlist_lookup_uint64(earg,
2029 PICLEVENTARG_FRUHANDLE, &fruh);
2030 if (fruh != NULL) {
2031 (void) remove_subtree(fruh);
2034 * Now repopulate the frutree with current data.
2036 parh = NULL;
2037 (void) nvlist_lookup_uint64(earg,
2038 PICLEVENTARG_PARENTHANDLE, &parh);
2039 if (parh != NULL) {
2040 frudr_add_subtree(parh);
2044 nvlist_free(earg);
2045 free(earg);
2046 free(ename);
2050 * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
2052 static void
2053 post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
2055 nvlist_t *nvl;
2056 char *ev_name;
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;
2065 if (parenth != 0L &&
2066 nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
2067 free(ev_name);
2068 nvlist_free(nvl);
2069 return;
2071 if (fruh != 0L &&
2072 nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
2073 free(ev_name);
2074 nvlist_free(nvl);
2075 return;
2077 if (ptree_post_event(ev_name, nvl, sizeof (nvl),
2078 frudr_completion_handler) != 0) {
2079 free(ev_name);
2080 nvlist_free(nvl);
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)
2089 static void
2090 update_fru_hdl(picl_nodehdl_t loc, fru_hdl_t newsgfruhdl)
2092 picl_prophdl_t schproph;
2093 int err;
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);
2101 (void) add_prop_ull(loc, (uint64_t)newsgfruhdl, PICL_PROP_SC_HANDLE);
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.
2108 static int
2109 get_fruhdl_from_parent(picl_nodehdl_t loc, fru_hdl_t *fruhdl)
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;
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);
2143 free(fruchildren);
2144 return (PICL_FAILURE);
2148 * handle EC_DR picl events
2150 /*ARGSUSED*/
2151 static void
2152 frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
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;
2164 if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0)
2165 return;
2167 if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
2168 return;
2170 if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
2171 nvlist_free(nvlp);
2172 return;
2175 if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
2176 nvlist_free(nvlp);
2177 return;
2180 if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
2181 nvlist_free(nvlp);
2182 return;
2185 if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
2186 nvlist_free(nvlp);
2187 return;
2190 if (strncmp(ap_id, AP_ID_PREAMBLE, AP_ID_PREAMBLE_LEN) != 0) {
2191 nvlist_free(nvlp);
2192 return;
2196 * OK - so this is an EC_DR event - let's handle it.
2198 sprintf_buf2(path, CHASSIS_LOC_PATH, &ap_id[AP_ID_PREAMBLE_LEN]);
2201 * special case - SSC arrival means that SSC has been reset - we
2202 * need to flush the cached sgfru handles
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;
2215 /* find existing chassis node */
2216 if (ptree_get_node_by_path(CHASSIS_PATH, &parh) !=
2217 PICL_SUCCESS) {
2218 nvlist_free(nvlp);
2219 return;
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;
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;
2236 err = ptree_delete_prop(schproph);
2237 if (err != PICL_SUCCESS) {
2238 nvlist_free(nvlp);
2239 return;
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;
2250 * remove all subtrees except DISK, TAPE, DVD and PCI subtrees
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);
2275 if (got_peer == 0)
2276 break;
2277 chdh = peerh;
2281 /* add new subtrees */
2282 (void) add_subtree(parh, sgfruchassisp->handle);
2283 free(sgfruchassisp);
2285 nvlist_free(nvlp);
2286 return;
2289 if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
2290 nvlist_free(nvlp);
2291 return;
2293 if (ptree_get_propval_by_name(locnodeh, PICL_PROP_SC_HANDLE,
2294 &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
2295 nvlist_free(nvlp);
2296 return;
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.
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) {
2308 * fru was there - but has gone away
2310 post_frudr_event(PICL_FRU_REMOVED, locnodeh, fruh);
2312 } else {
2314 * fru has been inserted (or may need to update)
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.
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;
2330 (void) add_subtree(locnodeh, sgfruhdl);
2332 nvlist_free(nvlp);
2336 * handle memcfg picl events - need to update reference properties
2338 /*ARGSUSED*/
2339 static void
2340 frumemcfg_evhandler(const char *ename, const void *earg, size_t size,
2341 void *cookie)
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];
2362 if (strcmp(ename, PICLEVENT_MC_ADDED) != 0 &&
2363 strcmp(ename, PICLEVENT_MC_REMOVED) != 0)
2364 return;
2367 * find corresponding frutree dimm nodes
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;
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;
2397 * walk through the DIMM locations
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;
2415 * this is a frutree dimm node corresponding to the
2416 * memory controller that has been added/deleted
2417 * - so create/delete reference properties
2419 if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
2421 * find bank name
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;
2433 err = ptree_get_propval_by_name(bankfruhdl,
2434 PICL_PROP_NAME, bname, sizeof (bname));
2435 if (err != PICL_SUCCESS)
2436 goto next_dimm;
2439 * find memory group node
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;
2448 * check if this is the right bank - if not
2449 * move on to sibling
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;
2472 * got the right bank - now create appropriate
2473 * link
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;
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;
2505 } else if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0) {
2507 * XXX - no mechanism for deleting row - so
2508 * delete whole tabel and start again
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);
2518 err = create_table(fruhdl, &tblhdl,
2519 PICL_PROP_DEVICES);
2520 if (err != PICL_SUCCESS)
2521 return;
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;
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;
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.
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);
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.
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)
2580 int err;
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);
2588 err = create_table_entry(tblhdl, *sensorhdlp, class);
2589 if (err != PICL_SUCCESS)
2590 return (err);
2592 err = add_sensor_prop(*sensorhdlp, prop_class);
2593 if (err != PICL_SUCCESS)
2594 return (err);
2596 err = add_prop_charstring(*sensorhdlp, "0", PICL_PROP_UNIT_ADDRESS);
2597 if (err != PICL_SUCCESS)
2598 return (err);
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);
2607 return (err);
2611 * subroutine for add_sensor_node()/add_env_nodes(). Used for adding dynamic
2612 * properties
2614 static int
2615 add_sensor_prop(picl_nodehdl_t nodeh, char *class)
2617 ptree_propinfo_t propinfo;
2618 int err;
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);
2646 if (err != PICL_SUCCESS) {
2647 syslog(LOG_ERR, PROPINFO_FAIL, class, err);
2648 return (err);
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);
2656 return (PICL_SUCCESS);
2660 * Get requested kstat
2662 static int
2663 open_kstat(char *name, void **ptr, kstat_ctl_t **kcp)
2665 kstat_t *info_ksp;
2667 *kcp = kstat_open();
2668 if (*kcp == NULL) {
2669 syslog(LOG_ERR, KSTAT_FAIL);
2670 return (PICL_FAILURE);
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);
2678 if (kstat_read(*kcp, info_ksp, NULL) == -1) {
2679 kstat_close(*kcp);
2680 syslog(LOG_ERR, KSTAT_FAIL);
2681 return (PICL_FAILURE);
2683 *ptr = info_ksp;
2684 return (PICL_SUCCESS);
2688 * dimm status - uses bank-status property on memory-controller node
2691 static int
2692 get_dimm_status(ptree_rarg_t *arg, void *result)
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];
2708 * find the name of this node
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);
2718 * find the name of grandparent (dimm bank) node
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);
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);
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);
2740 * lookup memory-module node in Devices table
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);
2748 err = ptree_get_next_by_row(tblhdl, &nextprop);
2749 if (err != PICL_SUCCESS) {
2751 * if Devices table empty then dimm is unconfigured
2753 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2754 MAX_OPERATIONAL_STATUS_LEN);
2755 return (PICL_SUCCESS);
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);
2764 * walk down second column (ref ptr)
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);
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);
2782 err = ptree_get_next_by_col(nextprop, &nextprop);
2783 if (err != PICL_SUCCESS) {
2785 * if no memory-module in Devices table
2786 * then dimm is unconfigured
2788 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2789 MAX_OPERATIONAL_STATUS_LEN);
2790 return (PICL_SUCCESS);
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.
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);
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);
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);
2820 * bank-status is a table. Need to find the entry corresponding
2821 * to this node
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);
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);
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);
2847 break;
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;
2856 return (PICL_SUCCESS);
2860 * cpu status - uses State property on cpu node
2863 static int
2864 get_cpu_status(ptree_rarg_t *arg, void *result)
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];
2874 * lookup cpu node in Devices table
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);
2882 err = ptree_get_next_by_row(tblhdl, &nextprop);
2883 if (err != PICL_SUCCESS) {
2885 * if Devices table empty then cpu is unconfigured
2887 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2888 MAX_OPERATIONAL_STATUS_LEN);
2889 return (PICL_SUCCESS);
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);
2898 * walk down second column (ref ptr)
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);
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);
2915 err = ptree_get_next_by_col(nextprop, &nextprop);
2916 if (err != PICL_SUCCESS) {
2918 * if no cpu in Devices table
2919 * then cpu is unconfigured
2921 (void) strlcpy(result, PICL_PROPVAL_DISABLED,
2922 MAX_OPERATIONAL_STATUS_LEN);
2923 return (PICL_SUCCESS);
2928 * we've finally found the associated cpu node. Now need to find its
2929 * status property if present (if not assume OK)
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);
2943 (void) strlcpy(result, PICL_PROPVAL_OKAY, MAX_OPERATIONAL_STATUS_LEN);
2944 return (PICL_SUCCESS);
2948 * system/io board condition - uses sgenv driver kstats
2951 static int
2952 get_board_status(ptree_rarg_t *arg, void *result)
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;
2962 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
2963 sizeof (name));
2964 if (err != PICL_SUCCESS) {
2965 return (err);
2968 err = open_kstat(SG_BOARD_STATUS_KSTAT_NAME, (void **)&board_info_ksp,
2969 &kc);
2970 if (err != PICL_SUCCESS) {
2971 return (err);
2974 brd = board_info_ksp->ks_data;
2975 for (i = 0; i < SGENV_NUM_BOARD_READINGS(board_info_ksp); i++, brd++) {
2977 * check this kstat matches the name of the node
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);
2986 if (strncmp(buf, name, strlen(buf)) != 0)
2987 continue;
2990 * ok - got the right kstat - get it's value
2991 * note that values 0-4 are defined in sbdp_mbox.h
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);
3000 kstat_close(kc);
3001 return (PICL_PROPVALUNAVAILABLE);
3004 static int
3005 get_op_status(ptree_rarg_t *arg, void *result)
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;
3014 err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3015 sizeof (name));
3016 if (err != PICL_SUCCESS) {
3017 return (err);
3021 * handle dimms, cpus and system boards specially
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));
3032 * otherwise OperationalStatus is derived from the fault led state
3036 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
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);
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);
3059 } else {
3060 if (get_led(name, FAULT_LED, value) != PICL_SUCCESS) {
3061 return (PICL_PROPVALUNAVAILABLE);
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);
3073 static int
3074 add_board_status(picl_nodehdl_t nodeh, char *nodename)
3076 ptree_propinfo_t propinfo;
3077 int err;
3078 picl_prophdl_t prophdl;
3081 * check if OperationalStatus property already created for this fru
3083 err = ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
3084 &prophdl);
3085 if (err == PICL_SUCCESS)
3086 return (PICL_SUCCESS);
3089 * put operational status on dimms, cpus, SBs, IBs, PSUs, FTs, Fans, RPs
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);
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);
3111 return (PICL_SUCCESS);
3115 * environmental information handling - uses sgenv driver kstats
3118 static int
3119 add_env_nodes(picl_nodehdl_t nodeh, char *nodename, picl_prophdl_t tblhdl)
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;
3135 err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
3136 if (err != PICL_SUCCESS) {
3137 return (err);
3140 env = env_info_ksp->ks_data;
3141 for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
3143 * check values from kstat entry are within valid range
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;
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
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);
3172 if (strcmp(nodename, fruname) != 0)
3173 continue;
3176 * set up FRUType. Note we only want to do this once per fru
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;
3189 * create the sensor node with a sensible name
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);
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);
3222 break;
3226 * check if sensor node has already been created
3228 sprintf_buf3(buf, "%s_%s", nodename, id);
3229 if (find_child_by_name(sch, buf) != NULL)
3230 continue;
3232 if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_COOLING) {
3234 * create individual fan_unit nodes
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))) {
3253 * put sensors under individual processor nodes
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;
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;
3278 * add additional properties
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;
3287 * add threshold at 75% of full speed
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;
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:
3356 * The 48VDC sensor is just an indicator - doesn't
3357 * give reading or thresholds
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;
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;
3388 done:
3389 kstat_close(kc);
3390 return (err);
3393 static int
3394 get_sensor_data(ptree_rarg_t *arg, void *result)
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;
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);
3414 err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
3415 if (err != PICL_SUCCESS) {
3416 return (err);
3419 env = env_info_ksp->ks_data;
3420 for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
3422 * check kstat values are within range
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;
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
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);
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);
3483 break;
3485 if (strcmp(buf1, name) != 0)
3486 continue;
3489 * ok - this is the kstat we want - update
3490 * Condition, or sensor reading as requested
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);
3512 kstat_close(kc);
3513 return (PICL_SUCCESS);
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);
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);
3575 break;
3576 default:
3577 kstat_close(kc);
3578 return (PICL_PROPVALUNAVAILABLE);
3580 kstat_close(kc);
3581 return (PICL_SUCCESS);
3583 kstat_close(kc);
3584 return (PICL_PROPVALUNAVAILABLE);
3588 * led information handling - uses lw8 driver
3591 static int
3592 add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
3593 picl_prophdl_t tblhdl)
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];
3602 * Open the lw8 pseudo dev to get the led information
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);
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);
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);
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);
3636 if (err != PICL_SUCCESS) {
3637 (void) close(ledfd);
3638 return (err);
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);
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);
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);
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);
3668 (void) close(ledfd);
3669 return (PICL_SUCCESS);
3672 static int
3673 get_led(char *name, char *ptr, char *result)
3675 int ledfd;
3676 lom_get_led_t lom_get_led;
3679 * Open the lw8 pseudo dev to get the led information
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);
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);
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);
3706 static int
3707 get_led_data(ptree_rarg_t *arg, void *result)
3709 int rc; /* return code */
3710 char name[PICL_PROPNAMELEN_MAX];
3711 char *ptr;
3713 rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3714 sizeof (name));
3715 if (rc != PICL_SUCCESS)
3716 return (rc);
3718 ptr = strchr(name, '_');
3719 *ptr++ = '\0'; /* now name is fru name, ptr is led name */
3720 return (get_led(name, ptr, (char *)result));
3723 static int
3724 set_led(char *name, char *ptr, char *value)
3726 int ledfd;
3727 lom_set_led_t lom_set_led;
3730 * Open the lw8 pseudo dev to set the led information
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);
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;
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);
3754 (void) close(ledfd);
3755 return (PICL_SUCCESS);
3758 static int
3759 set_led_data(ptree_warg_t *arg, const void *value)
3761 int rc; /* return code */
3762 char name[PICL_PROPNAMELEN_MAX];
3763 char *ptr;
3765 rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
3766 sizeof (name));
3767 if (rc != PICL_SUCCESS)
3768 return (rc);
3770 ptr = strchr(name, '_');
3771 *ptr++ = '\0'; /* now name is fru name, ptr is led name */
3772 return (set_led(name, ptr, (char *)value));
3775 static void
3776 disk_leds_init(void)
3778 int err = 0, i;
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;
3790 if (ledsthr_created) {
3792 * this is a restart, wake up sleeping threads
3794 err = pthread_mutex_lock(&g_mutex);
3795 if (err != 0) {
3796 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
3797 return;
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;
3812 ledsthr_created = B_TRUE;
3814 for (i = 0; i < N_DISKS; i++) {
3815 (void) set_led(lw8_disks[i].d_fruname, FAULT_LED,
3816 PICL_PROPVAL_OFF);
3820 static void
3821 disk_leds_fini(void)
3823 int err;
3826 * tell led thread to pause
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;
3835 g_wait_now = B_TRUE;
3836 disk_leds_thread_ack = B_FALSE;
3837 (void) pthread_cond_broadcast(&g_cv);
3840 * and wait for the led thread to acknowledge
3842 while (!disk_leds_thread_ack) {
3843 (void) pthread_cond_wait(&g_cv_ack, &g_mutex);
3845 (void) pthread_mutex_unlock(&g_mutex);
3848 static void
3849 update_disk_node(struct lw8_disk *diskp)
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;
3859 sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
3860 if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
3861 return;
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;
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);
3894 * Implement a state machine in order to:
3896 * o enable/disable disk LEDs
3897 * o add/delete the disk's node in the FRU tree
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.
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.
3909 static void
3910 set_disk_leds(struct lw8_disk *disk)
3912 devctl_hdl_t dhdl;
3913 uint_t cur_state = 0;
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;
3922 devctl_device_getstate(dhdl, &cur_state);
3923 devctl_release(dhdl);
3925 if ((cur_state & DEVICE_OFFLINE) != 0) {
3926 switch (disk->d_state) {
3927 default:
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.
3936 assert(0);
3937 /*FALLTHROUGH*/
3939 case DISK_STATE_NOT_INIT:
3940 case DISK_STATE_READY:
3941 disk->d_state = DISK_STATE_NOT_READY;
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);
3948 update_disk_node(disk);
3949 break;
3951 case DISK_STATE_NOT_READY:
3952 break;
3954 } else if ((cur_state & DEVICE_ONLINE) != 0) {
3955 switch (disk->d_state) {
3956 default:
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.
3965 assert(0);
3966 /*FALLTHROUGH*/
3968 case DISK_STATE_NOT_INIT:
3969 case DISK_STATE_NOT_READY:
3970 disk->d_state = DISK_STATE_READY;
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);
3977 update_disk_node(disk);
3978 break;
3980 case DISK_STATE_READY:
3981 break;
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).
3993 /*ARGSUSED*/
3994 static void *
3995 disk_leds_thread(void *args)
3997 int i;
3998 int err = 0;
3999 int n_disks = N_DISKS;
4001 static char *lw8_pci_devs[] = {
4002 DISK0_BASE_PATH,
4003 DISK1_BASE_PATH
4006 static char *lw8_pcix_devs[] = {
4007 DISK0_BASE_PATH_PCIX,
4008 DISK1_BASE_PATH_PCIX
4011 static char **lw8_devs;
4013 if (pcix_io) {
4014 lw8_devs = lw8_pcix_devs;
4015 } else {
4016 lw8_devs = lw8_pci_devs;
4020 * create aliases for disk names
4022 for (i = 0; i < n_disks; i++) {
4023 char buffer[MAXPATHLEN];
4025 (void) snprintf(buffer, sizeof (buffer), "/devices%s",
4026 lw8_devs[i]);
4027 lw8_disks[i].d_devices_path = strdup(buffer);
4029 (void) snprintf(buffer, sizeof (buffer), "/platform%s",
4030 lw8_devs[i]);
4031 lw8_disks[i].d_plat_path = strdup(buffer);
4034 for (;;) {
4035 for (i = 0; i < n_disks; i++) {
4036 set_disk_leds(&lw8_disks[i]);
4040 * wait a bit until we check again
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;
4048 err = pthread_mutex_lock(&g_mutex);
4049 if (err != 0) {
4050 syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
4051 break;
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);
4061 (void) pthread_mutex_unlock(&g_mutex);
4063 return ((void *)err);