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