xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4u/lw8/frutree/piclfrutree.c (revision 1797:cb5daa1663b0)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
231708Sstevel  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
281708Sstevel 
291708Sstevel /*
301708Sstevel  * This plugin-in creates the FRU Hierarchy for the
311708Sstevel  * SUNW,Netra-T12 platform and manages the environmental sensors
321708Sstevel  * on the platform.
331708Sstevel  */
341708Sstevel 
351708Sstevel #include <stdio.h>
361708Sstevel #include <errno.h>
371708Sstevel #include <syslog.h>
381708Sstevel #include <strings.h>
391708Sstevel #include <libintl.h>
401708Sstevel #include <stdlib.h>
411708Sstevel #include <unistd.h>
421708Sstevel #include <fcntl.h>
431708Sstevel #include <picl.h>
441708Sstevel #include <picltree.h>
451708Sstevel #include <sys/stat.h>
461708Sstevel #include <libnvpair.h>
471708Sstevel #include <sys/param.h>
481708Sstevel #include <kstat.h>
491708Sstevel #include <config_admin.h>
501708Sstevel #include <sys/sbd_ioctl.h>
511708Sstevel #include <sys/sgfrutree.h>
521708Sstevel #include <sys/sgenv.h>
531708Sstevel #include <sys/ioccom.h>
541708Sstevel #include <sys/lw8.h>
551708Sstevel #include <sys/sysevent/dr.h>
561708Sstevel #include <pthread.h>
571708Sstevel #include <sys/obpdefs.h>
581708Sstevel #include "libdevice.h"
591708Sstevel #include "picldefs.h"
601708Sstevel #define	NDEBUG
611708Sstevel #include <assert.h>
621708Sstevel 
631708Sstevel /*
641708Sstevel  * Plugin registration entry points
651708Sstevel  */
661708Sstevel static void	piclfrutree_register(void);
671708Sstevel static void	piclfrutree_init(void);
681708Sstevel static void	piclfrutree_fini(void);
691708Sstevel #pragma	init(piclfrutree_register)
701708Sstevel 
711708Sstevel static picld_plugin_reg_t  my_reg_info = {
721708Sstevel 	PICLD_PLUGIN_VERSION_1,
731708Sstevel 	PICLD_PLUGIN_CRITICAL,
741708Sstevel 	"SUNW_Netra-T12_frutree",
751708Sstevel 	piclfrutree_init,
761708Sstevel 	piclfrutree_fini,
771708Sstevel };
781708Sstevel 
791708Sstevel /*
801708Sstevel  * Log message texts
811708Sstevel  */
821708Sstevel #define	DEV_OPEN_FAIL gettext("piclfrutree_init: open of %s failed: %s")
831708Sstevel #define	ADD_NODES_FAIL gettext("piclfrutree_init: add_all_nodes failed: %d")
841708Sstevel #define	GET_ROOT_FAIL gettext("piclfrutree_init: ptree_get_root failed")
851708Sstevel #define	ADD_FRUTREE_FAIL gettext("piclfrutree_init: add frutree failed")
861708Sstevel #define	INVALID_PICL_CLASS gettext("add_subtree: invalid picl class 0x%x")
871708Sstevel #define	ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d")
881708Sstevel #define	GET_NEXT_BY_ROW_FAIL gettext("ptree_get_next_by_row %s failed: %d")
891708Sstevel #define	PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d")
901708Sstevel #define	GET_PROPVAL_FAIL gettext("ptree_get_propval failed: %d")
911708Sstevel #define	DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d")
921708Sstevel #define	DELETE_NODE_FAIL gettext("ptree_delete_node failed: %d")
931708Sstevel #define	ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d")
941708Sstevel #define	SGFRU_IOCTL_FAIL gettext("sgfru ioctl 0x%x handle 0x%llx failed: %s")
951708Sstevel #define	LED_IOCTL_FAIL gettext("led ioctl failed: %s")
961708Sstevel #define	MALLOC_FAIL gettext("piclfrutree: malloc failed")
971708Sstevel #define	NO_SC_FAIL gettext("piclfrutree: cannot find sc node")
981708Sstevel #define	NO_NODE_FAIL gettext("piclfrutree: cannot find node %s: %d")
991708Sstevel #define	KSTAT_FAIL gettext("piclfrutree: failure accessing kstats")
1001708Sstevel #define	ADD_TBL_ENTRY_FAIL gettext("piclfrutree: cannot add entry to table")
1011708Sstevel #define	PROP_LOOKUP_FAIL gettext("piclfrutree: cannot find %s property: %d")
1021708Sstevel #define	EM_DI_INIT_FAIL	gettext("frutree: di_init failed: %s")
1031708Sstevel #define	EM_THREAD_CREATE_FAILED gettext("frutree: pthread_create failed: %s")
1041708Sstevel #define	EM_MUTEX_FAIL gettext("frutree: pthread_mutex_lock returned: %s")
1051708Sstevel #define	EM_POLL_FAIL gettext("frutree: poll() failed: %s")
1061708Sstevel #define	DEVCTL_DEVICE_ACQUIRE_FAILED \
1071708Sstevel     gettext("frutree: devctl_device_acquire() failed: %s")
1081708Sstevel 
1091708Sstevel /*
1101708Sstevel  * PICL property values
1111708Sstevel  */
1121708Sstevel #define	PICL_PROPVAL_TRUE		"true"
1131708Sstevel #define	PICL_PROPVAL_SYSTEM		"system"
1141708Sstevel #define	PICL_PROPVAL_ON			"ON"
1151708Sstevel #define	PICL_PROPVAL_OFF		"OFF"
1161708Sstevel #define	PICL_PROPVAL_BLINKING		"BLINKING"
1171708Sstevel #define	PICL_PROPVAL_FLASHING		"FLASHING"
1181708Sstevel #define	PICL_PROPVAL_CHASSIS		"chassis"
1191708Sstevel #define	PICL_PROPVAL_AMBIENT		"Ambient"
1201708Sstevel #define	PICL_PROPVAL_DIE		"Die"
1211708Sstevel #define	PICL_PROPVAL_GREEN		"green"
1221708Sstevel #define	PICL_PROPVAL_AMBER		"amber"
1231708Sstevel #define	PICL_PROPVAL_OKAY		"okay"
1241708Sstevel #define	PICL_PROPVAL_FAILED		"failed"
1251708Sstevel #define	PICL_PROPVAL_WARNING		"warning"
1261708Sstevel #define	PICL_PROPVAL_DISABLED		"disabled"
1271708Sstevel #define	PICL_PROPVAL_UNKNOWN		"unknown"
1281708Sstevel #define	PICL_PROPVAL_SELF_REGULATING	"self-regulating"
1291708Sstevel #define	PICL_PROPVAL_PER_CENT 		"%"
1301708Sstevel #define	PICL_PROP_BANK_STATUS		"bank-status"
1311708Sstevel 
1321708Sstevel /*
1331708Sstevel  * PICL property names
1341708Sstevel  */
1351708Sstevel #define	PICL_PROP_LOW_WARNING_THRESHOLD	"LowWarningThreshold"
1361708Sstevel 
1371708Sstevel /*
1381708Sstevel  * Local defines
1391708Sstevel  */
1401708Sstevel #define	MAX_LINE_SIZE		1024
1411708Sstevel #define	MAX_TRIES		4
1421708Sstevel #define	MAX_SPEED_UNIT_LEN	20
1431708Sstevel #define	MAX_OPERATIONAL_STATUS_LEN	10
1441708Sstevel #define	MAX_CONDITION_LEN	10
1451708Sstevel #define	MAX_LABEL_LEN		256
1461708Sstevel #define	MAX_STATE_LEN		10
1471708Sstevel #define	MAX_STATE_SIZE		32
1481708Sstevel #define	LED_PSEUDO_DEV "/devices/pseudo/lw8@0:lw8"
1491708Sstevel #define	SC_DEV "/platform/ssm@0,0/pci@18,700000/bootbus-controller@4"
1501708Sstevel #define	SC_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/bootbus-controller@3"
1511708Sstevel #define	CPU_DEV "/platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0"
1521708Sstevel #define	CPU_DEV2 "/platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0"
1531708Sstevel #define	CPU_DEV3C0 "/platform/ssm@0,0/cmp@%x,0/cpu@0"
1541708Sstevel #define	CPU_DEV3C1 "/platform/ssm@0,0/cmp@%x,0/cpu@1"
1551708Sstevel #define	MEMORY_DEV "/platform/ssm@0,0/memory-controller@%x,400000"
1561708Sstevel #define	IO_DEV "/platform/ssm@0,0/pci@%s"
1571708Sstevel #define	DISK0_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@0,0"
1581717Swesolows #define	DISK0_DEV "/platform" DISK0_BASE_PATH
1591708Sstevel #define	DISK1_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@1,0"
1601717Swesolows #define	DISK1_DEV "/platform" DISK1_BASE_PATH
1611708Sstevel #define	DISK0_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@0,0"
1621717Swesolows #define	DISK0_DEV_PCIX "/platform" DISK0_BASE_PATH_PCIX
1631708Sstevel #define	DISK1_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@1,0"
1641717Swesolows #define	DISK1_DEV_PCIX "/platform" DISK1_BASE_PATH_PCIX
1651708Sstevel #define	TAPE_DEV "/platform/ssm@0,0/pci@18,600000/scsi@2/st@5,0"
1661708Sstevel #define	TAPE_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/scsi@2/st@5,0"
1671708Sstevel #define	DVD_DEV "/platform/ssm@0,0/pci@18,700000/ide@3/sd@0,0"
1681708Sstevel #define	DVD_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/ide@2/sd@0,0"
1691708Sstevel #define	CHASSIS_PATH "/frutree/chassis"
1701708Sstevel #define	CHASSIS_LOC_PATH "/frutree/chassis/%s"
1711708Sstevel #define	PROC_LOC_PATH "/frutree/chassis/SB%d/SB%d/P%d"
1721708Sstevel #define	PROC_FRU_PATH "/frutree/chassis/SB%d/SB%d/P%d/P%d"
1731708Sstevel /*
1741708Sstevel  * Calculate safari address to put in CPU_DEV/MEMORY_DEV string based on
1751708Sstevel  * SBx/Py fru path name
1761708Sstevel  */
1771708Sstevel #define	SB_P_TO_SAFARI_ADDR(sbname, pname) \
1781708Sstevel 	((pname[1] - '0') + (4 * (sbname[2] - '0')))
1791708Sstevel #define	SAFARI_ADDR_TO_SB(value) (value >> 2)
1801708Sstevel #define	SAFARI_ADDR_TO_P(value) (value & 3)
1811708Sstevel #define	AP_ID_PREAMBLE "ssm0:N0."
1821708Sstevel #define	AP_ID_PREAMBLE_LEN 8
1831708Sstevel #define	LABEL_PREAMBLE "N0/"
1841708Sstevel #define	LABEL_PREAMBLE_LEN 3
1851708Sstevel /*
1861708Sstevel  * work out type of fru based on name
1871708Sstevel  */
1881708Sstevel #define	IS_ECACHE_NODE(name)	(name[0] == 'E')
1891708Sstevel #define	IS_DIMM_NODE(name)	(name[0] == 'D' && name[1] != 'V')
1901708Sstevel #define	IS_PROC_NODE(name)	(name[0] == 'P' && name[1] != 'S')
1911708Sstevel #define	IS_PSU_NODE(name)	(name[0] == 'P' && name[1] == 'S')
1921708Sstevel #define	IS_SB_NODE(name)	(name[0] == 'S' && name[1] == 'B')
1931708Sstevel #define	IS_IB_NODE(name)	(name[0] == 'I')
1941708Sstevel #define	IS_FT_NODE(name)	(name[0] == 'F' && name[1] == 'T')
1951708Sstevel #define	IS_FAN_NODE(name)	(name[0] == 'F' && name[1] != 'T')
1961708Sstevel #define	IS_RP_NODE(name)	(name[0] == 'R')
1971708Sstevel /*
1981708Sstevel  * rename sgfru driver's node_t to sgfrunode_t to avoid confusion
1991708Sstevel  */
2001708Sstevel #define	sgfrunode_t node_t
2011708Sstevel 
2021708Sstevel /*
2031708Sstevel  * disk_led data
2041708Sstevel  */
2051708Sstevel #define	REMOK_LED "ok_to_remove"
2061708Sstevel #define	FAULT_LED "fault"
2071708Sstevel #define	POWER_LED "power"
2081708Sstevel 
2091708Sstevel /*
2101708Sstevel  * 'struct lw8_disk' contains the per-disk metadata needed to
2111708Sstevel  * manage the current state of one of the internal disks.
2121708Sstevel  *
2131708Sstevel  * 'lw8_disks[]' is an array that contains the metadata
2141708Sstevel  * for N_DISKS disks.
2151708Sstevel  *
2161708Sstevel  * The d_fruname field of 'struct lw8_disk' is static.
2171708Sstevel  * d_plat_path and d_devices_path are aliases for device-paths
2181708Sstevel  * to the disk.  They are logically static, as they are computed
2191708Sstevel  * when the disk_leds_thread() thread does its initialization.
2201708Sstevel  *
2211708Sstevel  * d_state is the most interesting field, as it changes
2221708Sstevel  * dynamically, based on whether the associated disk
2231708Sstevel  * is currently Configured or Unconfigured (by DR).  d_state
2241708Sstevel  * is an optimization that minimizes per-disk actions such
2251708Sstevel  * as setting of LEDs and updating the FRU Tree.
2261708Sstevel  *
2271708Sstevel  * A disk starts in a d_state of DISK_STATE_NOT_INIT
2281708Sstevel  * and moves to DISK_STATE_READY when the disk is
2291708Sstevel  * Configured (by DR) and it moves to DISK_STATE_NOT_READY
2301708Sstevel  * when it is Unconfigured (by DR).
2311708Sstevel  */
2321708Sstevel typedef enum {
2331708Sstevel 	DISK_STATE_NOT_INIT,
2341708Sstevel 	DISK_STATE_READY,
2351708Sstevel 	DISK_STATE_NOT_READY
2361708Sstevel } disk_state_t;
2371708Sstevel 
2381708Sstevel struct lw8_disk {
2391708Sstevel 	char		*d_fruname;		/* FRU name */
2401708Sstevel 	char		*d_plat_path;		/* /platform */
2411708Sstevel 	char		*d_devices_path;	/* /devices */
2421708Sstevel 	disk_state_t	d_state;
2431708Sstevel };
2441708Sstevel 
2451708Sstevel #define	N_DISKS 2
2461708Sstevel static	struct lw8_disk	lw8_disks[N_DISKS] = {
2471708Sstevel 	{"DISK0", NULL, NULL, DISK_STATE_NOT_INIT},
2481708Sstevel 	{"DISK1", NULL, NULL, DISK_STATE_NOT_INIT} };
2491708Sstevel 
2501708Sstevel /* Duration of inactivity within disk_leds_thread() */
2511708Sstevel #define	THR_POLL_PERIOD 5000    /* milliseconds */
2521708Sstevel 
2531708Sstevel static volatile boolean_t	disk_leds_thread_ack = B_FALSE;
2541708Sstevel static pthread_t		ledsthr_tid;
2551708Sstevel static pthread_attr_t		ledsthr_attr;
2561708Sstevel static boolean_t		ledsthr_created = B_FALSE;
2571708Sstevel static uint_t			ledsthr_poll_period =
2581708Sstevel 				    THR_POLL_PERIOD;
2591708Sstevel static boolean_t		g_mutex_init = B_FALSE;
2601708Sstevel static pthread_cond_t		g_cv;
2611708Sstevel static pthread_cond_t		g_cv_ack;
2621708Sstevel static pthread_mutex_t		g_mutex;
2631708Sstevel static volatile boolean_t	g_wait_now = B_FALSE;
2641708Sstevel 
2651708Sstevel static void disk_leds_init(void);
2661708Sstevel static void disk_leds_fini(void);
2671708Sstevel static void *disk_leds_thread(void *args);
2681708Sstevel 
2691708Sstevel /*
2701708Sstevel  * Tables to convert sgenv information
2711708Sstevel  */
2721708Sstevel static char *hpu_type_table[] = { "", "SSC", "SB", "RP", "FT",
2731708Sstevel 	"IB", "PS", "ID"};
2741708Sstevel static char *hpu_fru_type_table[] = { "", "SSC", "CPU", "RP", "FT",
2751708Sstevel 	"PCIB", "PS", "ID"};
2761708Sstevel static char *hpu_part_table[] = { "", "sbbc", "sdc",
2771708Sstevel 	"ar", "cbh", "dx", "cheetah", "1.5vdc", "3.3vdc",
2781708Sstevel 	"5vdc", "12vdc", "output", "current", "board", "sc-app",
2791708Sstevel 	"schizo", "fan", "input"};
2801708Sstevel static char *hpu_sensor_table[] = { "", "", "current",
2811708Sstevel 	"temp", "cooling", "1.5vdc", "1.8vdc", "3.3vdc", "5vdc",
2821708Sstevel 	"12vdc", "48vdc", NULL, "2.4vdc"};
2831708Sstevel static char *hpu_sensor_class_table[] = { "", "", PICL_CLASS_CURRENT_SENSOR,
2841708Sstevel 	PICL_CLASS_TEMPERATURE_SENSOR, PICL_CLASS_FAN,
2851708Sstevel 	PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR,
2861708Sstevel 	PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR,
2871708Sstevel 	PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_INDICATOR,
2881708Sstevel 	NULL, PICL_CLASS_VOLTAGE_SENSOR};
2891708Sstevel static char *hpu_sensor_prop_table[] = { "", "", PICL_PROP_CURRENT,
2901708Sstevel 	PICL_PROP_TEMPERATURE, PICL_PROP_FAN_SPEED, PICL_PROP_VOLTAGE,
2911708Sstevel 	PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE,
2921708Sstevel 	PICL_PROP_VOLTAGE, PICL_PROP_CONDITION, NULL, PICL_PROP_VOLTAGE};
2931708Sstevel static char *hpu_condition_table[] = {"unknown", "okay", "failing",
2941708Sstevel 	"failed", "unusable"};
2951708Sstevel 
2961708Sstevel /*
2971708Sstevel  * variables set up in init
2981708Sstevel  */
2991708Sstevel static picl_nodehdl_t	frutreeh;
3001708Sstevel static picl_nodehdl_t	sch = NULL;
3011708Sstevel static int init_complete;
3021708Sstevel static int pcix_io = 0;
3031708Sstevel 
3041708Sstevel /*
3051708Sstevel  * forward reference
3061708Sstevel  */
3071708Sstevel static int add_all_nodes(void);
3081708Sstevel static int remove_subtree(picl_nodehdl_t parh);
3091708Sstevel static int add_subtree(picl_nodehdl_t parh, fru_hdl_t fruparent);
3101708Sstevel static int add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
3111708Sstevel     picl_nodehdl_t *childp);
3121708Sstevel static int add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
3131708Sstevel     picl_nodehdl_t *childp);
3141708Sstevel static int add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
3151708Sstevel     picl_nodehdl_t *childp);
3161708Sstevel static int add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
3171708Sstevel     picl_nodehdl_t *childp);
3181708Sstevel static int add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
3191708Sstevel     picl_prophdl_t tblhdl);
3201708Sstevel static int add_env_nodes(picl_nodehdl_t nodeh, char *nodename,
3211708Sstevel     picl_prophdl_t tblhdl);
3221708Sstevel static int add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
3231708Sstevel     picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name);
3241708Sstevel static int add_intermediate_location(picl_nodehdl_t *nodep, char *labelp,
3251708Sstevel     char *slot_name);
3261708Sstevel static int add_pci_location(picl_nodehdl_t childh, char *parent_addr,
3271708Sstevel     char bus_addr, char *slot_name);
3281708Sstevel static picl_nodehdl_t find_child_by_name(picl_nodehdl_t parh, char *name);
3291708Sstevel static int create_dimm_references(picl_nodehdl_t parh, int dimm_id,
3301708Sstevel     picl_nodehdl_t nodeh, picl_prophdl_t tblhdl);
3311708Sstevel static int create_cpu_references(char *pname, picl_nodehdl_t nodeh,
3321708Sstevel     picl_prophdl_t tblhdl);
3331708Sstevel static void post_frudr_event(char *ename, picl_nodehdl_t parenth,
3341708Sstevel     picl_nodehdl_t fruh);
3351708Sstevel static int remove_references(picl_prophdl_t refprop, char *class);
3361708Sstevel static int remove_picl_node(picl_nodehdl_t nodeh);
3371708Sstevel static sgfrunode_t *get_node_children(fru_hdl_t fruparent, int *num_childrenp);
3381708Sstevel static int add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name);
3391708Sstevel static int add_prop_void(picl_nodehdl_t nodeh, char *name);
3401708Sstevel static int add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name);
3411708Sstevel static int add_prop_int(picl_nodehdl_t nodeh, int value, char *name);
3421708Sstevel static int add_prop_float(picl_nodehdl_t nodeh, float value, char *name);
3431708Sstevel static int add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name);
3441708Sstevel static void frudr_evhandler(const char *ename, const void *earg,
3451708Sstevel     size_t size, void *cookie);
3461708Sstevel static void frumemcfg_evhandler(const char *ename, const void *earg,
3471708Sstevel     size_t size, void *cookie);
3481708Sstevel static int add_sensor_prop(picl_nodehdl_t nodeh, char *class);
3491708Sstevel static int add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl,
3501708Sstevel     char *nodename, char *class, char *prop_class,
3511708Sstevel     picl_prophdl_t tblhdl, picl_nodehdl_t *sensorhdlp);
3521708Sstevel static int create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp,
3531708Sstevel     char *tbl_name);
3541708Sstevel static int create_table_entry(picl_prophdl_t tblhdl,
3551708Sstevel     picl_nodehdl_t refhdl, char *class);
3561708Sstevel static int get_sensor_data(ptree_rarg_t *arg, void *result);
3571708Sstevel static int get_led(char *name, char *ptr, char *result);
3581708Sstevel static int get_led_data(ptree_rarg_t *arg, void *result);
3591708Sstevel static int set_led_data(ptree_warg_t *arg, const void *value);
3601708Sstevel static int get_cpu_status(ptree_rarg_t *arg, void *result);
3611708Sstevel static int add_board_status(picl_nodehdl_t nodeh, char *nodename);
3621708Sstevel static int get_board_status(ptree_rarg_t *arg, void *result);
3631708Sstevel static int get_op_status(ptree_rarg_t *arg, void *result);
3641708Sstevel 
3651708Sstevel #define	sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2)
3661708Sstevel #define	sprintf_buf3(buf, a1, a2, a3) \
3671708Sstevel 	(void) snprintf(buf, sizeof (buf), a1, a2, a3)
3681708Sstevel #define	sprintf_buf4(buf, a1, a2, a3, a4) \
3691708Sstevel 	(void) snprintf(buf, sizeof (buf), a1, a2, a3, a4)
3701708Sstevel #define	sprintf_buf5(buf, a1, a2, a3, a4, a5) \
3711708Sstevel 	(void) snprintf(buf, sizeof (buf), a1, a2, a3, a4, a5)
3721708Sstevel /*
3731708Sstevel  * This function is executed as part of .init when the plugin is
3741708Sstevel  * dlopen()ed
3751708Sstevel  */
3761708Sstevel static void
piclfrutree_register(void)3771708Sstevel piclfrutree_register(void)
3781708Sstevel {
3791708Sstevel 	(void) picld_plugin_register(&my_reg_info);
3801708Sstevel }
3811708Sstevel 
3821708Sstevel /*
3831708Sstevel  * This function is the init entry point of the plugin.
3841708Sstevel  * It initializes the /frutree tree
3851708Sstevel  */
3861708Sstevel static void
piclfrutree_init(void)3871708Sstevel piclfrutree_init(void)
3881708Sstevel {
3891708Sstevel 	int err;
3901708Sstevel 
3911708Sstevel 	(void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
3921708Sstevel 	    frudr_evhandler, NULL);
3931708Sstevel 	(void) ptree_register_handler(PICLEVENT_MC_ADDED,
3941708Sstevel 	    frumemcfg_evhandler, NULL);
3951708Sstevel 	(void) ptree_register_handler(PICLEVENT_MC_REMOVED,
3961708Sstevel 	    frumemcfg_evhandler, NULL);
3971708Sstevel 	init_complete = 0;
3981708Sstevel 
3991708Sstevel 	err = add_all_nodes();
4001708Sstevel 	disk_leds_init();
4011708Sstevel 	init_complete = 1;
4021708Sstevel 	if (err != PICL_SUCCESS) {
4031708Sstevel 		syslog(LOG_ERR, ADD_NODES_FAIL, err);
4041708Sstevel 		piclfrutree_fini();
4051708Sstevel 	}
4061708Sstevel }
4071708Sstevel 
4081708Sstevel /*
4091708Sstevel  * This function is the fini entry point of the plugin.
4101708Sstevel  */
4111708Sstevel static void
piclfrutree_fini(void)4121708Sstevel piclfrutree_fini(void)
4131708Sstevel {
4141708Sstevel 	(void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
4151708Sstevel 	    frudr_evhandler, NULL);
4161708Sstevel 	(void) ptree_unregister_handler(PICLEVENT_MC_ADDED,
4171708Sstevel 	    frumemcfg_evhandler, NULL);
4181708Sstevel 	(void) ptree_unregister_handler(PICLEVENT_MC_REMOVED,
4191708Sstevel 	    frumemcfg_evhandler, NULL);
4201708Sstevel 	(void) remove_subtree(frutreeh);
4211708Sstevel 	disk_leds_fini();
4221708Sstevel }
4231708Sstevel 
4241708Sstevel /*
4251708Sstevel  * called from piclfrutree_init() to initialise picl frutree
4261708Sstevel  */
4271708Sstevel static int
add_all_nodes(void)4281708Sstevel add_all_nodes(void)
4291708Sstevel {
4301708Sstevel 	int err;
4311708Sstevel 	picl_nodehdl_t rooth;
4321708Sstevel 
4331708Sstevel 	/* Get the root node of the PICL tree */
4341708Sstevel 	err = ptree_get_root(&rooth);
4351708Sstevel 	if (err != PICL_SUCCESS) {
4361708Sstevel 		syslog(LOG_ERR, GET_ROOT_FAIL);
4371708Sstevel 		return (err);
4381708Sstevel 	}
4391708Sstevel 
4401708Sstevel 	/* find sc node so we can create sensor nodes under it */
4411708Sstevel 
4421708Sstevel 	err = ptree_get_node_by_path(SC_DEV, &sch);
4431708Sstevel 	if (err != PICL_SUCCESS) {
4441708Sstevel 
4451708Sstevel 		/*
4461708Sstevel 		 * There is a XMITS/PCI-X IO Board assembly implements
4471708Sstevel 		 * a different path for the the bootbus controller.
4481708Sstevel 		 */
4491708Sstevel 		err = ptree_get_node_by_path(SC_DEV_PCIX, &sch);
4501708Sstevel 		if (err == PICL_SUCCESS)
4511708Sstevel 			pcix_io = 1;
4521708Sstevel 	}
4531708Sstevel 
4541708Sstevel 	if (err != PICL_SUCCESS) {
4551708Sstevel 		syslog(LOG_ERR, NO_SC_FAIL);
4561708Sstevel 		return (err);
4571708Sstevel 	}
4581708Sstevel 
4591708Sstevel 	/* Create and add the root node of the FRU subtree */
4601708Sstevel 	err = ptree_create_and_add_node(rooth, PICL_NODE_FRUTREE,
4611708Sstevel 	    PICL_CLASS_PICL, &frutreeh);
4621708Sstevel 	if (err != PICL_SUCCESS) {
4631708Sstevel 		syslog(LOG_ERR, ADD_FRUTREE_FAIL);
4641708Sstevel 		return (err);
4651708Sstevel 	}
4661708Sstevel 
4671708Sstevel 	/* Recursively query the SC and add frutree nodes */
4681708Sstevel 	return (add_subtree(frutreeh, ROOTPARENT));
4691708Sstevel }
4701708Sstevel 
4711708Sstevel /*
4721708Sstevel  * Recursive routine to add picl nodes to the frutree. Called from
4731708Sstevel  * add_all_nodes() for the whole frutree at initialisation, and from
4741708Sstevel  * frudr_evhandler() for portions of the frutree on DR insert events
4751708Sstevel  */
4761708Sstevel static int
add_subtree(picl_nodehdl_t parh,fru_hdl_t handle)4771708Sstevel add_subtree(picl_nodehdl_t parh, fru_hdl_t handle)
4781708Sstevel {
4791708Sstevel 	int	err, i;
4801708Sstevel 	int	num_children;
4811708Sstevel 	sgfrunode_t	*cp, *fruchildren = NULL;
4821708Sstevel 	picl_nodehdl_t childh;
4831708Sstevel 
4841708Sstevel 	/* find children of the parent node */
4851708Sstevel 	fruchildren = get_node_children(handle, &num_children);
4861708Sstevel 	if (fruchildren == NULL)
4871708Sstevel 		return (PICL_FAILURE);
4881708Sstevel 
4891708Sstevel 	/* for each child, add a new picl node */
4901708Sstevel 	for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
4911708Sstevel 		/*
4921708Sstevel 		 * Add the appropriate PICL class
4931708Sstevel 		 */
4941708Sstevel 		childh = 0;
4951708Sstevel 		err = add_picl_node(parh, cp, &childh);
4961708Sstevel 		if (err == PICL_NOTNODE)
4971708Sstevel 			continue;
4981708Sstevel 		if (err != PICL_SUCCESS) {
4991708Sstevel 			free(fruchildren);
5001708Sstevel 			return (err);
5011708Sstevel 		}
5021708Sstevel 
5031708Sstevel 		/*
5041708Sstevel 		 * Recursively call this function based on has_children hint
5051708Sstevel 		 */
5061708Sstevel 		if (childh && cp->has_children) {
5071708Sstevel 			err = add_subtree(childh, cp->handle);
5081708Sstevel 			if (err != PICL_SUCCESS) {
5091708Sstevel 				free(fruchildren);
5101708Sstevel 				return (err);
5111708Sstevel 			}
5121708Sstevel 		}
5131708Sstevel 	}
5141708Sstevel 	free(fruchildren);
5151708Sstevel 	return (PICL_SUCCESS);
5161708Sstevel }
5171708Sstevel 
5181708Sstevel /*
5191708Sstevel  * Recursive routine to remove picl nodes to the frutree. Called from
5201708Sstevel  * piclfrutree_fini() for the whole frutree at termination, and from
5211708Sstevel  * frudr_completion_handler() for portions of the frutree on DR remove events
5221708Sstevel  */
5231708Sstevel static int
remove_subtree(picl_nodehdl_t parh)5241708Sstevel remove_subtree(picl_nodehdl_t parh)
5251708Sstevel {
5261708Sstevel 	picl_nodehdl_t chdh;
5271708Sstevel 
5281708Sstevel 	for (;;) {
5291708Sstevel 		if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh,
5301708Sstevel 		    sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
5311708Sstevel 			if (remove_subtree(chdh) != PICL_SUCCESS)
5321708Sstevel 				return (PICL_FAILURE);
5331708Sstevel 		} else {
5341708Sstevel 			return (remove_picl_node(parh));
5351708Sstevel 		}
5361708Sstevel 	}
5371708Sstevel 	/* NOTREACHED */
5381708Sstevel }
5391708Sstevel 
5401708Sstevel /*
5411708Sstevel  * Add fru and location nodes with SC_handle property
5421708Sstevel  * (aka, container handle, for frus).
5431708Sstevel  * Return picl_nodehdl of created node in *childp.
5441708Sstevel  */
5451708Sstevel static int
add_picl_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)5461708Sstevel add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
5471708Sstevel     picl_nodehdl_t *childp)
5481708Sstevel {
5491708Sstevel 	switch (sgfrunode->class) {
5501708Sstevel 	case PSEUDO_FRU_CLASS:
5511708Sstevel 		return (add_chassis_node(parh, sgfrunode, childp));
5521708Sstevel 
5531708Sstevel 	case FRU_CLASS:
5541708Sstevel 		return (add_fru_node(parh, sgfrunode, childp));
5551708Sstevel 
5561708Sstevel 	case LOCATION_CLASS:
5571708Sstevel 		return (add_location_node(parh, sgfrunode, childp));
5581708Sstevel 
5591708Sstevel 	default:
5601708Sstevel 		syslog(LOG_ERR, INVALID_PICL_CLASS, sgfrunode->class);
5611708Sstevel 		return (PICL_NOTNODE);
5621708Sstevel 	}
5631708Sstevel }
5641708Sstevel 
5651708Sstevel /*
5661708Sstevel  * create chassis node
5671708Sstevel  */
5681708Sstevel static int
add_chassis_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)5691708Sstevel add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
5701708Sstevel     picl_nodehdl_t *childp)
5711708Sstevel {
5721708Sstevel 	int err;
5731708Sstevel 	uint64_t handle = (uint64_t)sgfrunode->handle;
5741708Sstevel 	picl_prophdl_t	tblhdl;
5751708Sstevel 	picl_nodehdl_t nodeh;
5761708Sstevel 	picl_nodehdl_t devhdl;
5771708Sstevel 	picl_nodehdl_t childh;
5781708Sstevel 
5791708Sstevel 	err = ptree_create_and_add_node(parh, PICL_PROPVAL_CHASSIS,
5801708Sstevel 	    PICL_CLASS_FRU, &childh);
5811708Sstevel 	if (err != PICL_SUCCESS) {
5821708Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, PICL_PROPVAL_CHASSIS, err);
5831708Sstevel 		return (err);
5841708Sstevel 	}
5851708Sstevel 	err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
5861708Sstevel 	if (err != PICL_SUCCESS)
5871708Sstevel 		return (err);
5881708Sstevel 
5891708Sstevel 	/*
5901708Sstevel 	 * add devices table to chassis node (may need references
5911708Sstevel 	 * to led devices)
5921708Sstevel 	 */
5931708Sstevel 	err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
5941708Sstevel 	if (err != PICL_SUCCESS)
5951708Sstevel 		return (err);
5961708Sstevel 
5971708Sstevel 	err = add_led_nodes(childh, "chassis", LOM_LED_POSITION_FRU, tblhdl);
5981708Sstevel 	if (err != PICL_SUCCESS)
5991708Sstevel 		return (err);
6001708Sstevel 
6011708Sstevel 	if (pcix_io)
6021708Sstevel 		err = ptree_get_node_by_path(DISK0_DEV_PCIX, &devhdl);
6031708Sstevel 	else
6041708Sstevel 		err = ptree_get_node_by_path(DISK0_DEV, &devhdl);
6051708Sstevel 
6061708Sstevel 	nodeh = childh;
6071708Sstevel 	if (err != PICL_SUCCESS) {
6081708Sstevel 		err = add_intermediate_location(&nodeh, "DISK0", "disk-slot");
6091708Sstevel 	} else {
6101708Sstevel 		err = add_intermediate_nodes(&nodeh, "DISK0", &tblhdl,
6111708Sstevel 		    "disk-slot", NULL);
6121708Sstevel 		if (err != PICL_SUCCESS)
6131708Sstevel 			return (err);
6141708Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
6151708Sstevel 		if (err != PICL_SUCCESS)
6161708Sstevel 			return (err);
6171708Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
6181708Sstevel 	}
6191708Sstevel 	if (err != PICL_SUCCESS)
6201708Sstevel 		return (err);
6211708Sstevel 
6221708Sstevel 	if (pcix_io)
6231708Sstevel 		err = ptree_get_node_by_path(DISK1_DEV_PCIX, &devhdl);
6241708Sstevel 	else
6251708Sstevel 		err = ptree_get_node_by_path(DISK1_DEV, &devhdl);
6261708Sstevel 
6271708Sstevel 	nodeh = childh;
6281708Sstevel 	if (err != PICL_SUCCESS) {
6291708Sstevel 		err = add_intermediate_location(&nodeh, "DISK1", "disk-slot");
6301708Sstevel 	} else {
6311708Sstevel 		err = add_intermediate_nodes(&nodeh, "DISK1", &tblhdl,
6321708Sstevel 		    "disk-slot", NULL);
6331708Sstevel 		if (err != PICL_SUCCESS)
6341708Sstevel 			return (err);
6351708Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
6361708Sstevel 		if (err != PICL_SUCCESS)
6371708Sstevel 			return (err);
6381708Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
6391708Sstevel 	}
6401708Sstevel 	if (err != PICL_SUCCESS)
6411708Sstevel 		return (err);
6421708Sstevel 
6431708Sstevel 	if (pcix_io)
6441708Sstevel 		err = ptree_get_node_by_path(TAPE_DEV_PCIX, &devhdl);
6451708Sstevel 	else
6461708Sstevel 		err = ptree_get_node_by_path(TAPE_DEV, &devhdl);
6471708Sstevel 
6481708Sstevel 	nodeh = childh;
6491708Sstevel 	if (err != PICL_SUCCESS) {
6501708Sstevel 		err = add_intermediate_location(&nodeh, "TAPE", "tape-slot");
6511708Sstevel 	} else {
6521708Sstevel 		err = add_intermediate_nodes(&nodeh, "TAPE", &tblhdl,
6531708Sstevel 		    "tape-slot", NULL);
6541708Sstevel 		if (err != PICL_SUCCESS)
6551708Sstevel 			return (err);
6561708Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
6571708Sstevel 		if (err != PICL_SUCCESS)
6581708Sstevel 			return (err);
6591708Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_TAPE);
6601708Sstevel 	}
6611708Sstevel 	if (err != PICL_SUCCESS)
6621708Sstevel 		return (err);
6631708Sstevel 
6641708Sstevel 	if (pcix_io)
6651708Sstevel 		err = ptree_get_node_by_path(DVD_DEV_PCIX, &devhdl);
6661708Sstevel 	else
6671708Sstevel 		err = ptree_get_node_by_path(DVD_DEV, &devhdl);
6681708Sstevel 
6691708Sstevel 	nodeh = childh;
6701708Sstevel 	if (err != PICL_SUCCESS) {
6711708Sstevel 		err = add_intermediate_location(&nodeh, "DVD", "dvd-slot");
6721708Sstevel 	} else {
6731708Sstevel 		err = add_intermediate_nodes(&nodeh, "DVD", &tblhdl,
6741708Sstevel 		    "dvd-slot", NULL);
6751708Sstevel 		if (err != PICL_SUCCESS)
6761708Sstevel 			return (err);
6771708Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
6781708Sstevel 		if (err != PICL_SUCCESS)
6791708Sstevel 			return (err);
6801708Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_CDROM);
6811708Sstevel 	}
6821708Sstevel 	if (err != PICL_SUCCESS)
6831708Sstevel 		return (err);
6841708Sstevel 
6851708Sstevel 	if (pcix_io) {
6861708Sstevel 		/*
6871708Sstevel 		 * The XMITS/PCI-X IO Assembly is layed out a bit differently.
6881708Sstevel 		 */
6891708Sstevel 		err = add_pci_location(childh, "19,600000", '1', "PCI0");
6901708Sstevel 		if (err != PICL_SUCCESS)
6911708Sstevel 			return (err);
6921708Sstevel 		err = add_pci_location(childh, "19,600000", '2', "PCI1");
6931708Sstevel 		if (err != PICL_SUCCESS)
6941708Sstevel 			return (err);
6951708Sstevel 		err = add_pci_location(childh, "19,700000", '1', "PCI2");
6961708Sstevel 		if (err != PICL_SUCCESS)
6971708Sstevel 			return (err);
6981708Sstevel 		err = add_pci_location(childh, "19,700000", '2', "PCI3");
6991708Sstevel 		if (err != PICL_SUCCESS)
7001708Sstevel 			return (err);
7011708Sstevel 		err = add_pci_location(childh, "18,600000", '1', "PCI4");
7021708Sstevel 		if (err != PICL_SUCCESS)
7031708Sstevel 			return (err);
7041708Sstevel 		err = add_pci_location(childh, "18,600000", '2', "PCI5");
7051708Sstevel 		if (err != PICL_SUCCESS)
7061708Sstevel 			return (err);
7071708Sstevel 	} else {
7081708Sstevel 		err = add_pci_location(childh, "18,700000", '1', "PCI0");
7091708Sstevel 		if (err != PICL_SUCCESS)
7101708Sstevel 			return (err);
7111708Sstevel 		err = add_pci_location(childh, "18,700000", '2', "PCI1");
7121708Sstevel 		if (err != PICL_SUCCESS)
7131708Sstevel 			return (err);
7141708Sstevel 		err = add_pci_location(childh, "19,700000", '1', "PCI2");
7151708Sstevel 		if (err != PICL_SUCCESS)
7161708Sstevel 			return (err);
7171708Sstevel 		err = add_pci_location(childh, "19,700000", '2', "PCI3");
7181708Sstevel 		if (err != PICL_SUCCESS)
7191708Sstevel 			return (err);
7201708Sstevel 		err = add_pci_location(childh, "19,700000", '3', "PCI4");
7211708Sstevel 		if (err != PICL_SUCCESS)
7221708Sstevel 			return (err);
7231708Sstevel 		err = add_pci_location(childh, "18,600000", '1', "PCI5");
7241708Sstevel 		if (err != PICL_SUCCESS)
7251708Sstevel 			return (err);
7261708Sstevel 	}
7271708Sstevel 	*childp = childh;
7281708Sstevel 	return (PICL_SUCCESS);
7291708Sstevel }
7301708Sstevel 
7311708Sstevel /*
7321708Sstevel  * create fru node, based on sgfru node "sgfrunode" under parent parh. Return
7331708Sstevel  * picl_nodehdl of created node in *childp.
7341708Sstevel  */
7351708Sstevel static int
add_fru_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)7361708Sstevel add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
7371708Sstevel     picl_nodehdl_t *childp)
7381708Sstevel {
7391708Sstevel 	int err;
7401708Sstevel 	picl_prophdl_t	tblhdl;
7411708Sstevel 	picl_nodehdl_t childh;
7421708Sstevel 	uint64_t handle = (uint64_t)sgfrunode->handle;
7431708Sstevel 	char *nodename = sgfrunode->nodename;
7441708Sstevel 
7451708Sstevel 	/*
7461708Sstevel 	 * if sgfrunode already there, then just carry on own the tree
7471708Sstevel 	 */
7481708Sstevel 	childh = find_child_by_name(parh, nodename);
7491708Sstevel 	if (childh != NULL) {
7501708Sstevel 		/*
7511708Sstevel 		 * for frus other than dimms and ecaches, update environmental
7521708Sstevel 		 * sensors and board status if necessary
7531708Sstevel 		 */
7541708Sstevel 		if (IS_ECACHE_NODE(nodename)) {
7551708Sstevel 			*childp = childh;
7561708Sstevel 			return (PICL_SUCCESS);
7571708Sstevel 		}
7581708Sstevel 		if (IS_DIMM_NODE(nodename)) {
7591708Sstevel 			/*
7601708Sstevel 			 * for dimms we just want status
7611708Sstevel 			 */
7621708Sstevel 			err = add_board_status(childh, nodename);
7631708Sstevel 			if (err != PICL_SUCCESS)
7641708Sstevel 				return (err);
7651708Sstevel 			*childp = childh;
7661708Sstevel 			return (PICL_SUCCESS);
7671708Sstevel 		}
7681708Sstevel 		err = add_board_status(childh, nodename);
7691708Sstevel 		if (err != PICL_SUCCESS)
7701708Sstevel 			return (err);
7711708Sstevel 		err = ptree_get_propval_by_name(childh, PICL_PROP_DEVICES,
7721708Sstevel 		    &tblhdl, sizeof (tblhdl));
7731708Sstevel 		if (err != PICL_SUCCESS)
7741708Sstevel 			return (err);
7751708Sstevel 		err = add_env_nodes(childh, nodename, tblhdl);
7761708Sstevel 		if (err != PICL_SUCCESS)
7771708Sstevel 			return (err);
7781708Sstevel 		*childp = childh;
7791708Sstevel 		return (PICL_SUCCESS);
7801708Sstevel 	}
7811708Sstevel 
7821708Sstevel 	/*
7831708Sstevel 	 * create requested fru node
7841708Sstevel 	 */
7851708Sstevel 	err = ptree_create_and_add_node(parh, nodename, PICL_CLASS_FRU,
7861708Sstevel 	    &childh);
7871708Sstevel 	if (err != PICL_SUCCESS) {
7881708Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err);
7891708Sstevel 		return (err);
7901708Sstevel 	}
7911708Sstevel 
7921708Sstevel 	/*
7931708Sstevel 	 * if sgfru has sent us a valid handle, then there is fruid information.
7941708Sstevel 	 * create the SC_handle, and FRUDateAvailable properties for FRUID.
7951708Sstevel 	 */
7961708Sstevel 	if (handle != -1ULL) {
7971708Sstevel 		err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
7981708Sstevel 		if (err != PICL_SUCCESS)
7991708Sstevel 			return (err);
8001708Sstevel 		err = add_prop_void(childh, PICL_PROP_FRUDATA_AVAIL);
8011708Sstevel 		if (err != PICL_SUCCESS)
8021708Sstevel 			return (err);
8031708Sstevel 	}
8041708Sstevel 
8051708Sstevel 	/*
8061708Sstevel 	 * post fru added event to fru data plugin if this was due to
8071708Sstevel 	 * a dr event - ie post-initialisation
8081708Sstevel 	 */
8091708Sstevel 	if (init_complete)
8101708Sstevel 		post_frudr_event(PICL_FRU_ADDED, parh, NULL);
8111708Sstevel 
8121708Sstevel 	/*
8131708Sstevel 	 * Create empty Devices table - we'll add lines to it as we go along
8141708Sstevel 	 */
8151708Sstevel 	err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
8161708Sstevel 	if (err != PICL_SUCCESS)
8171708Sstevel 		return (err);
8181708Sstevel 
8191708Sstevel 	/*
8201708Sstevel 	 * Ecache nodes don't have sensors - just set up FRUType
8211708Sstevel 	 */
8221708Sstevel 	if (IS_ECACHE_NODE(nodename)) {
8231708Sstevel 		err = add_prop_charstring(childh, "EEPROM", PICL_PROP_FRU_TYPE);
8241708Sstevel 		if (err != PICL_SUCCESS)
8251708Sstevel 			return (err);
8261708Sstevel 		*childp = childh;
8271708Sstevel 		return (PICL_SUCCESS);
8281708Sstevel 	}
8291708Sstevel 
8301708Sstevel 	/*
8311708Sstevel 	 * Dimm nodes don't have sensors - just set up FRUType and
8321708Sstevel 	 * also reference properties to memory module nodes and OpStatus
8331708Sstevel 	 */
8341708Sstevel 	if (IS_DIMM_NODE(nodename)) {
8351708Sstevel 		err = add_prop_charstring(childh, "DIMM", PICL_PROP_FRU_TYPE);
8361708Sstevel 		if (err != PICL_SUCCESS)
8371708Sstevel 			return (err);
8381708Sstevel 		err = create_dimm_references(parh, nodename[1] - '0',
8391708Sstevel 		    childh, tblhdl);
8401708Sstevel 		if (err != PICL_SUCCESS)
8411708Sstevel 			return (err);
8421708Sstevel 		err = add_board_status(childh, nodename);
8431708Sstevel 		if (err != PICL_SUCCESS)
8441708Sstevel 			return (err);
8451708Sstevel 		*childp = childh;
8461708Sstevel 		return (PICL_SUCCESS);
8471708Sstevel 	}
8481708Sstevel 
8491708Sstevel 	/*
8501708Sstevel 	 * not a Dimm or Ecache node - set up environmental info,
8511708Sstevel 	 * board status and led info
8521708Sstevel 	 */
8531708Sstevel 	err = add_env_nodes(childh, nodename, tblhdl);
8541708Sstevel 	if (err != PICL_SUCCESS)
8551708Sstevel 		return (err);
8561708Sstevel 
8571708Sstevel 	err = add_board_status(childh, nodename);
8581708Sstevel 	if (err != PICL_SUCCESS)
8591708Sstevel 		return (err);
8601708Sstevel 
8611708Sstevel 	err = add_led_nodes(childh, nodename, LOM_LED_POSITION_FRU, tblhdl);
8621708Sstevel 	if (err != PICL_SUCCESS)
8631708Sstevel 		return (err);
8641708Sstevel 
8651708Sstevel 	*childp = childh;
8661708Sstevel 	return (PICL_SUCCESS);
8671708Sstevel }
8681708Sstevel 
8691708Sstevel /*
8701708Sstevel  * create location node, based on sgfru node "sgfrunode" under parent parh.
8711708Sstevel  * Return picl_nodehdl of created node in *childp.
8721708Sstevel  */
8731708Sstevel static int
add_location_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)8741708Sstevel add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
8751708Sstevel     picl_nodehdl_t *childp)
8761708Sstevel {
8771708Sstevel 	int err;
8781708Sstevel 	uint64_t handle = (uint64_t)sgfrunode->handle;
8791708Sstevel 	char *labelp;
8801708Sstevel 	char	label[MAX_LABEL_LEN];
8811708Sstevel 	char *ptr;
8821708Sstevel 	picl_prophdl_t tblhdl;
8831708Sstevel 	picl_nodehdl_t childh;
8841708Sstevel 
8851708Sstevel 	/*
8861708Sstevel 	 * strip "N0/" off the label if present (hang-over from wildcat)
8871708Sstevel 	 */
8881708Sstevel 	if (strncmp(sgfrunode->location_label, LABEL_PREAMBLE,
8891708Sstevel 	    LABEL_PREAMBLE_LEN) == 0)
8901708Sstevel 		(void) strlcpy(label, &sgfrunode->location_label[
8911708Sstevel 		    LABEL_PREAMBLE_LEN], sizeof (label));
8921708Sstevel 	else
8931708Sstevel 		(void) strlcpy(label, &sgfrunode->location_label[0],
8941708Sstevel 		    sizeof (label));
8951708Sstevel 
8961708Sstevel 	/*
8971708Sstevel 	 * some of the locations returned by sgfru are actually of the form
8981708Sstevel 	 * XX/YY/ZZ - we need to create multiple levels in the picl tree for
8991708Sstevel 	 * these.
9001708Sstevel 	 */
9011708Sstevel 	labelp = label;
9021708Sstevel 	while ((ptr = strchr(labelp, '/')) != NULL) {
9031708Sstevel 		/*
9041708Sstevel 		 * null end of this section of label
9051708Sstevel 		 */
9061708Sstevel 		*ptr = '\0';
9071708Sstevel 
9081708Sstevel 		/*
9091708Sstevel 		 * add intermediate nodes - parh will point to the created node
9101708Sstevel 		 */
9111708Sstevel 		if (IS_PROC_NODE(labelp)) {
9121708Sstevel 			err = add_intermediate_nodes(&parh, labelp, &tblhdl,
9131708Sstevel 			    "cpu", "PROC");
9141708Sstevel 		} else {
9151708Sstevel 			err = add_intermediate_nodes(&parh, labelp, &tblhdl,
9161708Sstevel 			    NULL, NULL);
9171708Sstevel 		}
9181708Sstevel 		if (err != PICL_SUCCESS)
9191708Sstevel 			return (err);
9201708Sstevel 		/*
9211708Sstevel 		 * if processor node, then create links to associated cpu node
9221708Sstevel 		 * and OpStatus property
9231708Sstevel 		 */
9241708Sstevel 		if (IS_PROC_NODE(labelp)) {
9251708Sstevel 			err = create_cpu_references(labelp, parh, tblhdl);
9261708Sstevel 			if (err != PICL_SUCCESS)
9271708Sstevel 				return (err);
9281708Sstevel 			err = add_board_status(parh, labelp);
9291708Sstevel 			if (err != PICL_SUCCESS)
9301708Sstevel 				return (err);
9311708Sstevel 		}
9321708Sstevel 		labelp = ptr + 1;
9331708Sstevel 
9341708Sstevel 		/*
9351708Sstevel 		 * set back to "/"
9361708Sstevel 		 */
9371708Sstevel 		*ptr = '/';
9381708Sstevel 	}
9391708Sstevel 
9401708Sstevel 	/*
9411708Sstevel 	 * if node already there, then just carry on down the tree
9421708Sstevel 	 */
9431708Sstevel 	childh = find_child_by_name(parh, labelp);
9441708Sstevel 	if (childh != NULL) {
9451708Sstevel 		*childp = childh;
9461708Sstevel 		return (PICL_SUCCESS);
9471708Sstevel 	}
9481708Sstevel 
9491708Sstevel 	/*
9501708Sstevel 	 * now just have the final level of the node left. First create it.
9511708Sstevel 	 */
9521708Sstevel 	err = ptree_create_and_add_node(parh, labelp, PICL_CLASS_LOCATION,
9531708Sstevel 	    &childh);
9541708Sstevel 	if (err != PICL_SUCCESS) {
9551708Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
9561708Sstevel 		return (err);
9571708Sstevel 	}
9581708Sstevel 
9591708Sstevel 	/*
9601708Sstevel 	 * if sgfru has sent us a valid handle, then there is fruid information.
9611708Sstevel 	 * create the SC_handle property for FRUID.
9621708Sstevel 	 */
9631708Sstevel 	if (handle != -1ULL) {
9641708Sstevel 		err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
9651708Sstevel 		if (err != PICL_SUCCESS)
9661708Sstevel 			return (err);
9671708Sstevel 	}
9681708Sstevel 
9691708Sstevel 	/* create label property for location class */
9701708Sstevel 	err = add_prop_charstring(childh, labelp, PICL_PROP_LABEL);
9711708Sstevel 	if (err != PICL_SUCCESS)
9721708Sstevel 		return (err);
9731708Sstevel 
9741708Sstevel 	/* create SlotType property where appropriate */
9751708Sstevel 	if (IS_ECACHE_NODE(sgfrunode->nodename)) {
9761708Sstevel 		err = add_prop_charstring(childh,
9771708Sstevel 		    "ecache", PICL_PROP_SLOT_TYPE);
9781708Sstevel 		/*
9791708Sstevel 		 * For Ecache, don't need to add environmental info
9801708Sstevel 		 * so return here
9811708Sstevel 		 */
9821708Sstevel 		*childp = childh;
9831708Sstevel 		return (err);
9841708Sstevel 	} else if (IS_DIMM_NODE(sgfrunode->nodename)) {
9851708Sstevel 		err = add_prop_charstring(childh, "memory-module",
9861708Sstevel 		    PICL_PROP_SLOT_TYPE);
9871708Sstevel 		/*
9881708Sstevel 		 * For Dimm, don't need to add environmental info
9891708Sstevel 		 * so return here
9901708Sstevel 		 */
9911708Sstevel 		*childp = childh;
9921708Sstevel 		return (err);
9931708Sstevel 	} else if (IS_SB_NODE(sgfrunode->nodename)) {
9941708Sstevel 		err = add_prop_charstring(childh, "system-board",
9951708Sstevel 		    PICL_PROP_SLOT_TYPE);
9961708Sstevel 	} else if (IS_PSU_NODE(sgfrunode->nodename)) {
9971708Sstevel 		err = add_prop_charstring(childh, "power-supply",
9981708Sstevel 		    PICL_PROP_SLOT_TYPE);
9991708Sstevel 	} else if (IS_FT_NODE(sgfrunode->nodename)) {
10001708Sstevel 		err = add_prop_charstring(childh, "fan-tray",
10011708Sstevel 		    PICL_PROP_SLOT_TYPE);
10021708Sstevel 	}
10031708Sstevel 	if (err != PICL_SUCCESS)
10041708Sstevel 		return (err);
10051708Sstevel 
10061708Sstevel 	/*
10071708Sstevel 	 * add devices table to location node (may need
10081708Sstevel 	 * references to led devices)
10091708Sstevel 	 */
10101708Sstevel 	err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
10111708Sstevel 	if (err != PICL_SUCCESS)
10121708Sstevel 		return (err);
10131708Sstevel 
10141708Sstevel 	err = add_led_nodes(childh, labelp, LOM_LED_POSITION_LOCATION, tblhdl);
10151708Sstevel 	if (err != PICL_SUCCESS)
10161708Sstevel 		return (err);
10171708Sstevel 	*childp = childh;
10181708Sstevel 	return (PICL_SUCCESS);
10191708Sstevel }
10201708Sstevel 
10211708Sstevel /*
10221708Sstevel  * remove an individual picl node - called from remove_subtree()
10231708Sstevel  * also removes any sensor nodes pointed at by Devices table
10241708Sstevel  */
10251708Sstevel static int
remove_picl_node(picl_nodehdl_t nodeh)10261708Sstevel remove_picl_node(picl_nodehdl_t nodeh)
10271708Sstevel {
10281708Sstevel 	int err;
10291708Sstevel 	picl_prophdl_t  tblhdl;
10301708Sstevel 	picl_prophdl_t  nextprop;
10311708Sstevel 	picl_prophdl_t  refprop;
10321708Sstevel 	char	class[PICL_CLASSNAMELEN_MAX];
10331708Sstevel 
10341708Sstevel 	/*
10351708Sstevel 	 * first scan Devices table so we can find any sensor nodes
10361708Sstevel 	 * we need to delete as well
10371708Sstevel 	 */
10381708Sstevel 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_DEVICES,
10391708Sstevel 	    &tblhdl, sizeof (tblhdl));
10401708Sstevel 
10411708Sstevel 	/*
10421708Sstevel 	 * If Devices table present, then read first column.
10431708Sstevel 	 * Devices table may be empty so don't treat this as an error
10441708Sstevel 	 */
10451708Sstevel 	if (err == PICL_SUCCESS &&
10461708Sstevel 	    ptree_get_next_by_row(tblhdl, &nextprop) == PICL_SUCCESS) {
10471708Sstevel 		/* find second column */
10481708Sstevel 		err = ptree_get_next_by_row(nextprop, &nextprop);
10491708Sstevel 		if (err != PICL_SUCCESS) {
10501708Sstevel 			syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL,
10511708Sstevel 			    PICL_PROP_DEVICES, err);
10521708Sstevel 			return (err);
10531708Sstevel 		}
10541708Sstevel 
10551708Sstevel 		/*
10561708Sstevel 		 * walk down second column (ref ptr)
10571708Sstevel 		 * deleting the referenced nodes
10581708Sstevel 		 */
10591708Sstevel 		while (err == PICL_SUCCESS) {
10601708Sstevel 			err = ptree_get_propval(nextprop, &refprop,
10611708Sstevel 			    sizeof (refprop));
10621708Sstevel 			if (err != PICL_SUCCESS) {
10631708Sstevel 				syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
10641708Sstevel 				return (err);
10651708Sstevel 			}
10661708Sstevel 
10671708Sstevel 			/*
10681708Sstevel 			 * don't delete memory-module nodes
10691708Sstevel 			 * or cpu nodes (they weren't created
10701708Sstevel 			 * by this plugin)
10711708Sstevel 			 */
10721708Sstevel 			err = ptree_get_propval_by_name(refprop,
10731708Sstevel 			    PICL_PROP_CLASSNAME, class, sizeof (class));
10741708Sstevel 			if (err == PICL_STALEHANDLE) {
10751708Sstevel 				/*
10761708Sstevel 				 * if another plugin has already deleted the
10771708Sstevel 				 * node for us then that is ok
10781708Sstevel 				 */
10791708Sstevel 				err = ptree_get_next_by_col(nextprop,
10801708Sstevel 				    &nextprop);
10811708Sstevel 				continue;
10821708Sstevel 			}
10831708Sstevel 			if (err != PICL_SUCCESS) {
10841708Sstevel 				syslog(LOG_ERR, PROP_LOOKUP_FAIL,
10851708Sstevel 				    PICL_PROP_CLASSNAME, err);
10861708Sstevel 				return (err);
10871708Sstevel 			}
10881708Sstevel 			if (strcmp(class, PICL_CLASS_MEMORY_MODULE) == 0 ||
10891708Sstevel 			    strcmp(class, PICL_CLASS_CPU) == 0) {
10901708Sstevel 				/*
10911708Sstevel 				 * but - do need to remove _fru_parent
10921708Sstevel 				 * property and Environment table (for cpu)
10931708Sstevel 				 */
10941708Sstevel 				err = remove_references(refprop, class);
10951708Sstevel 				if (err != PICL_SUCCESS)
10961708Sstevel 					return (err);
10971708Sstevel 			} else {
10981708Sstevel 				/*
10991708Sstevel 				 * sensor node - need to delete it
11001708Sstevel 				 */
11011708Sstevel 				err = ptree_delete_node(refprop);
11021708Sstevel 				if (err != PICL_SUCCESS) {
11031708Sstevel 					syslog(LOG_ERR, DELETE_PROP_FAIL, err);
11041708Sstevel 					return (err);
11051708Sstevel 				}
11061708Sstevel 				(void) ptree_destroy_node(refprop);
11071708Sstevel 			}
11081708Sstevel 			err = ptree_get_next_by_col(nextprop, &nextprop);
11091708Sstevel 		}
11101708Sstevel 	}
11111708Sstevel 
11121708Sstevel 	/*
11131708Sstevel 	 * now we can remove the frutree node
11141708Sstevel 	 */
11151708Sstevel 	err = ptree_delete_node(nodeh);
11161708Sstevel 	if (err != PICL_SUCCESS) {
11171708Sstevel 		syslog(LOG_ERR, DELETE_PROP_FAIL, err);
11181708Sstevel 		return (err);
11191708Sstevel 	}
11201708Sstevel 	(void) ptree_destroy_node(nodeh);
11211708Sstevel 	return (PICL_SUCCESS);
11221708Sstevel }
11231708Sstevel 
11241708Sstevel static int
add_child_pci_references(picl_nodehdl_t nodeh,picl_prophdl_t tblhdl,picl_nodehdl_t devnodeh)11251708Sstevel add_child_pci_references(picl_nodehdl_t nodeh, picl_prophdl_t tblhdl,
11261708Sstevel     picl_nodehdl_t devnodeh)
11271708Sstevel {
11281708Sstevel 	int err = PICL_SUCCESS;
11291708Sstevel 	picl_nodehdl_t childnodeh;
11301708Sstevel 	char	class[PICL_CLASSNAMELEN_MAX];
11311708Sstevel 
11321708Sstevel 	if (ptree_get_propval_by_name(devnodeh, PICL_PROP_CHILD, &childnodeh,
11331708Sstevel 	    sizeof (childnodeh)) != PICL_SUCCESS) {
11341708Sstevel 		return (PICL_SUCCESS);
11351708Sstevel 	}
11361708Sstevel 	for (;;) {
11371708Sstevel 		err = ptree_get_propval_by_name(childnodeh,
11381708Sstevel 		    PICL_PROP_CLASSNAME, class, sizeof (class));
11391708Sstevel 		if (err != PICL_SUCCESS)
11401708Sstevel 			break;
11411708Sstevel 		err = add_prop_ref(childnodeh, nodeh, PICL_REFPROP_FRU_PARENT);
11421708Sstevel 		if (err != PICL_SUCCESS)
11431708Sstevel 			break;
11441708Sstevel 		err = create_table_entry(tblhdl, childnodeh, class);
11451708Sstevel 		if (err != PICL_SUCCESS)
11461708Sstevel 			break;
11471708Sstevel 		err = add_child_pci_references(nodeh, tblhdl, childnodeh);
11481708Sstevel 		if (err != PICL_SUCCESS)
11491708Sstevel 			break;
11501708Sstevel 		err = ptree_get_propval_by_name(childnodeh,
11511708Sstevel 		    PICL_PROP_PEER, &childnodeh, sizeof (picl_nodehdl_t));
11521708Sstevel 		if (err != PICL_SUCCESS) {
11531708Sstevel 			err = PICL_SUCCESS;
11541708Sstevel 			break;
11551708Sstevel 		}
11561708Sstevel 	}
11571708Sstevel 	return (err);
11581708Sstevel }
11591708Sstevel 
11601708Sstevel static int
add_pci_location(picl_nodehdl_t childh,char * parent_addr,char bus_addr,char * slot_name)11611708Sstevel add_pci_location(picl_nodehdl_t childh, char *parent_addr, char bus_addr,
11621708Sstevel     char *slot_name)
11631708Sstevel {
11641708Sstevel 	int err;
11651708Sstevel 	int got_one = 0;
11661708Sstevel 	picl_nodehdl_t nodeh;
11671708Sstevel 	picl_nodehdl_t devnodeh;
11681708Sstevel 	picl_nodehdl_t devhdl;
11691708Sstevel 	char	addr[MAXPATHLEN];
11701708Sstevel 	char parent_path[MAXPATHLEN];
11711708Sstevel 	picl_prophdl_t tblhdl;
11721708Sstevel 	char	class[PICL_CLASSNAMELEN_MAX];
11731708Sstevel 
11741708Sstevel 	/*
11751708Sstevel 	 * search for any device nodes whose BUS_ADDR or UNIT_ADDRESS
11761708Sstevel 	 * are appropriate for this pci slot
11771708Sstevel 	 */
11781708Sstevel 	sprintf_buf2(parent_path, IO_DEV, parent_addr);
11791708Sstevel 	if (ptree_get_node_by_path(parent_path, &devhdl) == PICL_SUCCESS &&
11801708Sstevel 	    ptree_get_propval_by_name(devhdl, PICL_PROP_CHILD, &devnodeh,
11811708Sstevel 	    sizeof (devnodeh)) == PICL_SUCCESS) {
11821708Sstevel 		while (!got_one) {
11831708Sstevel 			err = ptree_get_propval_by_name(devnodeh,
11841708Sstevel 			    PICL_PROP_BUS_ADDR, addr, sizeof (addr));
11851708Sstevel 			if (err == PICL_SUCCESS && addr[0] == bus_addr &&
11861708Sstevel 			    (addr[1] == ',' || addr[1] == '\0')) {
11871708Sstevel 				got_one = 1;
11881708Sstevel 				break;
11891708Sstevel 			}
11901708Sstevel 			err = ptree_get_propval_by_name(devnodeh,
11911708Sstevel 			    PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr));
11921708Sstevel 			if (err == PICL_SUCCESS && addr[0] == bus_addr &&
11931708Sstevel 			    (addr[1] == ',' || addr[1] == '\0')) {
11941708Sstevel 				got_one = 1;
11951708Sstevel 				break;
11961708Sstevel 			}
11971708Sstevel 			err = ptree_get_propval_by_name(devnodeh,
11981708Sstevel 			    PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
11991708Sstevel 			if (err != PICL_SUCCESS)
12001708Sstevel 				break;
12011708Sstevel 		}
12021708Sstevel 	}
12031708Sstevel 	nodeh = childh;
12041708Sstevel 	if (got_one == 0) {
12051708Sstevel 		/*
12061708Sstevel 		 * no devnodes for this slot. Create location node but
12071708Sstevel 		 * no fru node (empty slot)
12081708Sstevel 		 */
12091708Sstevel 		return (add_intermediate_location(&nodeh, slot_name, "pci"));
12101708Sstevel 	}
12111708Sstevel 
12121708Sstevel 	/*
12131708Sstevel 	 * we've got the first devnode for this slot. Create the fru node
12141708Sstevel 	 * then walk along other nodes looking for further devnodes
12151708Sstevel 	 */
12161708Sstevel 	err = add_intermediate_nodes(&nodeh, slot_name, &tblhdl, "pci", NULL);
12171708Sstevel 	if (err != PICL_SUCCESS)
12181708Sstevel 		return (err);
12191708Sstevel 
12201708Sstevel 	for (;;) {
12211708Sstevel 		if (((err = ptree_get_propval_by_name(devnodeh,
12221708Sstevel 		    PICL_PROP_BUS_ADDR, addr, sizeof (addr))) ==
12231708Sstevel 		    PICL_SUCCESS && addr[0] == bus_addr &&
12241708Sstevel 		    (addr[1] == ',' || addr[1] == '\0')) ||
12251708Sstevel 		    ((err = ptree_get_propval_by_name(devnodeh,
12261708Sstevel 		    PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr))) ==
12271708Sstevel 		    PICL_SUCCESS && addr[0] == bus_addr &&
12281708Sstevel 		    (addr[1] == ',' || addr[1] == '\0'))) {
12291708Sstevel 			err = ptree_get_propval_by_name(devnodeh,
12301708Sstevel 			    PICL_PROP_CLASSNAME, class, sizeof (class));
12311708Sstevel 			if (err != PICL_SUCCESS)
12321708Sstevel 				break;
12331708Sstevel 			err = add_prop_ref(devnodeh, nodeh,
12341708Sstevel 			    PICL_REFPROP_FRU_PARENT);
12351708Sstevel 			if (err != PICL_SUCCESS)
12361708Sstevel 				break;
12371708Sstevel 			err = create_table_entry(tblhdl, devnodeh, class);
12381708Sstevel 			if (err != PICL_SUCCESS)
12391708Sstevel 				break;
12401708Sstevel 			err = add_child_pci_references(nodeh, tblhdl, devnodeh);
12411708Sstevel 			if (err != PICL_SUCCESS)
12421708Sstevel 				break;
12431708Sstevel 		}
12441708Sstevel 		err = ptree_get_propval_by_name(devnodeh,
12451708Sstevel 		    PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
12461708Sstevel 		if (err != PICL_SUCCESS) {
12471708Sstevel 			err = PICL_SUCCESS;
12481708Sstevel 			break;
12491708Sstevel 		}
12501708Sstevel 	}
12511708Sstevel 	return (err);
12521708Sstevel }
12531708Sstevel 
12541708Sstevel /*
12551708Sstevel  * add intermediate location into frutree (ie a location that we know
12561708Sstevel  * exists but sgfru doesn't)
12571708Sstevel  */
12581708Sstevel static int
add_intermediate_location(picl_nodehdl_t * nodep,char * labelp,char * slot_name)12591708Sstevel add_intermediate_location(picl_nodehdl_t *nodep, char *labelp, char *slot_name)
12601708Sstevel {
12611708Sstevel 	int err;
12621708Sstevel 	picl_nodehdl_t intermediate;
12631708Sstevel 	picl_prophdl_t tblhdl;
12641708Sstevel 	char	parent_name[PICL_PROPNAMELEN_MAX];
12651708Sstevel 
12661708Sstevel 	err = ptree_create_and_add_node(*nodep, labelp, PICL_CLASS_LOCATION,
12671708Sstevel 	    &intermediate);
12681708Sstevel 	if (err != PICL_SUCCESS) {
12691708Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
12701708Sstevel 		return (err);
12711708Sstevel 	}
12721708Sstevel 
12731708Sstevel 	/*
12741708Sstevel 	 * create label property for location class
12751708Sstevel 	 */
12761708Sstevel 	err = add_prop_charstring(intermediate, labelp, PICL_PROP_LABEL);
12771708Sstevel 	if (err != PICL_SUCCESS)
12781708Sstevel 		return (err);
12791708Sstevel 
12801708Sstevel 	/*
12811708Sstevel 	 * add devices table to location node (may need references to led
12821708Sstevel 	 * devices)
12831708Sstevel 	 */
12841708Sstevel 	err = create_table(intermediate, &tblhdl, PICL_PROP_DEVICES);
12851708Sstevel 	if (err != PICL_SUCCESS)
12861708Sstevel 		return (err);
12871708Sstevel 
12881708Sstevel 	/*
12891708Sstevel 	 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
12901708Sstevel 	 */
12911708Sstevel 	err = ptree_get_propval_by_name(*nodep, PICL_PROP_NAME, parent_name,
12921708Sstevel 	    sizeof (parent_name));
12931708Sstevel 	if (err != PICL_SUCCESS)
12941708Sstevel 		return (err);
12951708Sstevel 	if (strcmp(labelp, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0)
12961708Sstevel 		err = add_led_nodes(intermediate, "FAN8",
12971708Sstevel 		    LOM_LED_POSITION_LOCATION, tblhdl);
12981708Sstevel 	else if (strcmp(labelp, "FAN1") == 0 && strcmp(parent_name, "IB6") == 0)
12991708Sstevel 		err = add_led_nodes(intermediate, "FAN9",
13001708Sstevel 		    LOM_LED_POSITION_LOCATION, tblhdl);
13011708Sstevel 	else
13021708Sstevel 		err = add_led_nodes(intermediate, labelp,
13031708Sstevel 		    LOM_LED_POSITION_LOCATION, tblhdl);
13041708Sstevel 	if (err != PICL_SUCCESS)
13051708Sstevel 		return (err);
13061708Sstevel 
13071708Sstevel 	if (slot_name) {
13081708Sstevel 		err = add_prop_charstring(intermediate, slot_name,
13091708Sstevel 		    PICL_PROP_SLOT_TYPE);
13101708Sstevel 		if (err != PICL_SUCCESS)
13111708Sstevel 			return (err);
13121708Sstevel 	}
13131708Sstevel 	*nodep = intermediate;
13141708Sstevel 	return (PICL_SUCCESS);
13151708Sstevel }
13161708Sstevel 
13171708Sstevel /*
13181708Sstevel  * adds an intermediate location/fru pair into frutree
13191708Sstevel  */
13201708Sstevel static int
add_intermediate_nodes(picl_nodehdl_t * nodep,char * labelp,picl_prophdl_t * tblhdlp,char * slot_name,char * fru_name)13211708Sstevel add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
13221708Sstevel     picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name)
13231708Sstevel {
13241708Sstevel 	int err;
13251708Sstevel 	picl_nodehdl_t intermediate;
13261708Sstevel 	picl_nodehdl_t intermediate2;
13271708Sstevel 
13281708Sstevel 	/*
13291708Sstevel 	 * create intermediate location node (unless it has already been
13301708Sstevel 	 * created)
13311708Sstevel 	 */
13321708Sstevel 	intermediate = find_child_by_name(*nodep, labelp);
13331708Sstevel 	if (intermediate == NULL) {
13341708Sstevel 		intermediate = *nodep;
13351708Sstevel 		err = add_intermediate_location(&intermediate, labelp,
13361708Sstevel 		    slot_name);
13371708Sstevel 		if (err != PICL_SUCCESS) {
13381708Sstevel 			return (err);
13391708Sstevel 		}
13401708Sstevel 	}
13411708Sstevel 
13421708Sstevel 	/*
13431708Sstevel 	 * create intermediate fru node (unless it has already been
13441708Sstevel 	 * created)
13451708Sstevel 	 */
13461708Sstevel 	intermediate2 = find_child_by_name(intermediate, labelp);
13471708Sstevel 	if (intermediate2 == NULL) {
13481708Sstevel 		/*
13491708Sstevel 		 * need to create intermediate fru node node
13501708Sstevel 		 */
13511708Sstevel 		err = ptree_create_and_add_node(intermediate, labelp,
13521708Sstevel 		    PICL_CLASS_FRU, &intermediate2);
13531708Sstevel 		if (err != PICL_SUCCESS) {
13541708Sstevel 			syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
13551708Sstevel 			return (err);
13561708Sstevel 		}
13571708Sstevel 
13581708Sstevel 		/*
13591708Sstevel 		 * Create empty Devices table
13601708Sstevel 		 */
13611708Sstevel 		err = create_table(intermediate2, tblhdlp, PICL_PROP_DEVICES);
13621708Sstevel 		if (err != PICL_SUCCESS)
13631708Sstevel 			return (err);
13641708Sstevel 
13651708Sstevel 		if (fru_name) {
13661708Sstevel 			err = add_prop_charstring(intermediate2, fru_name,
13671708Sstevel 			    PICL_PROP_FRU_TYPE);
13681708Sstevel 			if (err != PICL_SUCCESS)
13691708Sstevel 				return (err);
13701708Sstevel 		}
13711708Sstevel 	} else  {
13721708Sstevel 		err = ptree_get_propval_by_name(intermediate2,
13731708Sstevel 		    PICL_PROP_DEVICES, tblhdlp, sizeof (*tblhdlp));
13741708Sstevel 		if (err != PICL_SUCCESS)
13751708Sstevel 			return (err);
13761708Sstevel 	}
13771708Sstevel 	*nodep = intermediate2;
13781708Sstevel 	return (PICL_SUCCESS);
13791708Sstevel }
13801708Sstevel 
13811708Sstevel /*
13821708Sstevel  * need to remove _fru_parent property and Environment table (for cpu)
13831708Sstevel  */
13841708Sstevel static int
remove_references(picl_prophdl_t refprop,char * class)13851708Sstevel remove_references(picl_prophdl_t refprop, char *class)
13861708Sstevel {
13871708Sstevel 	picl_prophdl_t  platprop;
13881708Sstevel 	int err;
13891708Sstevel 
13901708Sstevel 	err = ptree_get_prop_by_name(refprop, PICL_REFPROP_FRU_PARENT,
13911708Sstevel 	    &platprop);
13921708Sstevel 	if (err != PICL_SUCCESS) {
13931708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
13941708Sstevel 		return (err);
13951708Sstevel 	}
13961708Sstevel 	err = ptree_delete_prop(platprop);
13971708Sstevel 	if (err != PICL_SUCCESS) {
13981708Sstevel 		syslog(LOG_ERR, DELETE_PROP_FAIL, err);
13991708Sstevel 		return (err);
14001708Sstevel 	}
14011708Sstevel 	(void) ptree_destroy_prop(platprop);
14021708Sstevel 	if (strcmp(class, PICL_CLASS_CPU) == 0) {
14031708Sstevel 		err = ptree_get_prop_by_name(refprop, PICL_PROP_ENV, &platprop);
14041708Sstevel 		if (err != PICL_SUCCESS) {
14051708Sstevel 			/*
14061708Sstevel 			 * multi-core cpu is setup with only one cpu having
14071708Sstevel 			 * env table so ignore PICL_PROPNOTFOUND error.
14081708Sstevel 			 */
14091708Sstevel 			if (err == PICL_PROPNOTFOUND) {
14101708Sstevel 				return (PICL_SUCCESS);
14111708Sstevel 			}
14121708Sstevel 			syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_ENV, err);
14131708Sstevel 			return (err);
14141708Sstevel 		}
14151708Sstevel 		err = ptree_delete_prop(platprop);
14161708Sstevel 		if (err != PICL_SUCCESS) {
14171708Sstevel 			syslog(LOG_ERR, DELETE_PROP_FAIL, err);
14181708Sstevel 			return (err);
14191708Sstevel 		}
14201708Sstevel 		(void) ptree_destroy_prop(platprop);
14211708Sstevel 	}
14221708Sstevel 	return (PICL_SUCCESS);
14231708Sstevel }
14241708Sstevel 
14251708Sstevel /*
14261708Sstevel  * subroutine for various functions. Finds immediate child of parh with
14271708Sstevel  * requested name if present. Otherwise returns NULL.
14281708Sstevel  */
14291708Sstevel static picl_nodehdl_t
find_child_by_name(picl_nodehdl_t parh,char * name)14301708Sstevel find_child_by_name(picl_nodehdl_t parh, char *name)
14311708Sstevel {
14321708Sstevel 	picl_nodehdl_t nodeh;
14331708Sstevel 	int err;
14341708Sstevel 	char	nodename[PICL_PROPNAMELEN_MAX];
14351708Sstevel 
14361708Sstevel 	err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD,
14371708Sstevel 	    &nodeh, sizeof (picl_nodehdl_t));
14381708Sstevel 	if (err != PICL_SUCCESS)
14391708Sstevel 		return (NULL);
14401708Sstevel 	for (;;) {
14411708Sstevel 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename,
14421708Sstevel 		    sizeof (nodename));
14431708Sstevel 		if (err != PICL_SUCCESS)
14441708Sstevel 			return (NULL);
14451708Sstevel 		if (strcmp(name, nodename) == 0) {
14461708Sstevel 			return (nodeh);
14471708Sstevel 		}
14481708Sstevel 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
14491708Sstevel 		    &nodeh, sizeof (picl_nodehdl_t));
14501708Sstevel 		if (err != PICL_SUCCESS)
14511708Sstevel 			return (NULL);
14521708Sstevel 	}
14531708Sstevel }
14541708Sstevel 
14551708Sstevel static int
create_dimm_references(picl_nodehdl_t parh,int dimm_id,picl_nodehdl_t nodeh,picl_prophdl_t tblhdl)14561708Sstevel create_dimm_references(picl_nodehdl_t parh, int dimm_id,
14571708Sstevel     picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
14581708Sstevel {
14591708Sstevel 	int err;
14601708Sstevel 	picl_nodehdl_t memctlhdl = NULL;
14611708Sstevel 	picl_nodehdl_t memgrphdl;
14621708Sstevel 	picl_nodehdl_t memhdl;
14631708Sstevel 	char name[MAXPATHLEN];
14641708Sstevel 	char	sbname[PICL_PROPNAMELEN_MAX];
14651708Sstevel 	char	pname[PICL_PROPNAMELEN_MAX];
14661708Sstevel 	char	bname[PICL_PROPNAMELEN_MAX];
14671708Sstevel 	picl_nodehdl_t parentfruh;
14681708Sstevel 	picl_nodehdl_t parentloch;
14691708Sstevel 	int id;
14701708Sstevel 
14711708Sstevel 	/*
14721708Sstevel 	 * create reference properties for memory nodes
14731708Sstevel 	 * - first find names of ancestor frus - ie "SBx/Py/Bz"
14741708Sstevel 	 */
14751708Sstevel 	err = ptree_get_propval_by_name(parh, PICL_PROP_PARENT, &parentfruh,
14761708Sstevel 	    sizeof (picl_nodehdl_t));
14771708Sstevel 	if (err != PICL_SUCCESS) {
14781708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
14791708Sstevel 		return (err);
14801708Sstevel 	}
14811708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME,
14821708Sstevel 	    bname, sizeof (bname));
14831708Sstevel 	if (err != PICL_SUCCESS) {
14841708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
14851708Sstevel 		return (err);
14861708Sstevel 	}
14871708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT,
14881708Sstevel 	    &parentloch, sizeof (picl_nodehdl_t));
14891708Sstevel 	if (err != PICL_SUCCESS) {
14901708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
14911708Sstevel 		return (err);
14921708Sstevel 	}
14931708Sstevel 	err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
14941708Sstevel 	    &parentfruh, sizeof (picl_nodehdl_t));
14951708Sstevel 	if (err != PICL_SUCCESS) {
14961708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
14971708Sstevel 		return (err);
14981708Sstevel 	}
14991708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME,
15001708Sstevel 	    pname, sizeof (pname));
15011708Sstevel 	if (err != PICL_SUCCESS) {
15021708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
15031708Sstevel 		return (err);
15041708Sstevel 	}
15051708Sstevel 
15061708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT,
15071708Sstevel 	    &parentloch, sizeof (picl_nodehdl_t));
15081708Sstevel 	if (err != PICL_SUCCESS) {
15091708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
15101708Sstevel 		return (err);
15111708Sstevel 	}
15121708Sstevel 	err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
15131708Sstevel 	    &parentfruh, sizeof (picl_nodehdl_t));
15141708Sstevel 	if (err != PICL_SUCCESS) {
15151708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
15161708Sstevel 		return (err);
15171708Sstevel 	}
15181708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname,
15191708Sstevel 	    sizeof (sbname));
15201708Sstevel 	if (err != PICL_SUCCESS) {
15211708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
15221708Sstevel 		return (err);
15231708Sstevel 	}
15241708Sstevel 
15251708Sstevel 	/*
15261708Sstevel 	 * ok - we've now got name of system board node in sbname and
15271708Sstevel 	 * name of processor node in pname.
15281708Sstevel 	 * Now find corresponding memory-controller node if present
15291708Sstevel 	 */
15301708Sstevel 	sprintf_buf2(name, MEMORY_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
15311708Sstevel 	err = ptree_get_node_by_path(name, &memctlhdl);
15321708Sstevel 	if (err != PICL_SUCCESS)
15331708Sstevel 		return (PICL_SUCCESS);
15341708Sstevel 
15351708Sstevel 	/*
15361708Sstevel 	 * now find corresponding memory-module-group node if present
15371708Sstevel 	 */
15381708Sstevel 	err = ptree_get_propval_by_name(memctlhdl, PICL_PROP_CHILD, &memgrphdl,
15391708Sstevel 	    sizeof (picl_nodehdl_t));
15401708Sstevel 	if (err != PICL_SUCCESS)
15411708Sstevel 		return (PICL_SUCCESS);
15421708Sstevel 
15431708Sstevel 	/*
15441708Sstevel 	 * check if this is the right bank - if not move on to sibling
15451708Sstevel 	 */
15461708Sstevel 	err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID,
15471708Sstevel 	    &id, sizeof (int));
15481708Sstevel 	if (err != PICL_SUCCESS)
15491708Sstevel 		return (PICL_SUCCESS);
15501708Sstevel 	if (bname[1] != id + '0') {
15511708Sstevel 		err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_PEER,
15521708Sstevel 		    &memgrphdl, sizeof (picl_nodehdl_t));
15531708Sstevel 		if (err != PICL_SUCCESS)
15541708Sstevel 			return (PICL_SUCCESS);
15551708Sstevel 		err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID,
15561708Sstevel 		    &id, sizeof (int));
15571708Sstevel 		if (err != PICL_SUCCESS)
15581708Sstevel 			return (PICL_SUCCESS);
15591708Sstevel 		if (bname[1] != id + '0')
15601708Sstevel 			return (PICL_SUCCESS);
15611708Sstevel 	}
15621708Sstevel 
15631708Sstevel 	/*
15641708Sstevel 	 * now find corresponding memory-module node if present
15651708Sstevel 	 */
15661708Sstevel 	err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_CHILD, &memhdl,
15671708Sstevel 	    sizeof (picl_nodehdl_t));
15681708Sstevel 	if (err != PICL_SUCCESS)
15691708Sstevel 		return (PICL_SUCCESS);
15701708Sstevel 
15711708Sstevel 	/*
15721708Sstevel 	 * for each DIMM set up links with matching memory-module node
15731708Sstevel 	 */
15741708Sstevel 	for (;;) {
15751708Sstevel 		err = ptree_get_propval_by_name(memhdl, PICL_PROP_ID,
15761708Sstevel 		    &id, sizeof (int));
15771708Sstevel 		if (err == PICL_SUCCESS && dimm_id == id) {
15781708Sstevel 			err = add_prop_ref(memhdl, nodeh,
15791708Sstevel 			    PICL_REFPROP_FRU_PARENT);
15801708Sstevel 			if (err != PICL_SUCCESS)
15811708Sstevel 				return (err);
15821708Sstevel 			err = create_table_entry(tblhdl, memhdl,
15831708Sstevel 			    PICL_CLASS_MEMORY_MODULE);
15841708Sstevel 			if (err != PICL_SUCCESS)
15851708Sstevel 				return (err);
15861708Sstevel 		}
15871708Sstevel 		err = ptree_get_propval_by_name(memhdl, PICL_PROP_PEER,
15881708Sstevel 		    &memhdl, sizeof (picl_nodehdl_t));
15891708Sstevel 		if (err != PICL_SUCCESS)
15901708Sstevel 			break;
15911708Sstevel 	}
15921708Sstevel 	return (PICL_SUCCESS);
15931708Sstevel }
15941708Sstevel 
15951708Sstevel static int
create_cpu_references(char * pname,picl_nodehdl_t nodeh,picl_prophdl_t tblhdl)15961708Sstevel create_cpu_references(char *pname, picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
15971708Sstevel {
15981708Sstevel 	int err;
15991708Sstevel 	picl_nodehdl_t sensorhdl;
16001708Sstevel 	picl_nodehdl_t parentloch;
16011708Sstevel 	picl_nodehdl_t parentfruh;
16021708Sstevel 	picl_nodehdl_t cpuhdl;
16031708Sstevel 	picl_nodehdl_t cpuhdl1;
16041708Sstevel 	picl_prophdl_t envtblhdl;
16051708Sstevel 	picl_prophdl_t prophdl;
16061708Sstevel 	char name[MAXPATHLEN];
16071708Sstevel 	char	sbname[PICL_PROPNAMELEN_MAX];
16081708Sstevel 
16091708Sstevel 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
16101708Sstevel 	    &parentloch, sizeof (picl_nodehdl_t));
16111708Sstevel 	if (err != PICL_SUCCESS) {
16121708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
16131708Sstevel 		return (err);
16141708Sstevel 	}
16151708Sstevel 	err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
16161708Sstevel 	    &parentfruh, sizeof (picl_nodehdl_t));
16171708Sstevel 	if (err != PICL_SUCCESS) {
16181708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
16191708Sstevel 		return (err);
16201708Sstevel 	}
16211708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname,
16221708Sstevel 	    sizeof (sbname));
16231708Sstevel 	if (err != PICL_SUCCESS) {
16241708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
16251708Sstevel 		return (err);
16261708Sstevel 	}
16271708Sstevel 
16281708Sstevel 	/*
16291708Sstevel 	 * Find corresponding cpu node if present. Note, this code will
16301708Sstevel 	 * attempt to find a corresponding cpu node, by searching for devices
16311708Sstevel 	 * of the types  /platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0,
16321708Sstevel 	 * /platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0 or
16331708Sstevel 	 * /platform/ssm@0,0/cmp@%x,0/cpu@0 or 1. If we can not find
16341708Sstevel 	 * any such device, we return PICL_SUCCESS such that we
16351708Sstevel 	 * continue the construction of the remaining part of the
16361708Sstevel 	 * tree. We first check for UltraSPARC-III. If we do not
16371708Sstevel 	 * find such a device we check for UltraSPARC-III+. If
16381708Sstevel 	 * we are unsuccesful again we try one of the jaguar cores
16391708Sstevel 	 * /platform/ssm@0,0/cmp@%x,0/cpu@. If we do not find the
16401708Sstevel 	 * first one, there's no point in continuing and we just
16411708Sstevel 	 * return PICL_SUCCESS. Similarly if we find one core
16421708Sstevel 	 * but not the other, something must be wrong, so we
16431708Sstevel 	 * again just return PICL_SUCCESS without creating any
16441708Sstevel 	 * references.
16451708Sstevel 	 */
16461708Sstevel 	sprintf_buf2(name, CPU_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
16471708Sstevel 
16481708Sstevel 	err = ptree_get_node_by_path(name, &cpuhdl);
16491708Sstevel 
16501708Sstevel 	if (err != PICL_SUCCESS) {
16511708Sstevel 		sprintf_buf2(name, CPU_DEV2,
16521708Sstevel 		    SB_P_TO_SAFARI_ADDR(sbname, pname));
16531708Sstevel 		err = ptree_get_node_by_path(name, &cpuhdl);
16541708Sstevel 		if (err != PICL_SUCCESS) {
16551708Sstevel 			/* check for jaguar cores */
16561708Sstevel 			sprintf_buf2(name, CPU_DEV3C1,
16571708Sstevel 			    SB_P_TO_SAFARI_ADDR(sbname, pname));
16581708Sstevel 			err = ptree_get_node_by_path(name, &cpuhdl1);
16591708Sstevel 			if (err != PICL_SUCCESS)
16601708Sstevel 				return (PICL_SUCCESS);
16611708Sstevel 			/* add fru parent reference for the second core */
16621708Sstevel 			err = ptree_get_prop_by_name(cpuhdl1,
16631708Sstevel 			    PICL_REFPROP_FRU_PARENT, &prophdl);
16641708Sstevel 			if (err != PICL_SUCCESS) {
16651708Sstevel 			    err = add_prop_ref(cpuhdl1, nodeh,
16661708Sstevel 				PICL_REFPROP_FRU_PARENT);
16671708Sstevel 			if (err != PICL_SUCCESS)
16681708Sstevel 				return (err);
16691708Sstevel 			err = create_table_entry(tblhdl, cpuhdl1,
16701708Sstevel 			    PICL_CLASS_CPU);
16711708Sstevel 			if (err != PICL_SUCCESS)
16721708Sstevel 				return (err);
16731708Sstevel 			}
16741708Sstevel 			sprintf_buf2(name, CPU_DEV3C0,
16751708Sstevel 			    SB_P_TO_SAFARI_ADDR(sbname, pname));
16761708Sstevel 			err = ptree_get_node_by_path(name, &cpuhdl);
16771708Sstevel 			if (err != PICL_SUCCESS)
16781708Sstevel 				return (PICL_SUCCESS);
16791708Sstevel 
16801708Sstevel 		}
16811708Sstevel 	}
16821708Sstevel 
16831708Sstevel 	/*
16841708Sstevel 	 * now create reference properties
16851708Sstevel 	 */
16861708Sstevel 	err = ptree_get_prop_by_name(cpuhdl, PICL_REFPROP_FRU_PARENT, &prophdl);
16871708Sstevel 	if (err != PICL_SUCCESS) {
16881708Sstevel 		err = add_prop_ref(cpuhdl, nodeh, PICL_REFPROP_FRU_PARENT);
16891708Sstevel 		if (err != PICL_SUCCESS)
16901708Sstevel 			return (err);
16911708Sstevel 		err = create_table_entry(tblhdl, cpuhdl, PICL_CLASS_CPU);
16921708Sstevel 		if (err != PICL_SUCCESS)
16931708Sstevel 			return (err);
16941708Sstevel 	}
16951708Sstevel 
16961708Sstevel 	/*
16971708Sstevel 	 * create Environment table on cpu node - with Die and Ambient
16981708Sstevel 	 * temperature sensors if present. If already there, delete and start
16991708Sstevel 	 * again
17001708Sstevel 	 */
17011708Sstevel 	err = ptree_get_prop_by_name(cpuhdl, PICL_PROP_ENV, &prophdl);
17021708Sstevel 	if (err == PICL_SUCCESS) {
17031708Sstevel 		err = ptree_delete_prop(prophdl);
17041708Sstevel 		if (err != PICL_SUCCESS)
17051708Sstevel 			return (err);
17061708Sstevel 		(void) ptree_destroy_prop(prophdl);
17071708Sstevel 	}
17081708Sstevel 	err = create_table(cpuhdl, &envtblhdl, PICL_PROP_ENV);
17091708Sstevel 	if (err != PICL_SUCCESS)
17101708Sstevel 		return (err);
17111708Sstevel 
17121708Sstevel 	if (pcix_io)
17131708Sstevel 		sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV_PCIX, sbname,
17141708Sstevel 		    (pname[1] - '0'));
17151708Sstevel 	else
17161708Sstevel 		sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV, sbname,
17171708Sstevel 		    (pname[1] - '0'));
17181708Sstevel 
17191708Sstevel 	err = ptree_get_node_by_path(name, &sensorhdl);
17201708Sstevel 	if (err == PICL_SUCCESS) {
17211708Sstevel 		err = create_table_entry(envtblhdl, sensorhdl,
17221708Sstevel 		    PICL_CLASS_TEMPERATURE_SENSOR);
17231708Sstevel 		if (err != PICL_SUCCESS)
17241708Sstevel 			return (err);
17251708Sstevel 	}
17261708Sstevel 
17271708Sstevel 	if (pcix_io)
17281708Sstevel 		sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV_PCIX, sbname,
17291708Sstevel 		    (pname[1] - '0'));
17301708Sstevel 	else
17311708Sstevel 		sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV, sbname,
17321708Sstevel 		    (pname[1] - '0'));
17331708Sstevel 
17341708Sstevel 	err = ptree_get_node_by_path(name, &sensorhdl);
17351708Sstevel 	if (err == PICL_SUCCESS) {
17361708Sstevel 		return (create_table_entry(envtblhdl, sensorhdl,
17371708Sstevel 		    PICL_CLASS_TEMPERATURE_SENSOR));
17381708Sstevel 	}
17391708Sstevel 	return (PICL_SUCCESS);
17401708Sstevel }
17411708Sstevel 
17421708Sstevel /*
17431708Sstevel  * subroutine of add_subtree - get a list of children of a parent node
17441708Sstevel  */
17451708Sstevel static sgfrunode_t *
get_node_children(fru_hdl_t fruparent,int * num_childrenp)17461708Sstevel get_node_children(fru_hdl_t fruparent, int *num_childrenp)
17471708Sstevel {
17481708Sstevel 	int	max_children, i;
17491708Sstevel 	sgfrunode_t	*fruchildren = NULL;
17501708Sstevel 	child_info_t child_info;
17511708Sstevel 	int  frufd;
17521708Sstevel 
17531708Sstevel 	/*
17541708Sstevel 	 * Open the sgfru pseudo dev
17551708Sstevel 	 */
17561708Sstevel 	if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, 0)) == -1) {
17571708Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, FRU_PSEUDO_DEV, strerror(errno));
17581708Sstevel 		return (NULL);
17591708Sstevel 	}
17601708Sstevel 	for (i = 1; i <= MAX_TRIES; i++) {
17611708Sstevel 		max_children = i * MAX_NODE_CHILDREN;
17621708Sstevel 		if ((fruchildren = calloc(max_children,
17631708Sstevel 		    sizeof (sgfrunode_t))) == NULL) {
17641708Sstevel 			(void) close(frufd);
17651708Sstevel 			syslog(LOG_ERR, MALLOC_FAIL);
17661708Sstevel 			return (NULL);
17671708Sstevel 		}
17681708Sstevel 		child_info.fru_hdl = fruparent;
17691708Sstevel 		child_info.fru_cnt = max_children;
17701708Sstevel 		child_info.frus = (void *)fruchildren;
17711708Sstevel 		if (ioctl(frufd, SGFRU_GETCHILDLIST, &child_info) == 0) {
17721708Sstevel 			/*
17731708Sstevel 			 * got them - return success
17741708Sstevel 			 */
17751708Sstevel 			(void) close(frufd);
17761708Sstevel 			*num_childrenp = child_info.fru_cnt;
17771708Sstevel 			return (fruchildren);
17781708Sstevel 		}
17791708Sstevel 		free(fruchildren);
17801708Sstevel 
17811708Sstevel 		/*
17821708Sstevel 		 * if ENOMEM, need to calloc more space - so go round loop again
17831708Sstevel 		 * otherwise fail
17841708Sstevel 		 */
17851708Sstevel 		if (errno != ENOMEM) {
17861708Sstevel 			(void) close(frufd);
17871708Sstevel 			syslog(LOG_ERR, SGFRU_IOCTL_FAIL, SGFRU_GETCHILDLIST,
17881708Sstevel 			    fruparent, strerror(errno));
17891708Sstevel 			return (NULL);
17901708Sstevel 		}
17911708Sstevel 	}
17921708Sstevel 	(void) close(frufd);
17931708Sstevel 	syslog(LOG_ERR, MALLOC_FAIL);
17941708Sstevel 	return (NULL);
17951708Sstevel }
17961708Sstevel 
17971708Sstevel /* Creates an unsigned longlong property for a given PICL node */
17981708Sstevel static int
add_prop_ull(picl_nodehdl_t nodeh,uint64_t handle,char * name)17991708Sstevel add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name)
18001708Sstevel {
18011708Sstevel 	picl_prophdl_t proph;
18021708Sstevel 	ptree_propinfo_t propinfo;
18031708Sstevel 	int err;
18041708Sstevel 
18051708Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
18061708Sstevel 	    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (unsigned long long),
18071708Sstevel 	    PICL_PROP_SC_HANDLE, NULL, NULL);
18081708Sstevel 	if (err != PICL_SUCCESS) {
18091708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
18101708Sstevel 		return (err);
18111708Sstevel 	}
18121708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &handle, &proph);
18131708Sstevel 	if (err != PICL_SUCCESS) {
18141708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
18151708Sstevel 		return (err);
18161708Sstevel 	}
18171708Sstevel 	return (PICL_SUCCESS);
18181708Sstevel }
18191708Sstevel 
18201708Sstevel /* Creates a void property for a given PICL node */
18211708Sstevel static int
add_prop_void(picl_nodehdl_t nodeh,char * name)18221708Sstevel add_prop_void(picl_nodehdl_t nodeh, char *name)
18231708Sstevel {
18241708Sstevel 	picl_prophdl_t proph;
18251708Sstevel 	ptree_propinfo_t propinfo;
18261708Sstevel 	int err;
18271708Sstevel 
18281708Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
18291708Sstevel 	    PICL_PTYPE_VOID, PICL_READ, 0, PICL_PROP_FRUDATA_AVAIL, NULL, NULL);
18301708Sstevel 	if (err != PICL_SUCCESS) {
18311708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
18321708Sstevel 		return (err);
18331708Sstevel 	}
18341708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
18351708Sstevel 	if (err != PICL_SUCCESS) {
18361708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
18371708Sstevel 		return (err);
18381708Sstevel 	}
18391708Sstevel 	return (PICL_SUCCESS);
18401708Sstevel }
18411708Sstevel 
18421708Sstevel /* Creates a reference property for a given PICL node */
18431708Sstevel static int
add_prop_ref(picl_nodehdl_t nodeh,picl_nodehdl_t value,char * name)18441708Sstevel add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name)
18451708Sstevel {
18461708Sstevel 	picl_prophdl_t proph;
18471708Sstevel 	ptree_propinfo_t propinfo;
18481708Sstevel 	int err;
18491708Sstevel 
18501708Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
18511708Sstevel 	    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name,
18521708Sstevel 	    NULL, NULL);
18531708Sstevel 	if (err != PICL_SUCCESS) {
18541708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
18551708Sstevel 		return (err);
18561708Sstevel 	}
18571708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
18581708Sstevel 	if (err != PICL_SUCCESS) {
18591708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
18601708Sstevel 		return (err);
18611708Sstevel 	}
18621708Sstevel 	return (PICL_SUCCESS);
18631708Sstevel }
18641708Sstevel 
18651708Sstevel /* Creates an integer property for a given PICL node */
18661708Sstevel static int
add_prop_int(picl_nodehdl_t nodeh,int value,char * name)18671708Sstevel add_prop_int(picl_nodehdl_t nodeh, int value, char *name)
18681708Sstevel {
18691708Sstevel 	picl_prophdl_t proph;
18701708Sstevel 	ptree_propinfo_t propinfo;
18711708Sstevel 	int err;
18721708Sstevel 
18731708Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
18741708Sstevel 	    PICL_PTYPE_INT, PICL_READ, sizeof (int), name, NULL, NULL);
18751708Sstevel 	if (err != PICL_SUCCESS) {
18761708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
18771708Sstevel 		return (err);
18781708Sstevel 	}
18791708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
18801708Sstevel 	if (err != PICL_SUCCESS) {
18811708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
18821708Sstevel 		return (err);
18831708Sstevel 	}
18841708Sstevel 	return (PICL_SUCCESS);
18851708Sstevel }
18861708Sstevel 
18871708Sstevel /* Creates an integer property for a given PICL node */
18881708Sstevel static int
add_prop_float(picl_nodehdl_t nodeh,float value,char * name)18891708Sstevel add_prop_float(picl_nodehdl_t nodeh, float value, char *name)
18901708Sstevel {
18911708Sstevel 	picl_prophdl_t proph;
18921708Sstevel 	ptree_propinfo_t propinfo;
18931708Sstevel 	int err;
18941708Sstevel 
18951708Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
18961708Sstevel 	    PICL_PTYPE_FLOAT, PICL_READ, sizeof (float), name, NULL, NULL);
18971708Sstevel 	if (err != PICL_SUCCESS) {
18981708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
18991708Sstevel 		return (err);
19001708Sstevel 	}
19011708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
19021708Sstevel 	if (err != PICL_SUCCESS) {
19031708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
19041708Sstevel 		return (err);
19051708Sstevel 	}
19061708Sstevel 	return (PICL_SUCCESS);
19071708Sstevel }
19081708Sstevel 
19091708Sstevel /* Creates a charstring property for a given PICL node */
19101708Sstevel static int
add_prop_charstring(picl_nodehdl_t nodeh,char * value,char * name)19111708Sstevel add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name)
19121708Sstevel {
19131708Sstevel 	picl_prophdl_t proph;
19141708Sstevel 	ptree_propinfo_t propinfo;
19151708Sstevel 	int err;
19161708Sstevel 
19171708Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
19181708Sstevel 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(value) + 1,
19191708Sstevel 	    name, NULL, NULL);
19201708Sstevel 	if (err != PICL_SUCCESS) {
19211708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
19221708Sstevel 		return (err);
19231708Sstevel 	}
19241708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, value, &proph);
19251708Sstevel 	if (err != PICL_SUCCESS) {
19261708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
19271708Sstevel 		return (err);
19281708Sstevel 	}
19291708Sstevel 	return (PICL_SUCCESS);
19301708Sstevel }
19311708Sstevel 
19321708Sstevel /* create an entry in the specified table */
19331708Sstevel static int
create_table_entry(picl_prophdl_t tblhdl,picl_nodehdl_t refhdl,char * class)19341708Sstevel create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
19351708Sstevel {
19361708Sstevel 	int			err;
19371708Sstevel 	ptree_propinfo_t	prop;
19381708Sstevel 	picl_prophdl_t		prophdl[2];
19391708Sstevel 
19401708Sstevel 	/* first column is class */
19411708Sstevel 	prop.version = PTREE_PROPINFO_VERSION;
19421708Sstevel 	prop.piclinfo.type =  PICL_PTYPE_CHARSTRING;
19431708Sstevel 	prop.piclinfo.accessmode = PICL_READ;
19441708Sstevel 	prop.piclinfo.size = PICL_CLASSNAMELEN_MAX;
19451708Sstevel 	prop.read = NULL;
19461708Sstevel 	prop.write = NULL;
19471708Sstevel 	(void) strlcpy(prop.piclinfo.name, PICL_PROP_CLASS,
19481708Sstevel 	    sizeof (prop.piclinfo.name));
19491708Sstevel 	err = ptree_create_prop(&prop, class, &prophdl[0]);
19501708Sstevel 	if (err != PICL_SUCCESS) {
19511708Sstevel 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
19521708Sstevel 		return (err);
19531708Sstevel 	}
19541708Sstevel 
19551708Sstevel 	/* second column is refernce property */
19561708Sstevel 	prop.version = PTREE_PROPINFO_VERSION;
19571708Sstevel 	prop.piclinfo.type =  PICL_PTYPE_REFERENCE;
19581708Sstevel 	prop.piclinfo.accessmode = PICL_READ;
19591708Sstevel 	prop.piclinfo.size = sizeof (picl_nodehdl_t);
19601708Sstevel 	prop.read = NULL;
19611708Sstevel 	prop.write = NULL;
19621708Sstevel 	sprintf_buf2(prop.piclinfo.name, "_%s_", class);
19631708Sstevel 	err = ptree_create_prop(&prop, &refhdl, &prophdl[1]);
19641708Sstevel 	if (err != PICL_SUCCESS) {
19651708Sstevel 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
19661708Sstevel 		return (err);
19671708Sstevel 	}
19681708Sstevel 
19691708Sstevel 	/* add row to table */
19701708Sstevel 	err = ptree_add_row_to_table(tblhdl, 2, prophdl);
19711708Sstevel 	if (err != PICL_SUCCESS)
19721708Sstevel 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
19731708Sstevel 	return (err);
19741708Sstevel }
19751708Sstevel 
19761708Sstevel /* create an empty table property */
19771708Sstevel static int
create_table(picl_nodehdl_t fruhdl,picl_prophdl_t * tblhdlp,char * tbl_name)19781708Sstevel create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
19791708Sstevel {
19801708Sstevel 	int			err;
19811708Sstevel 	ptree_propinfo_t	prop;
19821708Sstevel 	picl_prophdl_t		tblprophdl;
19831708Sstevel 
19841708Sstevel 	err = ptree_create_table(tblhdlp);
19851708Sstevel 	if (err != PICL_SUCCESS) {
19861708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
19871708Sstevel 		return (err);
19881708Sstevel 	}
19891708Sstevel 	prop.version = PTREE_PROPINFO_VERSION;
19901708Sstevel 	prop.piclinfo.type =  PICL_PTYPE_TABLE;
19911708Sstevel 	prop.piclinfo.accessmode = PICL_READ;
19921708Sstevel 	prop.piclinfo.size = sizeof (picl_prophdl_t);
19931708Sstevel 	prop.read = NULL;
19941708Sstevel 	prop.write = NULL;
19951708Sstevel 	(void) strlcpy(prop.piclinfo.name, tbl_name,
19961708Sstevel 	    sizeof (prop.piclinfo.name));
19971708Sstevel 	err = ptree_create_and_add_prop(fruhdl, &prop, tblhdlp, &tblprophdl);
19981708Sstevel 	if (err != PICL_SUCCESS)
19991708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
20001708Sstevel 	return (err);
20011708Sstevel }
20021708Sstevel 
20031708Sstevel static void
frudr_add_subtree(picl_nodehdl_t parh)20041708Sstevel frudr_add_subtree(picl_nodehdl_t parh)
20051708Sstevel {
20061708Sstevel 	fru_hdl_t	sgfruhdl;
20071708Sstevel 	if (ptree_get_propval_by_name(parh, PICL_PROP_SC_HANDLE,
20081708Sstevel 	    &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
20091708Sstevel 		return;
20101708Sstevel 	}
20111708Sstevel 	(void) add_subtree(parh, sgfruhdl);
20121708Sstevel }
20131708Sstevel 
20141708Sstevel /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */
20151708Sstevel /*ARGSUSED*/
20161708Sstevel static void
frudr_completion_handler(char * ename,void * earg,size_t size)20171708Sstevel frudr_completion_handler(char *ename, void *earg, size_t size)
20181708Sstevel {
20191708Sstevel 	picl_nodehdl_t	fruh;
20201708Sstevel 	picl_nodehdl_t	parh;
20211708Sstevel 
20221708Sstevel 	if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
20231708Sstevel 		/*
20241708Sstevel 		 * now frudata has been notified that the node is to be
20251708Sstevel 		 * removed, we can actually remove it
20261708Sstevel 		 */
20271708Sstevel 		fruh = NULL;
20281708Sstevel 		(void) nvlist_lookup_uint64(earg,
20291708Sstevel 		    PICLEVENTARG_FRUHANDLE, &fruh);
20301708Sstevel 		if (fruh != NULL) {
20311708Sstevel 			(void) remove_subtree(fruh);
20321708Sstevel 
20331708Sstevel 			/*
20341708Sstevel 			 * Now repopulate the frutree with current data.
20351708Sstevel 			 */
20361708Sstevel 			parh = NULL;
20371708Sstevel 			(void) nvlist_lookup_uint64(earg,
20381708Sstevel 			    PICLEVENTARG_PARENTHANDLE, &parh);
20391708Sstevel 			if (parh != NULL) {
20401708Sstevel 				frudr_add_subtree(parh);
20411708Sstevel 			}
20421708Sstevel 		}
20431708Sstevel 	}
20441708Sstevel 	nvlist_free(earg);
20451708Sstevel 	free(earg);
20461708Sstevel 	free(ename);
20471708Sstevel }
20481708Sstevel 
20491708Sstevel /*
20501708Sstevel  * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
20511708Sstevel  */
20521708Sstevel static void
post_frudr_event(char * ename,picl_nodehdl_t parenth,picl_nodehdl_t fruh)20531708Sstevel post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
20541708Sstevel {
20551708Sstevel 	nvlist_t	*nvl;
20561708Sstevel 	char		*ev_name;
20571708Sstevel 
20581708Sstevel 	ev_name = strdup(ename);
20591708Sstevel 	if (ev_name == NULL)
20601708Sstevel 		return;
20611708Sstevel 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, NULL)) {
20621708Sstevel 		free(ev_name);
20631708Sstevel 		return;
20641708Sstevel 	}
20651708Sstevel 	if (parenth != 0L &&
20661708Sstevel 	    nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
20671708Sstevel 		free(ev_name);
20681708Sstevel 		nvlist_free(nvl);
20691708Sstevel 		return;
20701708Sstevel 	}
20711708Sstevel 	if (fruh != 0L &&
20721708Sstevel 	    nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
20731708Sstevel 		free(ev_name);
20741708Sstevel 		nvlist_free(nvl);
20751708Sstevel 		return;
20761708Sstevel 	}
20771708Sstevel 	if (ptree_post_event(ev_name, nvl, sizeof (nvl),
20781708Sstevel 	    frudr_completion_handler) != 0) {
20791708Sstevel 		free(ev_name);
20801708Sstevel 		nvlist_free(nvl);
20811708Sstevel 	}
20821708Sstevel }
20831708Sstevel 
20841708Sstevel /*
2085*1797Sjfrank  * updates the picl node 'loc' with the new fru handle (PICL_PROP_SC_HANDLE)
2086*1797Sjfrank  * (helper function for frudr_evhandler, when a stale fru handle is
2087*1797Sjfrank  * detected)
2088*1797Sjfrank  */
2089*1797Sjfrank static void
update_fru_hdl(picl_nodehdl_t loc,fru_hdl_t newsgfruhdl)2090*1797Sjfrank update_fru_hdl(picl_nodehdl_t loc, fru_hdl_t newsgfruhdl)
2091*1797Sjfrank {
2092*1797Sjfrank 	picl_prophdl_t	schproph;
2093*1797Sjfrank 	int		err;
2094*1797Sjfrank 
2095*1797Sjfrank 	err = ptree_get_prop_by_name(loc, PICL_PROP_SC_HANDLE, &schproph);
2096*1797Sjfrank 	if (err == PICL_SUCCESS) {
2097*1797Sjfrank 		if (ptree_delete_prop(schproph) == PICL_SUCCESS) {
2098*1797Sjfrank 			(void) ptree_destroy_prop(schproph);
2099*1797Sjfrank 		}
2100*1797Sjfrank 	}
2101*1797Sjfrank 	(void) add_prop_ull(loc, (uint64_t)newsgfruhdl, PICL_PROP_SC_HANDLE);
2102*1797Sjfrank }
2103*1797Sjfrank 
2104*1797Sjfrank /*
2105*1797Sjfrank  * Get the fru handle of loc by iterating through the parent's children.
2106*1797Sjfrank  * Sets fruhdl and returns PICL_SUCCESS unless an error is encountered.
2107*1797Sjfrank  */
2108*1797Sjfrank static int
get_fruhdl_from_parent(picl_nodehdl_t loc,fru_hdl_t * fruhdl)2109*1797Sjfrank get_fruhdl_from_parent(picl_nodehdl_t loc, fru_hdl_t *fruhdl)
2110*1797Sjfrank {
2111*1797Sjfrank 	picl_nodehdl_t	parlocnodeh;
2112*1797Sjfrank 	fru_hdl_t	parsgfruhdl;
2113*1797Sjfrank 	sgfrunode_t	*cp;
2114*1797Sjfrank 	sgfrunode_t	*fruchildren;
2115*1797Sjfrank 	char		nodename[PICL_PROPNAMELEN_MAX];
2116*1797Sjfrank 	int		err;
2117*1797Sjfrank 	int		num_children;
2118*1797Sjfrank 	int		i;
2119*1797Sjfrank 
2120*1797Sjfrank 	err = ptree_get_propval_by_name(loc, PICL_PROP_NAME, (void *)nodename,
2121*1797Sjfrank 	    PICL_PROPNAMELEN_MAX);
2122*1797Sjfrank 	if (err != PICL_SUCCESS)
2123*1797Sjfrank 		return (err);
2124*1797Sjfrank 	err = ptree_get_propval_by_name(loc, PICL_PROP_PARENT, &parlocnodeh,
2125*1797Sjfrank 	    sizeof (picl_nodehdl_t));
2126*1797Sjfrank 	if (err != PICL_SUCCESS)
2127*1797Sjfrank 		return (err);
2128*1797Sjfrank 	if ((err = ptree_get_propval_by_name(parlocnodeh, PICL_PROP_SC_HANDLE,
2129*1797Sjfrank 	    &parsgfruhdl, sizeof (parsgfruhdl))) != PICL_SUCCESS)
2130*1797Sjfrank 		return (err);
2131*1797Sjfrank 	/* find children of the parent node */
2132*1797Sjfrank 	fruchildren = get_node_children(parsgfruhdl, &num_children);
2133*1797Sjfrank 	if (fruchildren == NULL)
2134*1797Sjfrank 		return (PICL_FAILURE);
2135*1797Sjfrank 	for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
2136*1797Sjfrank 		/* find the child we're interested in */
2137*1797Sjfrank 		if (strcmp(cp->nodename, nodename) == 0) {
2138*1797Sjfrank 			*fruhdl = cp->handle;
2139*1797Sjfrank 			free(fruchildren);
2140*1797Sjfrank 			return (PICL_SUCCESS);
2141*1797Sjfrank 		}
2142*1797Sjfrank 	}
2143*1797Sjfrank 	free(fruchildren);
2144*1797Sjfrank 	return (PICL_FAILURE);
2145*1797Sjfrank }
2146*1797Sjfrank 
2147*1797Sjfrank /*
21481708Sstevel  * handle EC_DR picl events
21491708Sstevel  */
21501708Sstevel /*ARGSUSED*/
21511708Sstevel static void
frudr_evhandler(const char * ename,const void * earg,size_t size,void * cookie)21521708Sstevel frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
21531708Sstevel {
21541708Sstevel 	nvlist_t		*nvlp;
21551708Sstevel 	char			*dtype;
21561708Sstevel 	char			*ap_id;
21571708Sstevel 	char			*hint;
21581708Sstevel 	char			path[MAXPATHLEN];
21591708Sstevel 	picl_nodehdl_t		fruh;
21601708Sstevel 	picl_nodehdl_t		locnodeh;
21611708Sstevel 	fru_hdl_t		sgfruhdl;
2162*1797Sjfrank 	fru_hdl_t		sgfruhdl_from_parent;
21631708Sstevel 
21641708Sstevel 	if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0)
21651708Sstevel 		return;
21661708Sstevel 
21671708Sstevel 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
21681708Sstevel 		return;
21691708Sstevel 
21701708Sstevel 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
21711708Sstevel 		nvlist_free(nvlp);
21721708Sstevel 		return;
21731708Sstevel 	}
21741708Sstevel 
21751708Sstevel 	if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
21761708Sstevel 		nvlist_free(nvlp);
21771708Sstevel 		return;
21781708Sstevel 	}
21791708Sstevel 
21801708Sstevel 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
21811708Sstevel 		nvlist_free(nvlp);
21821708Sstevel 		return;
21831708Sstevel 	}
21841708Sstevel 
21851708Sstevel 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
21861708Sstevel 		nvlist_free(nvlp);
21871708Sstevel 		return;
21881708Sstevel 	}
21891708Sstevel 
21901708Sstevel 	if (strncmp(ap_id, AP_ID_PREAMBLE, AP_ID_PREAMBLE_LEN) != 0) {
21911708Sstevel 		nvlist_free(nvlp);
21921708Sstevel 		return;
21931708Sstevel 	}
21941708Sstevel 
21951708Sstevel 	/*
21961708Sstevel 	 * OK - so this is an EC_DR event - let's handle it.
21971708Sstevel 	 */
21981708Sstevel 	sprintf_buf2(path, CHASSIS_LOC_PATH, &ap_id[AP_ID_PREAMBLE_LEN]);
21991708Sstevel 
22001708Sstevel 	/*
22011708Sstevel 	 * special case - SSC arrival means that SSC has been reset - we
22021708Sstevel 	 * need to flush the cached sgfru handles
22031708Sstevel 	 */
22041708Sstevel 	if (strcmp(&ap_id[AP_ID_PREAMBLE_LEN], "SSC1") == 0) {
22051708Sstevel 		picl_nodehdl_t chdh;
22061708Sstevel 		picl_nodehdl_t peerh;
22071708Sstevel 		picl_nodehdl_t parh;
22081708Sstevel 		int got_peer;
22091708Sstevel 		char	label[MAX_LABEL_LEN];
22101708Sstevel 		int err;
22111708Sstevel 		sgfrunode_t	*sgfruchassisp = NULL;
22121708Sstevel 		int num_children;
22131708Sstevel 		picl_prophdl_t	schproph;
22141708Sstevel 
22151708Sstevel 		/* find existing chassis node */
22161708Sstevel 		if (ptree_get_node_by_path(CHASSIS_PATH, &parh) !=
22171708Sstevel 		    PICL_SUCCESS) {
22181708Sstevel 			nvlist_free(nvlp);
22191708Sstevel 			return;
22201708Sstevel 		}
22211708Sstevel 
22221708Sstevel 		/* find new chassis sgfru node */
22231708Sstevel 		sgfruchassisp = get_node_children(ROOTPARENT, &num_children);
22241708Sstevel 		if (sgfruchassisp == NULL || num_children != 1) {
22251708Sstevel 			nvlist_free(nvlp);
22261708Sstevel 			return;
22271708Sstevel 		}
22281708Sstevel 
22291708Sstevel 		/* update chassis SC_HANDLE property */
22301708Sstevel 		err = ptree_get_prop_by_name(parh, PICL_PROP_SC_HANDLE,
22311708Sstevel 		    &schproph);
22321708Sstevel 		if (err != PICL_SUCCESS) {
22331708Sstevel 			nvlist_free(nvlp);
22341708Sstevel 			return;
22351708Sstevel 		}
22361708Sstevel 		err = ptree_delete_prop(schproph);
22371708Sstevel 		if (err != PICL_SUCCESS) {
22381708Sstevel 			nvlist_free(nvlp);
22391708Sstevel 			return;
22401708Sstevel 		}
22411708Sstevel 		(void) ptree_destroy_prop(schproph);
22421708Sstevel 		err = add_prop_ull(parh, sgfruchassisp->handle,
22431708Sstevel 		    PICL_PROP_SC_HANDLE);
22441708Sstevel 		if (err != PICL_SUCCESS) {
22451708Sstevel 			nvlist_free(nvlp);
22461708Sstevel 			return;
22471708Sstevel 		}
22481708Sstevel 
22491708Sstevel 		/*
22501708Sstevel 		 * remove all subtrees except DISK, TAPE, DVD and PCI subtrees
22511708Sstevel 		 */
22521708Sstevel 		if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh,
22531708Sstevel 		    sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
22541708Sstevel 			for (;;) {
22551708Sstevel 				if (ptree_get_propval_by_name(chdh,
22561708Sstevel 				    PICL_PROP_PEER, &peerh,
22571708Sstevel 				    sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
22581708Sstevel 					got_peer = 0;
22591708Sstevel 				else
22601708Sstevel 					got_peer = 1;
22611708Sstevel 				err = ptree_get_propval_by_name(chdh,
22621708Sstevel 				    PICL_PROP_LABEL, label, sizeof (label));
22631708Sstevel 				if (err == PICL_SUCCESS) {
22641708Sstevel 					if (strncmp(label, "DISK",
22651708Sstevel 					    strlen("DISK")) != 0 &&
22661708Sstevel 					    strncmp(label, "TAPE",
22671708Sstevel 					    strlen("TAPE")) != 0 &&
22681708Sstevel 					    strncmp(label, "PCI",
22691708Sstevel 					    strlen("PCI")) != 0 &&
22701708Sstevel 					    strncmp(label, "DVD",
22711708Sstevel 					    strlen("DVD")) != 0) {
22721708Sstevel 						(void) remove_subtree(chdh);
22731708Sstevel 					}
22741708Sstevel 				}
22751708Sstevel 				if (got_peer == 0)
22761708Sstevel 					break;
22771708Sstevel 				chdh = peerh;
22781708Sstevel 			}
22791708Sstevel 		}
22801708Sstevel 
22811708Sstevel 		/* add new subtrees */
22821708Sstevel 		(void) add_subtree(parh, sgfruchassisp->handle);
22831708Sstevel 		free(sgfruchassisp);
22841708Sstevel 
22851708Sstevel 		nvlist_free(nvlp);
22861708Sstevel 		return;
22871708Sstevel 	}
22881708Sstevel 
22891708Sstevel 	if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
22901708Sstevel 		nvlist_free(nvlp);
22911708Sstevel 		return;
22921708Sstevel 	}
22931708Sstevel 	if (ptree_get_propval_by_name(locnodeh, PICL_PROP_SC_HANDLE,
22941708Sstevel 	    &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
22951708Sstevel 		nvlist_free(nvlp);
22961708Sstevel 		return;
22971708Sstevel 	}
22981708Sstevel 
22991708Sstevel 	/*
23001708Sstevel 	 * now either add or delete the fru node as appropriate. If no
23011708Sstevel 	 * hint, treat as insert - add_subtree will update the tree if
23021708Sstevel 	 * necessary.
23031708Sstevel 	 */
23041708Sstevel 	if (strcmp(hint, DR_HINT_REMOVE) == 0) {
23051708Sstevel 		if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD,
23061708Sstevel 		    &fruh, sizeof (picl_nodehdl_t)) != PICL_PROPNOTFOUND) {
23071708Sstevel 			/*
23081708Sstevel 			 * fru was there - but has gone away
23091708Sstevel 			 */
23101708Sstevel 			post_frudr_event(PICL_FRU_REMOVED, locnodeh, fruh);
23111708Sstevel 		}
23121708Sstevel 	} else {
23131708Sstevel 		/*
23141708Sstevel 		 * fru has been inserted (or may need to update)
2315*1797Sjfrank 		 *
2316*1797Sjfrank 		 * sgfruhdl may be stale due to hotplugging. We check this
2317*1797Sjfrank 		 * by getting the fru_hdl_t from the parent's children
2318*1797Sjfrank 		 * and compare it to the cached value in sgfruhdl.  If we
2319*1797Sjfrank 		 * have a stale handle, we update the cached value and
2320*1797Sjfrank 		 * use it in the call to add_subtree.
23211708Sstevel 		 */
2322*1797Sjfrank 		if (get_fruhdl_from_parent(locnodeh, &sgfruhdl_from_parent) ==
2323*1797Sjfrank 		    PICL_SUCCESS) {
2324*1797Sjfrank 			if (sgfruhdl != sgfruhdl_from_parent) {
2325*1797Sjfrank 				update_fru_hdl(locnodeh, sgfruhdl_from_parent);
2326*1797Sjfrank 				sgfruhdl = sgfruhdl_from_parent;
2327*1797Sjfrank 			}
2328*1797Sjfrank 		}
2329*1797Sjfrank 
23301708Sstevel 		(void) add_subtree(locnodeh, sgfruhdl);
23311708Sstevel 	}
23321708Sstevel 	nvlist_free(nvlp);
23331708Sstevel }
23341708Sstevel 
23351708Sstevel /*
23361708Sstevel  * handle memcfg picl events - need to update reference properties
23371708Sstevel  */
23381708Sstevel /*ARGSUSED*/
23391708Sstevel static void
frumemcfg_evhandler(const char * ename,const void * earg,size_t size,void * cookie)23401708Sstevel frumemcfg_evhandler(const char *ename, const void *earg, size_t size,
23411708Sstevel     void *cookie)
23421708Sstevel {
23431708Sstevel 	picl_nodehdl_t	nodeh;
23441708Sstevel 	picl_nodehdl_t	lochdl;
23451708Sstevel 	picl_nodehdl_t	fruhdl;
23461708Sstevel 	picl_nodehdl_t	memgrphdl;
23471708Sstevel 	picl_nodehdl_t	memhdl;
23481708Sstevel 	picl_prophdl_t	tblhdl;
23491708Sstevel 	picl_prophdl_t	tblproph;
23501708Sstevel 	nvlist_t	*nvlp;
23511708Sstevel 	char	addr[MAXPATHLEN];
23521708Sstevel 	char	bname[PICL_PROPNAMELEN_MAX];
23531708Sstevel 	picl_nodehdl_t	banklochdl;
23541708Sstevel 	picl_nodehdl_t	bankfruhdl;
23551708Sstevel 	char	label[MAX_LABEL_LEN];
23561708Sstevel 	int err;
23571708Sstevel 	int id;
23581708Sstevel 	char *ptr;
23591708Sstevel 	int value;
23601708Sstevel 	char buf[MAX_LINE_SIZE];
23611708Sstevel 
23621708Sstevel 	if (strcmp(ename, PICLEVENT_MC_ADDED) != 0 &&
23631708Sstevel 	    strcmp(ename, PICLEVENT_MC_REMOVED) != 0)
23641708Sstevel 		return;
23651708Sstevel 
23661708Sstevel 	/*
23671708Sstevel 	 * find corresponding frutree dimm nodes
23681708Sstevel 	 */
23691708Sstevel 	if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
23701708Sstevel 		return;
23711708Sstevel 	if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh)) {
23721708Sstevel 		nvlist_free(nvlp);
23731708Sstevel 		return;
23741708Sstevel 	}
23751708Sstevel 	nvlist_free(nvlp);
23761708Sstevel 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, addr,
23771708Sstevel 	    sizeof (addr));
23781708Sstevel 	if (err != PICL_SUCCESS)
23791708Sstevel 		return;
23801708Sstevel 	ptr = strchr(addr, ',');
23811708Sstevel 	if (ptr == NULL)
23821708Sstevel 		return;
23831708Sstevel 	*ptr = '\0';
23841708Sstevel 	value = strtol(addr, NULL, 16);
23851708Sstevel 	sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value),
23861708Sstevel 	    SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value),
23871708Sstevel 	    SAFARI_ADDR_TO_P(value));
23881708Sstevel 	err = ptree_get_node_by_path(buf, &fruhdl);
23891708Sstevel 	if (err != PICL_SUCCESS)
23901708Sstevel 		return;
23911708Sstevel 	err = ptree_get_propval_by_name(fruhdl, PICL_PROP_CHILD,
23921708Sstevel 	    &banklochdl, sizeof (banklochdl));
23931708Sstevel 	if (err != PICL_SUCCESS)
23941708Sstevel 		return;
23951708Sstevel 
23961708Sstevel 	/*
23971708Sstevel 	 * walk through the DIMM locations
23981708Sstevel 	 */
23991708Sstevel 	for (;;) {
24001708Sstevel 		err = ptree_get_propval_by_name(banklochdl, PICL_PROP_CHILD,
24011708Sstevel 		    &bankfruhdl, sizeof (bankfruhdl));
24021708Sstevel 		if (err != PICL_SUCCESS)
24031708Sstevel 			goto next_bank;
24041708Sstevel 		err = ptree_get_propval_by_name(bankfruhdl, PICL_PROP_CHILD,
24051708Sstevel 		    &lochdl, sizeof (lochdl));
24061708Sstevel 		if (err != PICL_SUCCESS)
24071708Sstevel 			goto next_bank;
24081708Sstevel 		for (;;) {
24091708Sstevel 			err = ptree_get_propval_by_name(lochdl, PICL_PROP_CHILD,
24101708Sstevel 			    &fruhdl, sizeof (fruhdl));
24111708Sstevel 			if (err != PICL_SUCCESS)
24121708Sstevel 				goto next_dimm;
24131708Sstevel 
24141708Sstevel 			/*
24151708Sstevel 			 * this is a frutree dimm node corresponding to the
24161708Sstevel 			 * memory controller that has been added/deleted
24171708Sstevel 			 * - so create/delete reference properties
24181708Sstevel 			 */
24191708Sstevel 			if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
24201708Sstevel 				/*
24211708Sstevel 				 * find bank name
24221708Sstevel 				 */
24231708Sstevel 				err = ptree_get_propval_by_name(fruhdl,
24241708Sstevel 				    PICL_PROP_DEVICES, &tblhdl,
24251708Sstevel 				    sizeof (tblhdl));
24261708Sstevel 				if (err != PICL_SUCCESS)
24271708Sstevel 					goto next_dimm;
24281708Sstevel 				err = ptree_get_propval_by_name(lochdl,
24291708Sstevel 				    PICL_PROP_LABEL, label, sizeof (label));
24301708Sstevel 				if (err != PICL_SUCCESS)
24311708Sstevel 					goto next_dimm;
24321708Sstevel 
24331708Sstevel 				err = ptree_get_propval_by_name(bankfruhdl,
24341708Sstevel 				    PICL_PROP_NAME, bname, sizeof (bname));
24351708Sstevel 				if (err != PICL_SUCCESS)
24361708Sstevel 					goto next_dimm;
24371708Sstevel 
24381708Sstevel 				/*
24391708Sstevel 				 * find memory group node
24401708Sstevel 				 */
24411708Sstevel 				err = ptree_get_propval_by_name(nodeh,
24421708Sstevel 				    PICL_PROP_CHILD, &memgrphdl,
24431708Sstevel 				    sizeof (memgrphdl));
24441708Sstevel 				if (err != PICL_SUCCESS)
24451708Sstevel 					goto next_dimm;
24461708Sstevel 
24471708Sstevel 				/*
24481708Sstevel 				 * check if this is the right bank - if not
24491708Sstevel 				 * move on to sibling
24501708Sstevel 				 */
24511708Sstevel 				err = ptree_get_propval_by_name(memgrphdl,
24521708Sstevel 				    PICL_PROP_ID, &id, sizeof (id));
24531708Sstevel 				if (err != PICL_SUCCESS)
24541708Sstevel 					goto next_dimm;
24551708Sstevel 				if (bname[1] != id + '0') {
24561708Sstevel 					err =
24571708Sstevel 					    ptree_get_propval_by_name(memgrphdl,
24581708Sstevel 					    PICL_PROP_PEER, &memgrphdl,
24591708Sstevel 					    sizeof (memgrphdl));
24601708Sstevel 					if (err != PICL_SUCCESS)
24611708Sstevel 						goto next_dimm;
24621708Sstevel 					err =
24631708Sstevel 					    ptree_get_propval_by_name(memgrphdl,
24641708Sstevel 					    PICL_PROP_ID, &id, sizeof (id));
24651708Sstevel 					if (err != PICL_SUCCESS)
24661708Sstevel 						goto next_dimm;
24671708Sstevel 					if (bname[1] != id + '0')
24681708Sstevel 						goto next_dimm;
24691708Sstevel 				}
24701708Sstevel 
24711708Sstevel 				/*
24721708Sstevel 				 * got the right bank - now create appropriate
24731708Sstevel 				 * link
24741708Sstevel 				 */
24751708Sstevel 				err = ptree_get_propval_by_name(memgrphdl,
24761708Sstevel 				    PICL_PROP_CHILD, &memhdl,
24771708Sstevel 				    sizeof (memhdl));
24781708Sstevel 				if (err != PICL_SUCCESS)
24791708Sstevel 					goto next_dimm;
24801708Sstevel 				for (;;) {
24811708Sstevel 					err = ptree_get_propval_by_name(memhdl,
24821708Sstevel 					    PICL_PROP_ID, &id, sizeof (id));
24831708Sstevel 					if (err != PICL_SUCCESS)
24841708Sstevel 						goto next_dimm;
24851708Sstevel 					if (label[1] == ('0' + id)) {
24861708Sstevel 						err = add_prop_ref(memhdl,
24871708Sstevel 						    fruhdl,
24881708Sstevel 						    PICL_REFPROP_FRU_PARENT);
24891708Sstevel 						if (err != PICL_SUCCESS)
24901708Sstevel 							return;
24911708Sstevel 						err = create_table_entry(tblhdl,
24921708Sstevel 						    memhdl,
24931708Sstevel 						    PICL_CLASS_MEMORY_MODULE);
24941708Sstevel 						if (err != PICL_SUCCESS)
24951708Sstevel 							return;
24961708Sstevel 					}
24971708Sstevel 					err = ptree_get_propval_by_name(memhdl,
24981708Sstevel 					    PICL_PROP_PEER,
24991708Sstevel 					    &memhdl, sizeof (memhdl));
25001708Sstevel 					if (err == PICL_PROPNOTFOUND)
25011708Sstevel 						break;
25021708Sstevel 					if (err != PICL_SUCCESS)
25031708Sstevel 						return;
25041708Sstevel 				}
25051708Sstevel 			} else if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0) {
25061708Sstevel 				/*
25071708Sstevel 				 * XXX - no mechanism for deleting row - so
25081708Sstevel 				 * delete whole tabel and start again
25091708Sstevel 				 */
25101708Sstevel 				err = ptree_get_prop_by_name(fruhdl,
25111708Sstevel 				    PICL_PROP_DEVICES, &tblproph);
25121708Sstevel 				if (err == PICL_SUCCESS) {
25131708Sstevel 					err = ptree_delete_prop(tblproph);
25141708Sstevel 					if (err != PICL_SUCCESS)
25151708Sstevel 						return;
25161708Sstevel 					(void) ptree_destroy_prop(tblproph);
25171708Sstevel 				}
25181708Sstevel 				err = create_table(fruhdl, &tblhdl,
25191708Sstevel 				    PICL_PROP_DEVICES);
25201708Sstevel 				if (err != PICL_SUCCESS)
25211708Sstevel 					return;
25221708Sstevel 			}
25231708Sstevel next_dimm:
25241708Sstevel 			err = ptree_get_propval_by_name(lochdl,
25251708Sstevel 			    PICL_PROP_PEER, &lochdl, sizeof (lochdl));
25261708Sstevel 			if (err == PICL_PROPNOTFOUND)
25271708Sstevel 				break;
25281708Sstevel 			if (err != PICL_SUCCESS)
25291708Sstevel 				return;
25301708Sstevel 		}
25311708Sstevel next_bank:
25321708Sstevel 		err = ptree_get_propval_by_name(banklochdl,
25331708Sstevel 		    PICL_PROP_PEER, &banklochdl, sizeof (banklochdl));
25341708Sstevel 		if (err == PICL_PROPNOTFOUND)
25351708Sstevel 			break;
25361708Sstevel 		if (err != PICL_SUCCESS)
25371708Sstevel 			return;
25381708Sstevel 	}
25391708Sstevel 	/*
25401708Sstevel 	 * We don't get an event to say that cpu nodes have been added/
25411708Sstevel 	 * deleted (in fact as things stand they are never deleted). However
25421708Sstevel 	 * we know that all cpus must be configured before the MC_ADDED event
25431708Sstevel 	 * we are handling here. So if the cpu links haven't been set up yet
25441708Sstevel 	 * then we do it now.
25451708Sstevel 	 */
25461708Sstevel 	if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
25471708Sstevel 		sprintf_buf4(buf, PROC_LOC_PATH, SAFARI_ADDR_TO_SB(value),
25481708Sstevel 		    SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value));
25491708Sstevel 		err = ptree_get_node_by_path(buf, &lochdl);
25501708Sstevel 		if (err != PICL_SUCCESS)
25511708Sstevel 			return;
25521708Sstevel 		sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value),
25531708Sstevel 		    SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value),
25541708Sstevel 		    SAFARI_ADDR_TO_P(value));
25551708Sstevel 		err = ptree_get_node_by_path(buf, &fruhdl);
25561708Sstevel 		if (err != PICL_SUCCESS)
25571708Sstevel 			return;
25581708Sstevel 		sprintf_buf2(buf, "P%d", SAFARI_ADDR_TO_P(value));
25591708Sstevel 		err = ptree_get_propval_by_name(fruhdl,
25601708Sstevel 		    PICL_PROP_DEVICES, &tblhdl, sizeof (tblhdl));
25611708Sstevel 		if (err != PICL_SUCCESS)
25621708Sstevel 			return;
25631708Sstevel 		(void) create_cpu_references(buf, fruhdl, tblhdl);
25641708Sstevel 	}
25651708Sstevel }
25661708Sstevel 
25671708Sstevel /*
25681708Sstevel  * subroutine for add_env_nodes(), and add_led_node(). Adds a sensor
25691708Sstevel  * node under the sc node in the platform tree, of name "nodename" and
25701708Sstevel  * class "class". Also add UnitAddress property (always 0 as the nodenames
25711708Sstevel  * are unique anyway). Add reference property back to parent fru/location node
25721708Sstevel  * in frutree and a Devices table entry pointing to this node from the
25731708Sstevel  * parent fru/location node in frutree.
25741708Sstevel  */
25751708Sstevel static int
add_sensor_node(picl_nodehdl_t fruhdl,picl_nodehdl_t lochdl,char * nodename,char * class,char * prop_class,picl_prophdl_t tblhdl,picl_nodehdl_t * sensorhdlp)25761708Sstevel add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl, char *nodename,
25771708Sstevel 	char *class, char *prop_class, picl_prophdl_t tblhdl,
25781708Sstevel 	picl_nodehdl_t *sensorhdlp)
25791708Sstevel {
25801708Sstevel 	int err;
25811708Sstevel 
25821708Sstevel 	err = ptree_create_and_add_node(sch, nodename, class, sensorhdlp);
25831708Sstevel 	if (err != PICL_SUCCESS) {
25841708Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err);
25851708Sstevel 		return (err);
25861708Sstevel 	}
25871708Sstevel 
25881708Sstevel 	err = create_table_entry(tblhdl, *sensorhdlp, class);
25891708Sstevel 	if (err != PICL_SUCCESS)
25901708Sstevel 		return (err);
25911708Sstevel 
25921708Sstevel 	err = add_sensor_prop(*sensorhdlp, prop_class);
25931708Sstevel 	if (err != PICL_SUCCESS)
25941708Sstevel 		return (err);
25951708Sstevel 
25961708Sstevel 	err = add_prop_charstring(*sensorhdlp, "0", PICL_PROP_UNIT_ADDRESS);
25971708Sstevel 	if (err != PICL_SUCCESS)
25981708Sstevel 		return (err);
25991708Sstevel 
26001708Sstevel 	if (fruhdl != NULL) {
26011708Sstevel 		err = add_prop_ref(*sensorhdlp, fruhdl,
26021708Sstevel 		    PICL_REFPROP_FRU_PARENT);
26031708Sstevel 	} else {
26041708Sstevel 		err = add_prop_ref(*sensorhdlp, lochdl,
26051708Sstevel 		    PICL_REFPROP_LOC_PARENT);
26061708Sstevel 	}
26071708Sstevel 	return (err);
26081708Sstevel }
26091708Sstevel 
26101708Sstevel /*
26111708Sstevel  * subroutine for add_sensor_node()/add_env_nodes(). Used for adding dynamic
26121708Sstevel  * properties
26131708Sstevel  */
26141708Sstevel static int
add_sensor_prop(picl_nodehdl_t nodeh,char * class)26151708Sstevel add_sensor_prop(picl_nodehdl_t nodeh, char *class)
26161708Sstevel {
26171708Sstevel 	ptree_propinfo_t propinfo;
26181708Sstevel 	int err;
26191708Sstevel 
26201708Sstevel 	if (strcmp(class, PICL_PROP_TEMPERATURE) == 0) {
26211708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
26221708Sstevel 		    PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE,
26231708Sstevel 		    sizeof (int), class, get_sensor_data, NULL);
26241708Sstevel 	} else if (strcmp(class, PICL_PROP_FAN_SPEED) == 0) {
26251708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
26261708Sstevel 		    PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE,
26271708Sstevel 		    sizeof (int), class, get_sensor_data, NULL);
26281708Sstevel 	} else if (strcmp(class, PICL_PROP_FAN_SPEED_UNIT) == 0) {
26291708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
26301708Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
26311708Sstevel 		    MAX_SPEED_UNIT_LEN, class, get_sensor_data, NULL);
26321708Sstevel 	} else if (strcmp(class, PICL_PROP_CONDITION) == 0) {
26331708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
26341708Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
26351708Sstevel 		    MAX_CONDITION_LEN, class, get_sensor_data, NULL);
26361708Sstevel 	} else if (strcmp(class, PICL_PROP_STATE) == 0) {
26371708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
26381708Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_WRITE +
26391708Sstevel 		    PICL_VOLATILE, MAX_STATE_LEN, class, get_led_data,
26401708Sstevel 		    set_led_data);
26411708Sstevel 	} else {
26421708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
26431708Sstevel 		    PICL_PTYPE_FLOAT, PICL_READ + PICL_VOLATILE,
26441708Sstevel 		    sizeof (float), class, get_sensor_data, NULL);
26451708Sstevel 	}
26461708Sstevel 	if (err != PICL_SUCCESS) {
26471708Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, class, err);
26481708Sstevel 		return (err);
26491708Sstevel 	}
26501708Sstevel 
26511708Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
26521708Sstevel 	if (err != PICL_SUCCESS) {
26531708Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, class, err);
26541708Sstevel 		return (err);
26551708Sstevel 	}
26561708Sstevel 	return (PICL_SUCCESS);
26571708Sstevel }
26581708Sstevel 
26591708Sstevel /*
26601708Sstevel  * Get requested kstat
26611708Sstevel  */
26621708Sstevel static int
open_kstat(char * name,void ** ptr,kstat_ctl_t ** kcp)26631708Sstevel open_kstat(char *name, void **ptr, kstat_ctl_t **kcp)
26641708Sstevel {
26651708Sstevel 	kstat_t *info_ksp;
26661708Sstevel 
26671708Sstevel 	*kcp = kstat_open();
26681708Sstevel 	if (*kcp == NULL) {
26691708Sstevel 		syslog(LOG_ERR, KSTAT_FAIL);
26701708Sstevel 		return (PICL_FAILURE);
26711708Sstevel 	}
26721708Sstevel 	info_ksp = kstat_lookup(*kcp, NULL, -1, name);
26731708Sstevel 	if (info_ksp == NULL) {
26741708Sstevel 		kstat_close(*kcp);
26751708Sstevel 		syslog(LOG_ERR, KSTAT_FAIL);
26761708Sstevel 		return (PICL_FAILURE);
26771708Sstevel 	}
26781708Sstevel 	if (kstat_read(*kcp, info_ksp, NULL) == -1) {
26791708Sstevel 		kstat_close(*kcp);
26801708Sstevel 		syslog(LOG_ERR, KSTAT_FAIL);
26811708Sstevel 		return (PICL_FAILURE);
26821708Sstevel 	}
26831708Sstevel 	*ptr = info_ksp;
26841708Sstevel 	return (PICL_SUCCESS);
26851708Sstevel }
26861708Sstevel 
26871708Sstevel /*
26881708Sstevel  * dimm status - uses bank-status property on memory-controller node
26891708Sstevel  */
26901708Sstevel 
26911708Sstevel static int
get_dimm_status(ptree_rarg_t * arg,void * result)26921708Sstevel get_dimm_status(ptree_rarg_t *arg, void *result)
26931708Sstevel {
26941708Sstevel 	int err;
26951708Sstevel 	int i;
26961708Sstevel 	picl_prophdl_t	tblhdl;
26971708Sstevel 	picl_prophdl_t  nextprop;
26981708Sstevel 	picl_prophdl_t  refprop;
26991708Sstevel 	picl_prophdl_t  mmgprop;
27001708Sstevel 	picl_prophdl_t  mcprop;
27011708Sstevel 	picl_prophdl_t  bankprop;
27021708Sstevel 	char	nodename[PICL_PROPNAMELEN_MAX];
27031708Sstevel 	char    class[PICL_CLASSNAMELEN_MAX];
27041708Sstevel 	char	bankname[PICL_PROPNAMELEN_MAX];
27051708Sstevel 	char    state[MAX_STATE_SIZE];
27061708Sstevel 
27071708Sstevel 	/*
27081708Sstevel 	 * find the name of this node
27091708Sstevel 	 */
27101708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, nodename,
27111708Sstevel 	    sizeof (nodename));
27121708Sstevel 	if (err != PICL_SUCCESS) {
27131708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
27141708Sstevel 		return (err);
27151708Sstevel 	}
27161708Sstevel 
27171708Sstevel 	/*
27181708Sstevel 	 * find the name of grandparent (dimm bank) node
27191708Sstevel 	 */
27201708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &bankprop,
27211708Sstevel 	    sizeof (picl_nodehdl_t));
27221708Sstevel 	if (err != PICL_SUCCESS) {
27231708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
27241708Sstevel 		return (err);
27251708Sstevel 	}
27261708Sstevel 	err = ptree_get_propval_by_name(bankprop, PICL_PROP_PARENT, &bankprop,
27271708Sstevel 	    sizeof (picl_nodehdl_t));
27281708Sstevel 	if (err != PICL_SUCCESS) {
27291708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
27301708Sstevel 		return (err);
27311708Sstevel 	}
27321708Sstevel 	err = ptree_get_propval_by_name(bankprop, PICL_PROP_NAME, bankname,
27331708Sstevel 	    sizeof (bankname));
27341708Sstevel 	if (err != PICL_SUCCESS) {
27351708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
27361708Sstevel 		return (err);
27371708Sstevel 	}
27381708Sstevel 
27391708Sstevel 	/*
27401708Sstevel 	 * lookup memory-module node in Devices table
27411708Sstevel 	 */
27421708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl,
27431708Sstevel 	    sizeof (tblhdl));
27441708Sstevel 	if (err != PICL_SUCCESS) {
27451708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err);
27461708Sstevel 		return (err);
27471708Sstevel 	}
27481708Sstevel 	err = ptree_get_next_by_row(tblhdl, &nextprop);
27491708Sstevel 	if (err != PICL_SUCCESS) {
27501708Sstevel 		/*
27511708Sstevel 		 * if Devices table empty then dimm is unconfigured
27521708Sstevel 		 */
27531708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_DISABLED,
27541708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
27551708Sstevel 		return (PICL_SUCCESS);
27561708Sstevel 	}
27571708Sstevel 	err = ptree_get_next_by_row(nextprop, &nextprop);
27581708Sstevel 	if (err != PICL_SUCCESS) {
27591708Sstevel 		syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err);
27601708Sstevel 		return (err);
27611708Sstevel 	}
27621708Sstevel 
27631708Sstevel 	/*
27641708Sstevel 	 * walk down second column (ref ptr)
27651708Sstevel 	 */
27661708Sstevel 	while (err == PICL_SUCCESS) {
27671708Sstevel 		err = ptree_get_propval(nextprop, &refprop, sizeof (refprop));
27681708Sstevel 		if (err != PICL_SUCCESS) {
27691708Sstevel 			syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
27701708Sstevel 			return (PICL_PROPVALUNAVAILABLE);
27711708Sstevel 		}
27721708Sstevel 		err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME,
27731708Sstevel 		    class, sizeof (class));
27741708Sstevel 		if (err == PICL_SUCCESS && strcmp(class,
27751708Sstevel 		    PICL_CLASS_MEMORY_MODULE) == 0)
27761708Sstevel 			break;
27771708Sstevel 		if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) {
27781708Sstevel 			syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME,
27791708Sstevel 			    err);
27801708Sstevel 			return (err);
27811708Sstevel 		}
27821708Sstevel 		err = ptree_get_next_by_col(nextprop, &nextprop);
27831708Sstevel 		if (err != PICL_SUCCESS) {
27841708Sstevel 			/*
27851708Sstevel 			 * if no memory-module in Devices table
27861708Sstevel 			 *  then dimm is unconfigured
27871708Sstevel 			 */
27881708Sstevel 			(void) strlcpy(result, PICL_PROPVAL_DISABLED,
27891708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
27901708Sstevel 			return (PICL_SUCCESS);
27911708Sstevel 		}
27921708Sstevel 	}
27931708Sstevel 
27941708Sstevel 	/*
27951708Sstevel 	 * we've finally found the associated memory-module
27961708Sstevel 	 * node. Now need to find the bank-status property on
27971708Sstevel 	 * its parent memory-controller.
27981708Sstevel 	 */
27991708Sstevel 	err = ptree_get_propval_by_name(refprop, PICL_PROP_PARENT,
28001708Sstevel 	    &mmgprop, sizeof (picl_nodehdl_t));
28011708Sstevel 	if (err != PICL_SUCCESS) {
28021708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
28031708Sstevel 		return (err);
28041708Sstevel 	}
28051708Sstevel 	err = ptree_get_propval_by_name(mmgprop, PICL_PROP_PARENT, &mcprop,
28061708Sstevel 	    sizeof (picl_nodehdl_t));
28071708Sstevel 	if (err != PICL_SUCCESS) {
28081708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
28091708Sstevel 		return (err);
28101708Sstevel 	}
28111708Sstevel 	err = ptree_get_propval_by_name(mcprop, PICL_PROP_BANK_STATUS, &tblhdl,
28121708Sstevel 	    sizeof (tblhdl));
28131708Sstevel 	if (err != PICL_SUCCESS) {
28141708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
28151708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
28161708Sstevel 		return (PICL_SUCCESS);
28171708Sstevel 	}
28181708Sstevel 
28191708Sstevel 	/*
28201708Sstevel 	 * bank-status is a table. Need to find the entry corresponding
28211708Sstevel 	 * to this node
28221708Sstevel 	 */
28231708Sstevel 	err = ptree_get_next_by_row(tblhdl, &nextprop);
28241708Sstevel 	if (err != PICL_SUCCESS) {
28251708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
28261708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
28271708Sstevel 		return (PICL_SUCCESS);
28281708Sstevel 	}
28291708Sstevel 	for (i = 0; i < 4; i++) {
28301708Sstevel 		err = ptree_get_propval(nextprop, &state, sizeof (state));
28311708Sstevel 		if (err != PICL_SUCCESS) {
28321708Sstevel 			(void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
28331708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
28341708Sstevel 			return (err);
28351708Sstevel 		}
28361708Sstevel 		if ((i & 1) == (bankname[1] - '0')) {
28371708Sstevel 			if (strcmp(state, "pass") == 0) {
28381708Sstevel 				(void) strlcpy(result, PICL_PROPVAL_OKAY,
28391708Sstevel 				    MAX_OPERATIONAL_STATUS_LEN);
28401708Sstevel 			} else if (strcmp(state, "fail") == 0) {
28411708Sstevel 				(void) strlcpy(result, PICL_PROPVAL_FAILED,
28421708Sstevel 				    MAX_OPERATIONAL_STATUS_LEN);
28431708Sstevel 			} else {
28441708Sstevel 				(void) strlcpy(result, state,
28451708Sstevel 				    MAX_OPERATIONAL_STATUS_LEN);
28461708Sstevel 			}
28471708Sstevel 			break;
28481708Sstevel 		}
28491708Sstevel 		err = ptree_get_next_by_col(nextprop, &nextprop);
28501708Sstevel 		if (err != PICL_SUCCESS) {
28511708Sstevel 			(void) strlcpy(result, PICL_PROPVAL_OKAY,
28521708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
28531708Sstevel 			break;
28541708Sstevel 		}
28551708Sstevel 	}
28561708Sstevel 	return (PICL_SUCCESS);
28571708Sstevel }
28581708Sstevel 
28591708Sstevel /*
28601708Sstevel  * cpu status - uses State property on cpu node
28611708Sstevel  */
28621708Sstevel 
28631708Sstevel static int
get_cpu_status(ptree_rarg_t * arg,void * result)28641708Sstevel get_cpu_status(ptree_rarg_t *arg, void *result)
28651708Sstevel {
28661708Sstevel 	int err;
28671708Sstevel 	picl_prophdl_t	tblhdl;
28681708Sstevel 	picl_prophdl_t  nextprop;
28691708Sstevel 	picl_prophdl_t  refprop;
28701708Sstevel 	char    class[PICL_CLASSNAMELEN_MAX];
28711708Sstevel 	char    state[MAX_STATE_SIZE];
28721708Sstevel 
28731708Sstevel 	/*
28741708Sstevel 	 * lookup cpu node in Devices table
28751708Sstevel 	 */
28761708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl,
28771708Sstevel 	    sizeof (tblhdl));
28781708Sstevel 	if (err != PICL_SUCCESS) {
28791708Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err);
28801708Sstevel 		return (err);
28811708Sstevel 	}
28821708Sstevel 	err = ptree_get_next_by_row(tblhdl, &nextprop);
28831708Sstevel 	if (err != PICL_SUCCESS) {
28841708Sstevel 		/*
28851708Sstevel 		 * if Devices table empty then cpu is unconfigured
28861708Sstevel 		 */
28871708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_DISABLED,
28881708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
28891708Sstevel 		return (PICL_SUCCESS);
28901708Sstevel 	}
28911708Sstevel 	err = ptree_get_next_by_row(nextprop, &nextprop);
28921708Sstevel 	if (err != PICL_SUCCESS) {
28931708Sstevel 		syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err);
28941708Sstevel 		return (err);
28951708Sstevel 	}
28961708Sstevel 
28971708Sstevel 	/*
28981708Sstevel 	 * walk down second column (ref ptr)
28991708Sstevel 	 */
29001708Sstevel 	while (err == PICL_SUCCESS) {
29011708Sstevel 		err = ptree_get_propval(nextprop, &refprop, sizeof (refprop));
29021708Sstevel 		if (err != PICL_SUCCESS) {
29031708Sstevel 			syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
29041708Sstevel 			return (err);
29051708Sstevel 		}
29061708Sstevel 		err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME,
29071708Sstevel 		    class, sizeof (class));
29081708Sstevel 		if (err == PICL_SUCCESS && strcmp(class, PICL_CLASS_CPU) == 0)
29091708Sstevel 			break;
29101708Sstevel 		if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) {
29111708Sstevel 			syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME,
29121708Sstevel 			    err);
29131708Sstevel 			return (err);
29141708Sstevel 		}
29151708Sstevel 		err = ptree_get_next_by_col(nextprop, &nextprop);
29161708Sstevel 		if (err != PICL_SUCCESS) {
29171708Sstevel 			/*
29181708Sstevel 			 * if no cpu in Devices table
29191708Sstevel 			 *  then cpu is unconfigured
29201708Sstevel 			 */
29211708Sstevel 			(void) strlcpy(result, PICL_PROPVAL_DISABLED,
29221708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
29231708Sstevel 			return (PICL_SUCCESS);
29241708Sstevel 		}
29251708Sstevel 	}
29261708Sstevel 
29271708Sstevel 	/*
29281708Sstevel 	 * we've finally found the associated cpu node. Now need to find its
29291708Sstevel 	 * status property if present (if not assume OK)
29301708Sstevel 	 */
29311708Sstevel 	err = ptree_get_propval_by_name(refprop, OBP_STATUS,
29321708Sstevel 	    state, sizeof (state));
29331708Sstevel 	if (err == PICL_SUCCESS) {
29341708Sstevel 		if (strcmp(state, "fail") == 0)
29351708Sstevel 			(void) strlcpy(result, PICL_PROPVAL_FAILED,
29361708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
29371708Sstevel 		else
29381708Sstevel 			(void) strlcpy(result, state,
29391708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
29401708Sstevel 		return (PICL_SUCCESS);
29411708Sstevel 	}
29421708Sstevel 
29431708Sstevel 	(void) strlcpy(result, PICL_PROPVAL_OKAY, MAX_OPERATIONAL_STATUS_LEN);
29441708Sstevel 	return (PICL_SUCCESS);
29451708Sstevel }
29461708Sstevel 
29471708Sstevel /*
29481708Sstevel  * system/io board condition - uses sgenv driver kstats
29491708Sstevel  */
29501708Sstevel 
29511708Sstevel static int
get_board_status(ptree_rarg_t * arg,void * result)29521708Sstevel get_board_status(ptree_rarg_t *arg, void *result)
29531708Sstevel {
29541708Sstevel 	int err = PICL_SUCCESS;
29551708Sstevel 	int i;
29561708Sstevel 	sg_board_info_t	*brd;
29571708Sstevel 	char name[PICL_PROPNAMELEN_MAX];
29581708Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
29591708Sstevel 	kstat_ctl_t *kc;
29601708Sstevel 	kstat_t *board_info_ksp;
29611708Sstevel 
29621708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
29631708Sstevel 	    sizeof (name));
29641708Sstevel 	if (err != PICL_SUCCESS) {
29651708Sstevel 		return (err);
29661708Sstevel 	}
29671708Sstevel 
29681708Sstevel 	err = open_kstat(SG_BOARD_STATUS_KSTAT_NAME, (void **)&board_info_ksp,
29691708Sstevel 	    &kc);
29701708Sstevel 	if (err != PICL_SUCCESS) {
29711708Sstevel 		return (err);
29721708Sstevel 	}
29731708Sstevel 
29741708Sstevel 	brd = board_info_ksp->ks_data;
29751708Sstevel 	for (i = 0; i < SGENV_NUM_BOARD_READINGS(board_info_ksp); i++, brd++) {
29761708Sstevel 		/*
29771708Sstevel 		 * check this kstat matches the name of the node
29781708Sstevel 		 */
29791708Sstevel 		if (SG_BOARD_IS_CPU_TYPE(brd->board_num)) {
29801708Sstevel 			sprintf_buf3(buf, "%s%d",
29811708Sstevel 			    SG_HPU_TYPE_CPU_BOARD_ID, brd->board_num);
29821708Sstevel 		} else {
29831708Sstevel 			sprintf_buf3(buf, "%s%d",
29841708Sstevel 			    SG_HPU_TYPE_PCI_IO_BOARD_ID, brd->board_num);
29851708Sstevel 		}
29861708Sstevel 		if (strncmp(buf, name, strlen(buf)) != 0)
29871708Sstevel 			continue;
29881708Sstevel 
29891708Sstevel 		/*
29901708Sstevel 		 * ok - got the right kstat - get it's value
29911708Sstevel 		 * note that values 0-4 are defined in sbdp_mbox.h
29921708Sstevel 		 */
29931708Sstevel 		if (brd->condition >= 0 && brd->condition < 5)
29941708Sstevel 			(void) strlcpy(result,
29951708Sstevel 			    hpu_condition_table[brd->condition],
29961708Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
29971708Sstevel 		kstat_close(kc);
29981708Sstevel 		return (PICL_SUCCESS);
29991708Sstevel 	}
30001708Sstevel 	kstat_close(kc);
30011708Sstevel 	return (PICL_PROPVALUNAVAILABLE);
30021708Sstevel }
30031708Sstevel 
30041708Sstevel static int
get_op_status(ptree_rarg_t * arg,void * result)30051708Sstevel get_op_status(ptree_rarg_t *arg, void *result)
30061708Sstevel {
30071708Sstevel 	int err = PICL_SUCCESS;
30081708Sstevel 	char name[PICL_PROPNAMELEN_MAX];
30091708Sstevel 	char value[MAX_STATE_LEN];
30101708Sstevel 	char	parent_name[PICL_PROPNAMELEN_MAX];
30111708Sstevel 	picl_nodehdl_t loch;
30121708Sstevel 	picl_nodehdl_t parentfruh;
30131708Sstevel 
30141708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
30151708Sstevel 	    sizeof (name));
30161708Sstevel 	if (err != PICL_SUCCESS) {
30171708Sstevel 		return (err);
30181708Sstevel 	}
30191708Sstevel 
30201708Sstevel 	/*
30211708Sstevel 	 * handle dimms, cpus and system boards specially
30221708Sstevel 	 */
30231708Sstevel 	if (IS_PROC_NODE(name)) {
30241708Sstevel 		return (get_cpu_status(arg, result));
30251708Sstevel 	} else if (IS_DIMM_NODE(name)) {
30261708Sstevel 		return (get_dimm_status(arg, result));
30271708Sstevel 	} else if (IS_SB_NODE(name) || IS_IB_NODE(name)) {
30281708Sstevel 		return (get_board_status(arg, result));
30291708Sstevel 	}
30301708Sstevel 
30311708Sstevel 	/*
30321708Sstevel 	 * otherwise OperationalStatus is derived from the fault led state
30331708Sstevel 	 */
30341708Sstevel 
30351708Sstevel 	/*
30361708Sstevel 	 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
30371708Sstevel 	 */
30381708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &loch,
30391708Sstevel 	    sizeof (loch));
30401708Sstevel 	if (err != PICL_SUCCESS)
30411708Sstevel 		return (PICL_PROPVALUNAVAILABLE);
30421708Sstevel 	err = ptree_get_propval_by_name(loch, PICL_PROP_PARENT, &parentfruh,
30431708Sstevel 	    sizeof (parentfruh));
30441708Sstevel 	if (err != PICL_SUCCESS)
30451708Sstevel 		return (PICL_PROPVALUNAVAILABLE);
30461708Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, parent_name,
30471708Sstevel 	    sizeof (parent_name));
30481708Sstevel 	if (err != PICL_SUCCESS)
30491708Sstevel 		return (PICL_PROPVALUNAVAILABLE);
30501708Sstevel 	if (strcmp(name, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0) {
30511708Sstevel 		if (get_led("FAN8", FAULT_LED, value) != PICL_SUCCESS) {
30521708Sstevel 			return (PICL_PROPVALUNAVAILABLE);
30531708Sstevel 		}
30541708Sstevel 	} else if (strcmp(name, "FAN1") == 0 && strcmp(parent_name,
30551708Sstevel 	    "IB6") == 0) {
30561708Sstevel 		if (get_led("FAN9", FAULT_LED, value) != PICL_SUCCESS) {
30571708Sstevel 			return (PICL_PROPVALUNAVAILABLE);
30581708Sstevel 		}
30591708Sstevel 	} else {
30601708Sstevel 		if (get_led(name, FAULT_LED, value) != PICL_SUCCESS) {
30611708Sstevel 			return (PICL_PROPVALUNAVAILABLE);
30621708Sstevel 		}
30631708Sstevel 	}
30641708Sstevel 	if (strcmp(value, PICL_PROPVAL_ON) == 0)
30651708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_FAILED,
30661708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
30671708Sstevel 	else
30681708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_OKAY,
30691708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
30701708Sstevel 	return (PICL_SUCCESS);
30711708Sstevel }
30721708Sstevel 
30731708Sstevel static int
add_board_status(picl_nodehdl_t nodeh,char * nodename)30741708Sstevel add_board_status(picl_nodehdl_t nodeh, char *nodename)
30751708Sstevel {
30761708Sstevel 	ptree_propinfo_t propinfo;
30771708Sstevel 	int err;
30781708Sstevel 	picl_prophdl_t prophdl;
30791708Sstevel 
30801708Sstevel 	/*
30811708Sstevel 	 * check if OperationalStatus property already created for this fru
30821708Sstevel 	 */
30831708Sstevel 	err = ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
30841708Sstevel 	    &prophdl);
30851708Sstevel 	if (err == PICL_SUCCESS)
30861708Sstevel 		return (PICL_SUCCESS);
30871708Sstevel 
30881708Sstevel 	/*
30891708Sstevel 	 * put operational status on dimms, cpus, SBs, IBs, PSUs, FTs, Fans, RPs
30901708Sstevel 	 */
30911708Sstevel 	if (IS_DIMM_NODE(nodename) || IS_PROC_NODE(nodename) ||
30921708Sstevel 	    IS_SB_NODE(nodename) || IS_IB_NODE(nodename) ||
30931708Sstevel 	    IS_PSU_NODE(nodename) || IS_FT_NODE(nodename) ||
30941708Sstevel 	    IS_FAN_NODE(nodename) || IS_RP_NODE(nodename)) {
30951708Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
30961708Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
30971708Sstevel 		    MAX_OPERATIONAL_STATUS_LEN, PICL_PROP_OPERATIONAL_STATUS,
30981708Sstevel 		    get_op_status, NULL);
30991708Sstevel 		if (err != PICL_SUCCESS) {
31001708Sstevel 			syslog(LOG_ERR, PROPINFO_FAIL,
31011708Sstevel 			    PICL_PROP_OPERATIONAL_STATUS, err);
31021708Sstevel 			return (err);
31031708Sstevel 		}
31041708Sstevel 		err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
31051708Sstevel 		if (err != PICL_SUCCESS) {
31061708Sstevel 			syslog(LOG_ERR, ADD_PROP_FAIL,
31071708Sstevel 			    PICL_PROP_OPERATIONAL_STATUS, err);
31081708Sstevel 			return (err);
31091708Sstevel 		}
31101708Sstevel 	}
31111708Sstevel 	return (PICL_SUCCESS);
31121708Sstevel }
31131708Sstevel 
31141708Sstevel /*
31151708Sstevel  * environmental information handling - uses sgenv driver kstats
31161708Sstevel  */
31171708Sstevel 
31181708Sstevel static int
add_env_nodes(picl_nodehdl_t nodeh,char * nodename,picl_prophdl_t tblhdl)31191708Sstevel add_env_nodes(picl_nodehdl_t nodeh, char *nodename, picl_prophdl_t tblhdl)
31201708Sstevel {
31211708Sstevel 	int err = PICL_SUCCESS;
31221708Sstevel 	env_sensor_t	*env;
31231708Sstevel 	int	i;
31241708Sstevel 	picl_prophdl_t	tblhdl2;
31251708Sstevel 	picl_prophdl_t	frutype;
31261708Sstevel 	char fruname[PICL_PROPNAMELEN_MAX];
31271708Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
31281708Sstevel 	char id[PICL_PROPNAMELEN_MAX];
31291708Sstevel 	float scale;
31301708Sstevel 	picl_nodehdl_t childh;
31311708Sstevel 	picl_nodehdl_t sensorhdl;
31321708Sstevel 	kstat_ctl_t *kc;
31331708Sstevel 	kstat_t *env_info_ksp;
31341708Sstevel 
31351708Sstevel 	err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
31361708Sstevel 	if (err != PICL_SUCCESS) {
31371708Sstevel 		return (err);
31381708Sstevel 	}
31391708Sstevel 
31401708Sstevel 	env = env_info_ksp->ks_data;
31411708Sstevel 	for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
31421708Sstevel 		/*
31431708Sstevel 		 * check values from kstat entry are within valid range
31441708Sstevel 		 */
31451708Sstevel 		if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT)
31461708Sstevel 			continue;
31471708Sstevel 		if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB)
31481708Sstevel 			continue;
31491708Sstevel 		if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC)
31501708Sstevel 			continue;
31511708Sstevel 		if ((env->sd_id.id.hpu_type >> 8) >=
31521708Sstevel 		    (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8))
31531708Sstevel 			continue;
31541708Sstevel 		if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT)
31551708Sstevel 			continue;
31561708Sstevel 
31571708Sstevel 		/*
31581708Sstevel 		 * does this kstat entry belong to this fru?
31591708Sstevel 		 * Note sc reports RPS as 10 and 12 via env messages
31601708Sstevel 		 * but by 0 and 2 via fru messages, so correct here
31611708Sstevel 		 */
31621708Sstevel 		if ((env->sd_id.id.hpu_type >> 8) ==
31631708Sstevel 		    (SG_HPU_TYPE_REPEATER_BOARD >> 8)) {
31641708Sstevel 			sprintf_buf3(fruname, "%s%d",
31651708Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
31661708Sstevel 			    env->sd_id.id.hpu_slot - 10);
31671708Sstevel 		} else {
31681708Sstevel 			sprintf_buf3(fruname, "%s%d",
31691708Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
31701708Sstevel 			    env->sd_id.id.hpu_slot);
31711708Sstevel 		}
31721708Sstevel 		if (strcmp(nodename, fruname) != 0)
31731708Sstevel 			continue;
31741708Sstevel 
31751708Sstevel 		/*
31761708Sstevel 		 * set up FRUType. Note we only want to do this once per fru
31771708Sstevel 		 */
31781708Sstevel 		err = ptree_get_prop_by_name(nodeh, PICL_PROP_FRU_TYPE,
31791708Sstevel 		    &frutype);
31801708Sstevel 		if (err != PICL_SUCCESS) {
31811708Sstevel 			err = add_prop_charstring(nodeh,
31821708Sstevel 			    hpu_fru_type_table[env->sd_id.id.hpu_type >> 8],
31831708Sstevel 			    PICL_PROP_FRU_TYPE);
31841708Sstevel 			if (err != PICL_SUCCESS)
31851708Sstevel 				goto done;
31861708Sstevel 		}
31871708Sstevel 
31881708Sstevel 		/*
31891708Sstevel 		 * create the sensor node with a sensible name
31901708Sstevel 		 */
31911708Sstevel 		switch (env->sd_id.id.sensor_type) {
31921708Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
31931708Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
31941708Sstevel 				sprintf_buf2(id, "t_ambient%d",
31951708Sstevel 				    env->sd_id.id.sensor_typenum);
31961708Sstevel 			} else {
31971708Sstevel 				sprintf_buf3(id, "t_%s%d",
31981708Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
31991708Sstevel 				    env->sd_id.id.sensor_partnum);
32001708Sstevel 			}
32011708Sstevel 			break;
32021708Sstevel 		case SG_SENSOR_TYPE_CURRENT:
32031708Sstevel 			sprintf_buf3(id, "i_%s%d",
32041708Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
32051708Sstevel 			    env->sd_id.id.sensor_partnum);
32061708Sstevel 			break;
32071708Sstevel 		case SG_SENSOR_TYPE_COOLING:
32081708Sstevel 			sprintf_buf3(id, "ft_%s%d",
32091708Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
32101708Sstevel 			    env->sd_id.id.sensor_partnum);
32111708Sstevel 			break;
32121708Sstevel 		default: /* voltage */
32131708Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
32141708Sstevel 				sprintf_buf3(id, "v_%s%d",
32151708Sstevel 				    hpu_sensor_table[env->sd_id.id.sensor_type],
32161708Sstevel 				    env->sd_id.id.sensor_typenum);
32171708Sstevel 			} else {
32181708Sstevel 				sprintf_buf3(id, "v_%s%d",
32191708Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
32201708Sstevel 				    env->sd_id.id.sensor_partnum);
32211708Sstevel 			}
32221708Sstevel 			break;
32231708Sstevel 		}
32241708Sstevel 
32251708Sstevel 		/*
32261708Sstevel 		 * check if sensor node has already been created
32271708Sstevel 		 */
32281708Sstevel 		sprintf_buf3(buf, "%s_%s", nodename, id);
32291708Sstevel 		if (find_child_by_name(sch, buf) != NULL)
32301708Sstevel 			continue;
32311708Sstevel 
32321708Sstevel 		if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_COOLING) {
32331708Sstevel 			/*
32341708Sstevel 			 * create individual fan_unit nodes
32351708Sstevel 			 */
32361708Sstevel 			childh = nodeh;
32371708Sstevel 			sprintf_buf2(fruname, "FAN%d",
32381708Sstevel 			    env->sd_id.id.sensor_partnum);
32391708Sstevel 			err = add_intermediate_nodes(&childh, fruname,
32401708Sstevel 			    &tblhdl2, "fan-unit", "FAN");
32411708Sstevel 			if (err != PICL_SUCCESS)
32421708Sstevel 				goto done;
32431708Sstevel 			err = add_board_status(childh, fruname);
32441708Sstevel 			if (err != PICL_SUCCESS)
32451708Sstevel 				goto done;
32461708Sstevel 		} else if (env->sd_id.id.sensor_part ==
32471708Sstevel 		    SG_SENSOR_PART_CHEETAH ||
32481708Sstevel 		    ((env->sd_id.id.hpu_type >> 8) ==
32491708Sstevel 		    (SG_HPU_TYPE_CPU_BOARD >> 8) &&
32501708Sstevel 		    (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_TEMPERATURE) &&
32511708Sstevel 		    (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD))) {
32521708Sstevel 			/*
32531708Sstevel 			 * put sensors under individual processor nodes
32541708Sstevel 			 */
32551708Sstevel 			childh = nodeh;
32561708Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD)
32571708Sstevel 				sprintf_buf2(fruname, "P%d",
32581708Sstevel 				    env->sd_id.id.sensor_typenum);
32591708Sstevel 			else
32601708Sstevel 				sprintf_buf2(fruname, "P%d",
32611708Sstevel 				    env->sd_id.id.sensor_partnum);
32621708Sstevel 			err = add_intermediate_nodes(&childh, fruname,
32631708Sstevel 			    &tblhdl2, "cpu", "PROC");
32641708Sstevel 			if (err != PICL_SUCCESS)
32651708Sstevel 				goto done;
32661708Sstevel 		} else {
32671708Sstevel 			childh = nodeh;
32681708Sstevel 			tblhdl2 = tblhdl;
32691708Sstevel 		}
32701708Sstevel 		err = add_sensor_node(childh, NULL, buf,
32711708Sstevel 		    hpu_sensor_class_table[env->sd_id.id.sensor_type],
32721708Sstevel 		    hpu_sensor_prop_table[env->sd_id.id.sensor_type],
32731708Sstevel 		    tblhdl2, &sensorhdl);
32741708Sstevel 		if (err != PICL_SUCCESS)
32751708Sstevel 			goto done;
32761708Sstevel 
32771708Sstevel 		/*
32781708Sstevel 		 * add additional properties
32791708Sstevel 		 */
32801708Sstevel 		switch (env->sd_id.id.sensor_type) {
32811708Sstevel 		case SG_SENSOR_TYPE_COOLING:
32821708Sstevel 			err = add_prop_charstring(sensorhdl, id,
32831708Sstevel 			    PICL_PROP_LABEL);
32841708Sstevel 			if (err != PICL_SUCCESS)
32851708Sstevel 				goto done;
32861708Sstevel 			/*
32871708Sstevel 			 * add threshold at 75% of full speed
32881708Sstevel 			 */
32891708Sstevel 			err = add_prop_int(sensorhdl, 75,
32901708Sstevel 			    PICL_PROP_LOW_WARNING_THRESHOLD);
32911708Sstevel 			if (err != PICL_SUCCESS)
32921708Sstevel 				goto done;
32931708Sstevel 			err = add_sensor_prop(sensorhdl,
32941708Sstevel 			    PICL_PROP_FAN_SPEED_UNIT);
32951708Sstevel 			if (err != PICL_SUCCESS)
32961708Sstevel 				goto done;
32971708Sstevel 			continue;
32981708Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
32991708Sstevel 			if ((env->sd_id.id.hpu_type >> 8 ==
33001708Sstevel 			    (SG_HPU_TYPE_CPU_BOARD >> 8)) &&
33011708Sstevel 			    (env->sd_id.id.sensor_part ==
33021708Sstevel 			    SG_SENSOR_PART_BOARD)) {
33031708Sstevel 				err = add_prop_charstring(sensorhdl,
33041708Sstevel 				    PICL_PROPVAL_AMBIENT, PICL_PROP_LABEL);
33051708Sstevel 				if (err != PICL_SUCCESS)
33061708Sstevel 					goto done;
33071708Sstevel 			} else if (env->sd_id.id.sensor_part ==
33081708Sstevel 			    SG_SENSOR_PART_CHEETAH) {
33091708Sstevel 				err = add_prop_charstring(sensorhdl,
33101708Sstevel 				    PICL_PROPVAL_DIE, PICL_PROP_LABEL);
33111708Sstevel 				if (err != PICL_SUCCESS)
33121708Sstevel 					goto done;
33131708Sstevel 			} else {
33141708Sstevel 				err = add_prop_charstring(sensorhdl, id,
33151708Sstevel 				    PICL_PROP_LABEL);
33161708Sstevel 				if (err != PICL_SUCCESS)
33171708Sstevel 					goto done;
33181708Sstevel 			}
33191708Sstevel 			err = add_prop_int(sensorhdl, env->sd_lo_warn /
33201708Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_LOW_WARNING);
33211708Sstevel 			if (err != PICL_SUCCESS)
33221708Sstevel 				goto done;
33231708Sstevel 			err = add_prop_int(sensorhdl, env->sd_lo /
33241708Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_LOW_SHUTDOWN);
33251708Sstevel 			if (err != PICL_SUCCESS)
33261708Sstevel 				goto done;
33271708Sstevel 			err = add_prop_int(sensorhdl, env->sd_hi_warn /
33281708Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_WARNING);
33291708Sstevel 			if (err != PICL_SUCCESS)
33301708Sstevel 				goto done;
33311708Sstevel 			err = add_prop_int(sensorhdl, env->sd_hi /
33321708Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_SHUTDOWN);
33331708Sstevel 			if (err != PICL_SUCCESS)
33341708Sstevel 				goto done;
33351708Sstevel 			continue;
33361708Sstevel 		case SG_SENSOR_TYPE_1_5_VDC:
33371708Sstevel 			scale = SG_1_5_VDC_SCALE;
33381708Sstevel 			break;
33391708Sstevel 		case SG_SENSOR_TYPE_1_8_VDC:
33401708Sstevel 			scale = SG_1_8_VDC_SCALE;
33411708Sstevel 			break;
33421708Sstevel 		case SG_SENSOR_TYPE_2_5_VDC:
33431708Sstevel 			scale = SG_2_5_VDC_SCALE;
33441708Sstevel 			break;
33451708Sstevel 		case SG_SENSOR_TYPE_3_3_VDC:
33461708Sstevel 			scale = SG_3_3_VDC_SCALE;
33471708Sstevel 			break;
33481708Sstevel 		case SG_SENSOR_TYPE_5_VDC:
33491708Sstevel 			scale = SG_5_VDC_SCALE;
33501708Sstevel 			break;
33511708Sstevel 		case SG_SENSOR_TYPE_12_VDC:
33521708Sstevel 			scale = SG_12_VDC_SCALE;
33531708Sstevel 			break;
33541708Sstevel 		case SG_SENSOR_TYPE_48_VDC:
33551708Sstevel 			/*
33561708Sstevel 			 * The 48VDC sensor is just an indicator - doesn't
33571708Sstevel 			 * give reading or thresholds
33581708Sstevel 			 */
33591708Sstevel 			err = add_prop_charstring(sensorhdl, id,
33601708Sstevel 			    PICL_PROP_LABEL);
33611708Sstevel 			if (err != PICL_SUCCESS)
33621708Sstevel 				goto done;
33631708Sstevel 			continue;
33641708Sstevel 		case SG_SENSOR_TYPE_CURRENT:
33651708Sstevel 			scale = SG_CURRENT_SCALE;
33661708Sstevel 			break;
33671708Sstevel 		}
33681708Sstevel 		err = add_prop_charstring(sensorhdl, id, PICL_PROP_LABEL);
33691708Sstevel 		if (err != PICL_SUCCESS)
33701708Sstevel 			goto done;
33711708Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_lo_warn / scale,
33721708Sstevel 		    PICL_PROP_LOW_WARNING);
33731708Sstevel 		if (err != PICL_SUCCESS)
33741708Sstevel 			goto done;
33751708Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_lo / scale,
33761708Sstevel 		    PICL_PROP_LOW_SHUTDOWN);
33771708Sstevel 		if (err != PICL_SUCCESS)
33781708Sstevel 			goto done;
33791708Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_hi_warn / scale,
33801708Sstevel 		    PICL_PROP_HIGH_WARNING);
33811708Sstevel 		if (err != PICL_SUCCESS)
33821708Sstevel 			goto done;
33831708Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_hi / scale,
33841708Sstevel 		    PICL_PROP_HIGH_SHUTDOWN);
33851708Sstevel 		if (err != PICL_SUCCESS)
33861708Sstevel 			goto done;
33871708Sstevel 	}
33881708Sstevel done:
33891708Sstevel 	kstat_close(kc);
33901708Sstevel 	return (err);
33911708Sstevel }
33921708Sstevel 
33931708Sstevel static int
get_sensor_data(ptree_rarg_t * arg,void * result)33941708Sstevel get_sensor_data(ptree_rarg_t *arg, void *result)
33951708Sstevel {
33961708Sstevel 	int err;				/* return code */
33971708Sstevel 	kstat_ctl_t		*kc;
33981708Sstevel 	char	name[PICL_PROPNAMELEN_MAX];
33991708Sstevel 	ptree_propinfo_t propinfo;
34001708Sstevel 	int	i;
34011708Sstevel 	env_sensor_t	*env;
34021708Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
34031708Sstevel 	char buf1[PICL_PROPNAMELEN_MAX];
34041708Sstevel 	kstat_t *env_info_ksp;
34051708Sstevel 
34061708Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
34071708Sstevel 	    sizeof (name));
34081708Sstevel 	if (err != PICL_SUCCESS)
34091708Sstevel 		return (err);
34101708Sstevel 	err = ptree_get_propinfo(arg->proph, &propinfo);
34111708Sstevel 	if (err != PICL_SUCCESS)
34121708Sstevel 		return (err);
34131708Sstevel 
34141708Sstevel 	err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
34151708Sstevel 	if (err != PICL_SUCCESS) {
34161708Sstevel 		return (err);
34171708Sstevel 	}
34181708Sstevel 
34191708Sstevel 	env = env_info_ksp->ks_data;
34201708Sstevel 	for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
34211708Sstevel 		/*
34221708Sstevel 		 * check kstat values are within range
34231708Sstevel 		 */
34241708Sstevel 		if (SG_INFO_VALUESTATUS(env->sd_infostamp) != SG_INFO_VALUE_OK)
34251708Sstevel 			continue;
34261708Sstevel 		if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT)
34271708Sstevel 			continue;
34281708Sstevel 		if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB)
34291708Sstevel 			continue;
34301708Sstevel 		if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC)
34311708Sstevel 			continue;
34321708Sstevel 		if ((env->sd_id.id.hpu_type >> 8) >=
34331708Sstevel 		    (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8))
34341708Sstevel 			continue;
34351708Sstevel 		if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT)
34361708Sstevel 			continue;
34371708Sstevel 
34381708Sstevel 		/*
34391708Sstevel 		 * check this kstat matches the name of the node
34401708Sstevel 		 * note sc reports RPS as 10 and 12 via env messages
34411708Sstevel 		 * but by 0 and 2 via fru messages, so correct here
34421708Sstevel 		 */
34431708Sstevel 		if ((env->sd_id.id.hpu_type >> 8) ==
34441708Sstevel 		    (SG_HPU_TYPE_REPEATER_BOARD >> 8))
34451708Sstevel 			sprintf_buf3(buf, "%s%d",
34461708Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
34471708Sstevel 			    env->sd_id.id.hpu_slot - 10);
34481708Sstevel 		else
34491708Sstevel 			sprintf_buf3(buf, "%s%d",
34501708Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
34511708Sstevel 			    env->sd_id.id.hpu_slot);
34521708Sstevel 		switch (env->sd_id.id.sensor_type) {
34531708Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
34541708Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
34551708Sstevel 				sprintf_buf3(buf1, "%s_t_ambient%d",
34561708Sstevel 				    buf, env->sd_id.id.sensor_typenum);
34571708Sstevel 			} else {
34581708Sstevel 				sprintf_buf4(buf1, "%s_t_%s%d", buf,
34591708Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
34601708Sstevel 				    env->sd_id.id.sensor_partnum);
34611708Sstevel 			}
34621708Sstevel 			break;
34631708Sstevel 		case SG_SENSOR_TYPE_CURRENT:
34641708Sstevel 			sprintf_buf4(buf1, "%s_i_%s%d", buf,
34651708Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
34661708Sstevel 			    env->sd_id.id.sensor_partnum);
34671708Sstevel 			break;
34681708Sstevel 		case SG_SENSOR_TYPE_COOLING:
34691708Sstevel 			sprintf_buf4(buf1, "%s_ft_%s%d", buf,
34701708Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
34711708Sstevel 			    env->sd_id.id.sensor_partnum);
34721708Sstevel 			break;
34731708Sstevel 		default: /* voltage */
34741708Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
34751708Sstevel 				sprintf_buf4(buf1, "%s_v_%s%d", buf,
34761708Sstevel 				    hpu_sensor_table[env->sd_id.id.sensor_type],
34771708Sstevel 				    env->sd_id.id.sensor_typenum);
34781708Sstevel 			} else {
34791708Sstevel 				sprintf_buf4(buf1, "%s_v_%s%d", buf,
34801708Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
34811708Sstevel 				    env->sd_id.id.sensor_partnum);
34821708Sstevel 			}
34831708Sstevel 			break;
34841708Sstevel 		}
34851708Sstevel 		if (strcmp(buf1, name) != 0)
34861708Sstevel 			continue;
34871708Sstevel 
34881708Sstevel 		/*
34891708Sstevel 		 * ok - this is the kstat we want - update
34901708Sstevel 		 * Condition, or sensor reading as requested
34911708Sstevel 		 */
34921708Sstevel 		if (strcmp(propinfo.piclinfo.name, PICL_PROP_CONDITION) == 0) {
34931708Sstevel 			switch (SG_GET_SENSOR_STATUS(env->sd_status)) {
34941708Sstevel 			case SG_SENSOR_STATUS_OK:
34951708Sstevel 				(void) strlcpy(result, PICL_PROPVAL_OKAY,
34961708Sstevel 				    MAX_CONDITION_LEN);
34971708Sstevel 				break;
34981708Sstevel 			case SG_SENSOR_STATUS_LO_WARN:
34991708Sstevel 			case SG_SENSOR_STATUS_HI_WARN:
35001708Sstevel 				(void) strlcpy(result, PICL_PROPVAL_WARNING,
35011708Sstevel 				    MAX_CONDITION_LEN);
35021708Sstevel 				break;
35031708Sstevel 			case SG_SENSOR_STATUS_LO_DANGER:
35041708Sstevel 			case SG_SENSOR_STATUS_HI_DANGER:
35051708Sstevel 				(void) strlcpy(result, PICL_PROPVAL_FAILED,
35061708Sstevel 				    MAX_CONDITION_LEN);
35071708Sstevel 				break;
35081708Sstevel 			default:
35091708Sstevel 				kstat_close(kc);
35101708Sstevel 				return (PICL_PROPVALUNAVAILABLE);
35111708Sstevel 			}
35121708Sstevel 			kstat_close(kc);
35131708Sstevel 			return (PICL_SUCCESS);
35141708Sstevel 		}
35151708Sstevel 		switch (env->sd_id.id.sensor_type) {
35161708Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
35171708Sstevel 			*(int *)result = env->sd_value / SG_TEMPERATURE_SCALE;
35181708Sstevel 			break;
35191708Sstevel 		case SG_SENSOR_TYPE_1_5_VDC:
35201708Sstevel 			*(float *)result =
35211708Sstevel 			    (float)env->sd_value / (float)SG_1_5_VDC_SCALE;
35221708Sstevel 			break;
35231708Sstevel 		case SG_SENSOR_TYPE_1_8_VDC:
35241708Sstevel 			*(float *)result =
35251708Sstevel 			    (float)env->sd_value / (float)SG_1_8_VDC_SCALE;
35261708Sstevel 			break;
35271708Sstevel 		case SG_SENSOR_TYPE_2_5_VDC:
35281708Sstevel 			*(float *)result =
35291708Sstevel 			    (float)env->sd_value / (float)SG_2_5_VDC_SCALE;
35301708Sstevel 			break;
35311708Sstevel 		case SG_SENSOR_TYPE_3_3_VDC:
35321708Sstevel 			*(float *)result =
35331708Sstevel 			    (float)env->sd_value / (float)SG_3_3_VDC_SCALE;
35341708Sstevel 			break;
35351708Sstevel 		case SG_SENSOR_TYPE_5_VDC:
35361708Sstevel 			*(float *)result =
35371708Sstevel 			    (float)env->sd_value / (float)SG_5_VDC_SCALE;
35381708Sstevel 			break;
35391708Sstevel 		case SG_SENSOR_TYPE_12_VDC:
35401708Sstevel 			*(float *)result =
35411708Sstevel 			    (float)env->sd_value / (float)SG_12_VDC_SCALE;
35421708Sstevel 			break;
35431708Sstevel 		case SG_SENSOR_TYPE_CURRENT:
35441708Sstevel 			*(float *)result =
35451708Sstevel 			    (float)env->sd_value / (float)SG_CURRENT_SCALE;
35461708Sstevel 			break;
35471708Sstevel 		case SG_SENSOR_TYPE_COOLING:
35481708Sstevel 			if (strcmp(propinfo.piclinfo.name,
35491708Sstevel 			    PICL_PROP_FAN_SPEED_UNIT) == 0) {
35501708Sstevel 				if (SG_GET_SENSOR_STATUS(env->sd_status) ==
35511708Sstevel 				    SG_SENSOR_STATUS_FAN_LOW) {
35521708Sstevel 					(void) strlcpy(result,
35531708Sstevel 					    PICL_PROPVAL_SELF_REGULATING,
35541708Sstevel 					    MAX_SPEED_UNIT_LEN);
35551708Sstevel 				} else {
35561708Sstevel 					(void) strlcpy(result,
35571708Sstevel 					    PICL_PROPVAL_PER_CENT,
35581708Sstevel 					    MAX_SPEED_UNIT_LEN);
35591708Sstevel 				}
35601708Sstevel 			} else {
35611708Sstevel 				switch (SG_GET_SENSOR_STATUS(env->sd_status)) {
35621708Sstevel 				case SG_SENSOR_STATUS_FAN_HIGH:
35631708Sstevel 					*(int *)result = 100;
35641708Sstevel 					break;
35651708Sstevel 				case SG_SENSOR_STATUS_FAN_FAIL:
35661708Sstevel 				case SG_SENSOR_STATUS_FAN_OFF:
35671708Sstevel 					*(int *)result = 0;
35681708Sstevel 					break;
35691708Sstevel 				default:
35701708Sstevel 				case SG_SENSOR_STATUS_FAN_LOW:
35711708Sstevel 					kstat_close(kc);
35721708Sstevel 					return (PICL_PROPVALUNAVAILABLE);
35731708Sstevel 				}
35741708Sstevel 			}
35751708Sstevel 			break;
35761708Sstevel 		default:
35771708Sstevel 			kstat_close(kc);
35781708Sstevel 			return (PICL_PROPVALUNAVAILABLE);
35791708Sstevel 		}
35801708Sstevel 		kstat_close(kc);
35811708Sstevel 		return (PICL_SUCCESS);
35821708Sstevel 	}
35831708Sstevel 	kstat_close(kc);
35841708Sstevel 	return (PICL_PROPVALUNAVAILABLE);
35851708Sstevel }
35861708Sstevel 
35871708Sstevel /*
35881708Sstevel  * led information handling - uses lw8 driver
35891708Sstevel  */
35901708Sstevel 
35911708Sstevel static int
add_led_nodes(picl_nodehdl_t nodeh,char * name,int position,picl_prophdl_t tblhdl)35921708Sstevel add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
35931708Sstevel     picl_prophdl_t tblhdl)
35941708Sstevel {
35951708Sstevel 	int err;
35961708Sstevel 	int  ledfd;
35971708Sstevel 	lom_get_led_t lom_get_led;
35981708Sstevel 	picl_nodehdl_t sensorhdl;
35991708Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
36001708Sstevel 
36011708Sstevel 	/*
36021708Sstevel 	 * Open the lw8 pseudo dev to get the led information
36031708Sstevel 	 */
36041708Sstevel 	if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
36051708Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
36061708Sstevel 		return (PICL_SUCCESS);
36071708Sstevel 	}
36081708Sstevel 	bzero(&lom_get_led, sizeof (lom_get_led));
36091708Sstevel 	(void) strlcpy(lom_get_led.location, name,
36101708Sstevel 	    sizeof (lom_get_led.location));
36111708Sstevel 	if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
36121708Sstevel 		(void) close(ledfd);
36131708Sstevel 		syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
36141708Sstevel 		return (PICL_FAILURE);
36151708Sstevel 	}
36161708Sstevel 	while (lom_get_led.next_id[0] != '\0') {
36171708Sstevel 		(void) strlcpy(lom_get_led.id, lom_get_led.next_id,
36181708Sstevel 		    sizeof (lom_get_led.id));
36191708Sstevel 		lom_get_led.next_id[0] = '\0';
36201708Sstevel 		lom_get_led.position = LOM_LED_POSITION_FRU;
36211708Sstevel 		if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
36221708Sstevel 			(void) close(ledfd);
36231708Sstevel 			syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
36241708Sstevel 			return (PICL_FAILURE);
36251708Sstevel 		}
36261708Sstevel 		sprintf_buf3(buf, "%s_%s", name, lom_get_led.id);
36271708Sstevel 		if (position != lom_get_led.position)
36281708Sstevel 			continue;
36291708Sstevel 		if (position == LOM_LED_POSITION_LOCATION) {
36301708Sstevel 			err = add_sensor_node(NULL, nodeh, buf, PICL_CLASS_LED,
36311708Sstevel 			    PICL_PROP_STATE, tblhdl, &sensorhdl);
36321708Sstevel 		} else {
36331708Sstevel 			err = add_sensor_node(nodeh, NULL, buf, PICL_CLASS_LED,
36341708Sstevel 			    PICL_PROP_STATE, tblhdl, &sensorhdl);
36351708Sstevel 		}
36361708Sstevel 		if (err != PICL_SUCCESS) {
36371708Sstevel 			(void) close(ledfd);
36381708Sstevel 			return (err);
36391708Sstevel 		}
36401708Sstevel 		if (strcmp(name, "chassis") == 0 && strcmp(lom_get_led.id,
36411708Sstevel 		    "locator") == 0) {
36421708Sstevel 			err = add_prop_charstring(sensorhdl, PICL_PROPVAL_TRUE,
36431708Sstevel 			    PICL_PROP_IS_LOCATOR);
36441708Sstevel 			if (err != PICL_SUCCESS) {
36451708Sstevel 				(void) close(ledfd);
36461708Sstevel 				return (err);
36471708Sstevel 			}
36481708Sstevel 			err = add_prop_charstring(sensorhdl,
36491708Sstevel 			    PICL_PROPVAL_SYSTEM, PICL_PROP_LOCATOR_NAME);
36501708Sstevel 			if (err != PICL_SUCCESS) {
36511708Sstevel 				(void) close(ledfd);
36521708Sstevel 				return (err);
36531708Sstevel 			}
36541708Sstevel 		}
36551708Sstevel 		err = add_prop_charstring(sensorhdl, lom_get_led.id,
36561708Sstevel 		    PICL_PROP_LABEL);
36571708Sstevel 		if (err != PICL_SUCCESS) {
36581708Sstevel 			(void) close(ledfd);
36591708Sstevel 			return (err);
36601708Sstevel 		}
36611708Sstevel 		err = add_prop_charstring(sensorhdl, lom_get_led.color,
36621708Sstevel 		    PICL_PROP_COLOR);
36631708Sstevel 		if (err != PICL_SUCCESS) {
36641708Sstevel 			(void) close(ledfd);
36651708Sstevel 			return (err);
36661708Sstevel 		}
36671708Sstevel 	}
36681708Sstevel 	(void) close(ledfd);
36691708Sstevel 	return (PICL_SUCCESS);
36701708Sstevel }
36711708Sstevel 
36721708Sstevel static int
get_led(char * name,char * ptr,char * result)36731708Sstevel get_led(char *name, char *ptr, char *result)
36741708Sstevel {
36751708Sstevel 	int ledfd;
36761708Sstevel 	lom_get_led_t lom_get_led;
36771708Sstevel 
36781708Sstevel 	/*
36791708Sstevel 	 * Open the lw8 pseudo dev to get the led information
36801708Sstevel 	 */
36811708Sstevel 	if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
36821708Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
36831708Sstevel 		return (PICL_FAILURE);
36841708Sstevel 	}
36851708Sstevel 	bzero(&lom_get_led, sizeof (lom_get_led));
36861708Sstevel 	(void) strlcpy(lom_get_led.location, name,
36871708Sstevel 	    sizeof (lom_get_led.location));
36881708Sstevel 	(void) strlcpy(lom_get_led.id, ptr, sizeof (lom_get_led.id));
36891708Sstevel 	if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
36901708Sstevel 		(void) close(ledfd);
36911708Sstevel 		syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
36921708Sstevel 		return (PICL_PROPVALUNAVAILABLE);
36931708Sstevel 	}
36941708Sstevel 	if (lom_get_led.status == LOM_LED_STATUS_ON)
36951708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_ON, MAX_STATE_LEN);
36961708Sstevel 	else if (lom_get_led.status == LOM_LED_STATUS_FLASHING)
36971708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_FLASHING, MAX_STATE_LEN);
36981708Sstevel 	else if (lom_get_led.status == LOM_LED_STATUS_BLINKING)
36991708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_BLINKING, MAX_STATE_LEN);
37001708Sstevel 	else
37011708Sstevel 		(void) strlcpy(result, PICL_PROPVAL_OFF, MAX_STATE_LEN);
37021708Sstevel 	(void) close(ledfd);
37031708Sstevel 	return (PICL_SUCCESS);
37041708Sstevel }
37051708Sstevel 
37061708Sstevel static int
get_led_data(ptree_rarg_t * arg,void * result)37071708Sstevel get_led_data(ptree_rarg_t *arg, void *result)
37081708Sstevel {
37091708Sstevel 	int rc;				/* return code */
37101708Sstevel 	char	name[PICL_PROPNAMELEN_MAX];
37111708Sstevel 	char *ptr;
37121708Sstevel 
37131708Sstevel 	rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
37141708Sstevel 	    sizeof (name));
37151708Sstevel 	if (rc != PICL_SUCCESS)
37161708Sstevel 		return (rc);
37171708Sstevel 
37181708Sstevel 	ptr = strchr(name, '_');
37191708Sstevel 	*ptr++ = '\0'; /* now name is fru name, ptr is led name */
37201708Sstevel 	return (get_led(name, ptr, (char *)result));
37211708Sstevel }
37221708Sstevel 
37231708Sstevel static int
set_led(char * name,char * ptr,char * value)37241708Sstevel set_led(char *name, char *ptr, char *value)
37251708Sstevel {
37261708Sstevel 	int ledfd;
37271708Sstevel 	lom_set_led_t lom_set_led;
37281708Sstevel 
37291708Sstevel 	/*
37301708Sstevel 	 * Open the lw8 pseudo dev to set the led information
37311708Sstevel 	 */
37321708Sstevel 	if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
37331708Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
37341708Sstevel 		return (PICL_FAILURE);
37351708Sstevel 	}
37361708Sstevel 	bzero(&lom_set_led, sizeof (lom_set_led));
37371708Sstevel 	(void) strlcpy(lom_set_led.location, name,
37381708Sstevel 	    sizeof (lom_set_led.location));
37391708Sstevel 	(void) strlcpy(lom_set_led.id, ptr, sizeof (lom_set_led.id));
37401708Sstevel 	if (strcmp(value, PICL_PROPVAL_ON) == 0) {
37411708Sstevel 		lom_set_led.status = LOM_LED_STATUS_ON;
37421708Sstevel 	} else if (strcmp(value, PICL_PROPVAL_FLASHING) == 0) {
37431708Sstevel 		lom_set_led.status = LOM_LED_STATUS_FLASHING;
37441708Sstevel 	} else if (strcmp(value, PICL_PROPVAL_BLINKING) == 0) {
37451708Sstevel 		lom_set_led.status = LOM_LED_STATUS_BLINKING;
37461708Sstevel 	} else {
37471708Sstevel 		lom_set_led.status = LOM_LED_STATUS_OFF;
37481708Sstevel 	}
37491708Sstevel 	if (ioctl(ledfd, LOMIOCSETLED, &lom_set_led) == -1) {
37501708Sstevel 		(void) close(ledfd);
37511708Sstevel 		syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
37521708Sstevel 		return (PICL_PROPVALUNAVAILABLE);
37531708Sstevel 	}
37541708Sstevel 	(void) close(ledfd);
37551708Sstevel 	return (PICL_SUCCESS);
37561708Sstevel }
37571708Sstevel 
37581708Sstevel static int
set_led_data(ptree_warg_t * arg,const void * value)37591708Sstevel set_led_data(ptree_warg_t *arg, const void *value)
37601708Sstevel {
37611708Sstevel 	int rc;				/* return code */
37621708Sstevel 	char	name[PICL_PROPNAMELEN_MAX];
37631708Sstevel 	char *ptr;
37641708Sstevel 
37651708Sstevel 	rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
37661708Sstevel 	    sizeof (name));
37671708Sstevel 	if (rc != PICL_SUCCESS)
37681708Sstevel 		return (rc);
37691708Sstevel 
37701708Sstevel 	ptr = strchr(name, '_');
37711708Sstevel 	*ptr++ = '\0'; /* now name is fru name, ptr is led name */
37721708Sstevel 	return (set_led(name, ptr, (char *)value));
37731708Sstevel }
37741708Sstevel 
37751708Sstevel static void
disk_leds_init(void)37761708Sstevel disk_leds_init(void)
37771708Sstevel {
37781708Sstevel 	int err = 0, i;
37791708Sstevel 
37801708Sstevel 	if (!g_mutex_init) {
37811708Sstevel 		if ((pthread_cond_init(&g_cv, NULL) == 0) &&
37821708Sstevel 		    (pthread_cond_init(&g_cv_ack, NULL) == 0) &&
37831708Sstevel 		    (pthread_mutex_init(&g_mutex, NULL) == 0)) {
37841708Sstevel 			g_mutex_init = B_TRUE;
37851708Sstevel 		} else {
37861708Sstevel 			return;
37871708Sstevel 		}
37881708Sstevel 	}
37891708Sstevel 
37901708Sstevel 	if (ledsthr_created) {
37911708Sstevel 		/*
37921708Sstevel 		 * this is a restart, wake up sleeping threads
37931708Sstevel 		 */
37941708Sstevel 		err = pthread_mutex_lock(&g_mutex);
37951708Sstevel 		if (err != 0) {
37961708Sstevel 			syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
37971708Sstevel 			return;
37981708Sstevel 		}
37991708Sstevel 		g_wait_now = B_FALSE;
38001708Sstevel 		(void) pthread_cond_broadcast(&g_cv);
38011708Sstevel 		(void) pthread_mutex_unlock(&g_mutex);
38021708Sstevel 	} else {
38031708Sstevel 		if ((pthread_attr_init(&ledsthr_attr) != 0) ||
38041708Sstevel 		    (pthread_attr_setscope(&ledsthr_attr,
38051708Sstevel 		    PTHREAD_SCOPE_SYSTEM) != 0))
38061708Sstevel 			return;
38071708Sstevel 		if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr,
38081708Sstevel 		    disk_leds_thread, NULL)) != 0) {
38091708Sstevel 			syslog(LOG_ERR, EM_THREAD_CREATE_FAILED, strerror(err));
38101708Sstevel 			return;
38111708Sstevel 		}
38121708Sstevel 		ledsthr_created = B_TRUE;
38131708Sstevel 	}
38141708Sstevel 	for (i = 0; i < N_DISKS; i++) {
38151708Sstevel 		(void) set_led(lw8_disks[i].d_fruname, FAULT_LED,
38161708Sstevel 		    PICL_PROPVAL_OFF);
38171708Sstevel 	}
38181708Sstevel }
38191708Sstevel 
38201708Sstevel static void
disk_leds_fini(void)38211708Sstevel disk_leds_fini(void)
38221708Sstevel {
38231708Sstevel 	int	err;
38241708Sstevel 
38251708Sstevel 	/*
38261708Sstevel 	 * tell led thread to pause
38271708Sstevel 	 */
38281708Sstevel 	if (!ledsthr_created)
38291708Sstevel 		return;
38301708Sstevel 	err = pthread_mutex_lock(&g_mutex);
38311708Sstevel 	if (err != 0) {
38321708Sstevel 		syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
38331708Sstevel 		return;
38341708Sstevel 	}
38351708Sstevel 	g_wait_now = B_TRUE;
38361708Sstevel 	disk_leds_thread_ack = B_FALSE;
38371708Sstevel 	(void) pthread_cond_broadcast(&g_cv);
38381708Sstevel 
38391708Sstevel 	/*
38401708Sstevel 	 * and wait for the led thread to acknowledge
38411708Sstevel 	 */
38421708Sstevel 	while (!disk_leds_thread_ack) {
38431708Sstevel 		(void) pthread_cond_wait(&g_cv_ack, &g_mutex);
38441708Sstevel 	}
38451708Sstevel 	(void) pthread_mutex_unlock(&g_mutex);
38461708Sstevel }
38471708Sstevel 
38481708Sstevel static void
update_disk_node(struct lw8_disk * diskp)38491708Sstevel update_disk_node(struct lw8_disk *diskp)
38501708Sstevel {
38511708Sstevel 	picl_nodehdl_t slotndh;
38521708Sstevel 	picl_nodehdl_t diskndh;
38531708Sstevel 	picl_nodehdl_t devhdl;
38541708Sstevel 	picl_prophdl_t	tblhdl;
38551708Sstevel 	int err;
38561708Sstevel 	char path[MAXPATHLEN];
38571708Sstevel 	char *fruname = diskp->d_fruname;
38581708Sstevel 
38591708Sstevel 	sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
38601708Sstevel 	if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
38611708Sstevel 		return;
38621708Sstevel 	}
38631708Sstevel 	diskndh = find_child_by_name(slotndh, fruname);
38641708Sstevel 	err = ptree_get_node_by_path(diskp->d_plat_path, &devhdl);
38651708Sstevel 	if (err == PICL_SUCCESS) {
38661708Sstevel 		if (diskndh != NULL)
38671708Sstevel 			return;
38681708Sstevel 		err = ptree_create_and_add_node(slotndh, fruname,
38691708Sstevel 		    PICL_CLASS_FRU, &diskndh);
38701708Sstevel 		if (err != PICL_SUCCESS) {
38711708Sstevel 			syslog(LOG_ERR, ADD_NODE_FAIL, fruname, err);
38721708Sstevel 			return;
38731708Sstevel 		}
38741708Sstevel 		err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES);
38751708Sstevel 		if (err != PICL_SUCCESS)
38761708Sstevel 			return;
38771708Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
38781708Sstevel 		if (err != PICL_SUCCESS)
38791708Sstevel 			return;
38801708Sstevel 		err = add_prop_ref(devhdl, diskndh, PICL_REFPROP_FRU_PARENT);
38811708Sstevel 		if (err != PICL_SUCCESS)
38821708Sstevel 			return;
38831708Sstevel 	} else {
38841708Sstevel 		if (diskndh == NULL)
38851708Sstevel 			return;
38861708Sstevel 		err = ptree_delete_node(diskndh);
38871708Sstevel 		if (err != PICL_SUCCESS)
38881708Sstevel 			return;
38891708Sstevel 		(void) ptree_destroy_node(diskndh);
38901708Sstevel 	}
38911708Sstevel }
38921708Sstevel 
38931708Sstevel /*
38941708Sstevel  * Implement a state machine in order to:
38951708Sstevel  *
38961708Sstevel  *  o enable/disable disk LEDs
38971708Sstevel  *  o add/delete the disk's node in the FRU tree
38981708Sstevel  *
38991708Sstevel  * The machine changes state based on the current, in-memory
39001708Sstevel  * state of the disk (eg, the d_state field of 'struct lw8_disk')
39011708Sstevel  * and libdevice's current view of whether the disk is
39021708Sstevel  * Configured or Unconfigured.
39031708Sstevel  *
39041708Sstevel  * If the new state is the same as the previous state, then
39051708Sstevel  * no side effects occur.  Otherwise, the LEDs for the
39061708Sstevel  * disk are set and the disk's associated node in the
39071708Sstevel  * FRU Tree is added or deleted.
39081708Sstevel  */
39091708Sstevel static void
set_disk_leds(struct lw8_disk * disk)39101708Sstevel set_disk_leds(struct lw8_disk *disk)
39111708Sstevel {
39121708Sstevel 	devctl_hdl_t	dhdl;
39131708Sstevel 	uint_t		cur_state = 0;
39141708Sstevel 
39151708Sstevel 	dhdl = devctl_device_acquire(disk->d_devices_path, 0);
39161708Sstevel 	if (dhdl == NULL) {
39171708Sstevel 		int err = errno;
39181708Sstevel 		syslog(LOG_ERR, DEVCTL_DEVICE_ACQUIRE_FAILED,
39191708Sstevel 		    strerror(err));
39201708Sstevel 		return;
39211708Sstevel 	}
39221708Sstevel 	devctl_device_getstate(dhdl, &cur_state);
39231708Sstevel 	devctl_release(dhdl);
39241708Sstevel 
39251708Sstevel 	if ((cur_state & DEVICE_OFFLINE) != 0) {
39261708Sstevel 		switch (disk->d_state) {
39271708Sstevel 		default:
39281708Sstevel 			/*
39291708Sstevel 			 * State machine should never get here.
39301708Sstevel 			 * When NDEBUG is defined, control will
39311708Sstevel 			 * fall through and force d_state to
39321708Sstevel 			 * match the semantics of "DEVICE_OFFLINE".
39331708Sstevel 			 * During development, NDEBUG can be undefined,
39341708Sstevel 			 * and this will fire an assertion.
39351708Sstevel 			 */
39361708Sstevel 			assert(0);
39371708Sstevel 			/*FALLTHROUGH*/
39381708Sstevel 
39391708Sstevel 		case DISK_STATE_NOT_INIT:
39401708Sstevel 		case DISK_STATE_READY:
39411708Sstevel 			disk->d_state = DISK_STATE_NOT_READY;
39421708Sstevel 
39431708Sstevel 			(void) set_led(disk->d_fruname, POWER_LED,
39441708Sstevel 			    PICL_PROPVAL_OFF);
39451708Sstevel 			(void) set_led(disk->d_fruname, REMOK_LED,
39461708Sstevel 			    PICL_PROPVAL_ON);
39471708Sstevel 
39481708Sstevel 			update_disk_node(disk);
39491708Sstevel 			break;
39501708Sstevel 
39511708Sstevel 		case DISK_STATE_NOT_READY:
39521708Sstevel 			break;
39531708Sstevel 		}
39541708Sstevel 	} else if ((cur_state & DEVICE_ONLINE) != 0) {
39551708Sstevel 		switch (disk->d_state) {
39561708Sstevel 		default:
39571708Sstevel 			/*
39581708Sstevel 			 * State machine should never get here.
39591708Sstevel 			 * When NDEBUG is defined, control will
39601708Sstevel 			 * fall through and force d_state to
39611708Sstevel 			 * match the semantics of "DEVICE_ONLINE".
39621708Sstevel 			 * During development, NDEBUG can be undefined,
39631708Sstevel 			 * and this will fire an assertion.
39641708Sstevel 			 */
39651708Sstevel 			assert(0);
39661708Sstevel 			/*FALLTHROUGH*/
39671708Sstevel 
39681708Sstevel 		case DISK_STATE_NOT_INIT:
39691708Sstevel 		case DISK_STATE_NOT_READY:
39701708Sstevel 			disk->d_state = DISK_STATE_READY;
39711708Sstevel 
39721708Sstevel 			(void) set_led(disk->d_fruname, REMOK_LED,
39731708Sstevel 			    PICL_PROPVAL_OFF);
39741708Sstevel 			(void) set_led(disk->d_fruname, POWER_LED,
39751708Sstevel 			    PICL_PROPVAL_ON);
39761708Sstevel 
39771708Sstevel 			update_disk_node(disk);
39781708Sstevel 			break;
39791708Sstevel 
39801708Sstevel 		case DISK_STATE_READY:
39811708Sstevel 			break;
39821708Sstevel 		}
39831708Sstevel 	}
39841708Sstevel }
39851708Sstevel 
39861708Sstevel /*
39871708Sstevel  * NOTE: this implementation of disk_leds_thread is based on the version in
39881708Sstevel  * plugins/sun4u/mpxu/frudr/piclfrudr.c (with V440 raid support removed). Some
39891708Sstevel  * day the source code layout and build environment should support common code
39901708Sstevel  * used by platform specific plugins, in which case LW8 support could be added
39911708Sstevel  * to the mpxu version (which would be moved to a common directory).
39921708Sstevel  */
39931708Sstevel /*ARGSUSED*/
39941708Sstevel static void *
disk_leds_thread(void * args)39951708Sstevel disk_leds_thread(void *args)
39961708Sstevel {
39971708Sstevel 	int	i;
39981708Sstevel 	int	err = 0;
39991708Sstevel 	int	n_disks = N_DISKS;
40001708Sstevel 
40011708Sstevel 	static char *lw8_pci_devs[] = {
40021708Sstevel 		DISK0_BASE_PATH,
40031708Sstevel 		DISK1_BASE_PATH
40041708Sstevel 	};
40051708Sstevel 
40061708Sstevel 	static char *lw8_pcix_devs[] = {
40071708Sstevel 		DISK0_BASE_PATH_PCIX,
40081708Sstevel 		DISK1_BASE_PATH_PCIX
40091708Sstevel 	};
40101708Sstevel 
40111708Sstevel 	static char **lw8_devs;
40121708Sstevel 
40131708Sstevel 	if (pcix_io) {
40141708Sstevel 		lw8_devs = lw8_pcix_devs;
40151708Sstevel 	} else {
40161708Sstevel 		lw8_devs = lw8_pci_devs;
40171708Sstevel 	}
40181708Sstevel 
40191708Sstevel 	/*
40201708Sstevel 	 * create aliases for disk names
40211708Sstevel 	 */
40221708Sstevel 	for (i = 0; i < n_disks; i++) {
40231708Sstevel 		char buffer[MAXPATHLEN];
40241708Sstevel 
40251708Sstevel 		(void) snprintf(buffer, sizeof (buffer), "/devices%s",
40261708Sstevel 		    lw8_devs[i]);
40271708Sstevel 		lw8_disks[i].d_devices_path = strdup(buffer);
40281708Sstevel 
40291708Sstevel 		(void) snprintf(buffer, sizeof (buffer), "/platform%s",
40301708Sstevel 		    lw8_devs[i]);
40311708Sstevel 		lw8_disks[i].d_plat_path = strdup(buffer);
40321708Sstevel 	}
40331708Sstevel 
40341708Sstevel 	for (;;) {
40351708Sstevel 		for (i = 0; i < n_disks; i++) {
40361708Sstevel 			set_disk_leds(&lw8_disks[i]);
40371708Sstevel 		}
40381708Sstevel 
40391708Sstevel 		/*
40401708Sstevel 		 * wait a bit until we check again
40411708Sstevel 		 */
40421708Sstevel 		err = poll(NULL, 0, ledsthr_poll_period);
40431708Sstevel 		if (err == -1) {
40441708Sstevel 			err = errno;
40451708Sstevel 			syslog(LOG_ERR, EM_POLL_FAIL, strerror(err));
40461708Sstevel 			break;
40471708Sstevel 		}
40481708Sstevel 		err = pthread_mutex_lock(&g_mutex);
40491708Sstevel 		if (err != 0) {
40501708Sstevel 			syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
40511708Sstevel 			break;
40521708Sstevel 		}
40531708Sstevel 		if (g_wait_now != B_FALSE) {
40541708Sstevel 			/* notify _fini routine that we've paused */
40551708Sstevel 			disk_leds_thread_ack = B_TRUE;
40561708Sstevel 			(void) pthread_cond_signal(&g_cv_ack);
40571708Sstevel 			/* and go to sleep in case we get restarted */
40581708Sstevel 			while (g_wait_now != B_FALSE)
40591708Sstevel 				(void) pthread_cond_wait(&g_cv, &g_mutex);
40601708Sstevel 		}
40611708Sstevel 		(void) pthread_mutex_unlock(&g_mutex);
40621708Sstevel 	}
40631708Sstevel 	return ((void *)err);
40641708Sstevel }
4065