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