xref: /illumos-gate/usr/src/cmd/picl/plugins/sun4u/lw8/frutree/piclfrutree.c (revision ada2da53edc6b7d3afbdff4975c5c32c01a7c72d)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
2303831d35Sstevel  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel /*
2803831d35Sstevel  * This plugin-in creates the FRU Hierarchy for the
2903831d35Sstevel  * SUNW,Netra-T12 platform and manages the environmental sensors
3003831d35Sstevel  * on the platform.
3103831d35Sstevel  */
3203831d35Sstevel 
3303831d35Sstevel #include <stdio.h>
3403831d35Sstevel #include <errno.h>
3503831d35Sstevel #include <syslog.h>
3603831d35Sstevel #include <strings.h>
3703831d35Sstevel #include <libintl.h>
3803831d35Sstevel #include <stdlib.h>
3903831d35Sstevel #include <unistd.h>
4003831d35Sstevel #include <fcntl.h>
4103831d35Sstevel #include <picl.h>
4203831d35Sstevel #include <picltree.h>
4303831d35Sstevel #include <sys/stat.h>
4403831d35Sstevel #include <libnvpair.h>
4503831d35Sstevel #include <sys/param.h>
4603831d35Sstevel #include <kstat.h>
4703831d35Sstevel #include <config_admin.h>
4803831d35Sstevel #include <sys/sbd_ioctl.h>
4903831d35Sstevel #include <sys/sgfrutree.h>
5003831d35Sstevel #include <sys/sgenv.h>
5103831d35Sstevel #include <sys/ioccom.h>
5203831d35Sstevel #include <sys/lw8.h>
5303831d35Sstevel #include <sys/sysevent/dr.h>
5403831d35Sstevel #include <pthread.h>
5503831d35Sstevel #include <sys/obpdefs.h>
5603831d35Sstevel #include "libdevice.h"
5703831d35Sstevel #include "picldefs.h"
5803831d35Sstevel #define	NDEBUG
5903831d35Sstevel #include <assert.h>
6003831d35Sstevel 
6103831d35Sstevel /*
6203831d35Sstevel  * Plugin registration entry points
6303831d35Sstevel  */
6403831d35Sstevel static void	piclfrutree_register(void);
6503831d35Sstevel static void	piclfrutree_init(void);
6603831d35Sstevel static void	piclfrutree_fini(void);
6703831d35Sstevel #pragma	init(piclfrutree_register)
6803831d35Sstevel 
6903831d35Sstevel static picld_plugin_reg_t  my_reg_info = {
7003831d35Sstevel 	PICLD_PLUGIN_VERSION_1,
7103831d35Sstevel 	PICLD_PLUGIN_CRITICAL,
7203831d35Sstevel 	"SUNW_Netra-T12_frutree",
7303831d35Sstevel 	piclfrutree_init,
7403831d35Sstevel 	piclfrutree_fini,
7503831d35Sstevel };
7603831d35Sstevel 
7703831d35Sstevel /*
7803831d35Sstevel  * Log message texts
7903831d35Sstevel  */
8003831d35Sstevel #define	DEV_OPEN_FAIL gettext("piclfrutree_init: open of %s failed: %s")
8103831d35Sstevel #define	ADD_NODES_FAIL gettext("piclfrutree_init: add_all_nodes failed: %d")
8203831d35Sstevel #define	GET_ROOT_FAIL gettext("piclfrutree_init: ptree_get_root failed")
8303831d35Sstevel #define	ADD_FRUTREE_FAIL gettext("piclfrutree_init: add frutree failed")
8403831d35Sstevel #define	INVALID_PICL_CLASS gettext("add_subtree: invalid picl class 0x%x")
8503831d35Sstevel #define	ADD_NODE_FAIL gettext("ptree_create_and_add_node %s failed: %d")
8603831d35Sstevel #define	GET_NEXT_BY_ROW_FAIL gettext("ptree_get_next_by_row %s failed: %d")
8703831d35Sstevel #define	PROPINFO_FAIL gettext("ptree_init_propinfo %s failed: %d")
8803831d35Sstevel #define	GET_PROPVAL_FAIL gettext("ptree_get_propval failed: %d")
8903831d35Sstevel #define	DELETE_PROP_FAIL gettext("ptree_delete_prop failed: %d")
9003831d35Sstevel #define	DELETE_NODE_FAIL gettext("ptree_delete_node failed: %d")
9103831d35Sstevel #define	ADD_PROP_FAIL gettext("ptree_create_and_add_prop %s failed: %d")
9203831d35Sstevel #define	SGFRU_IOCTL_FAIL gettext("sgfru ioctl 0x%x handle 0x%llx failed: %s")
9303831d35Sstevel #define	LED_IOCTL_FAIL gettext("led ioctl failed: %s")
9403831d35Sstevel #define	MALLOC_FAIL gettext("piclfrutree: malloc failed")
9503831d35Sstevel #define	NO_SC_FAIL gettext("piclfrutree: cannot find sc node")
9603831d35Sstevel #define	NO_NODE_FAIL gettext("piclfrutree: cannot find node %s: %d")
9703831d35Sstevel #define	KSTAT_FAIL gettext("piclfrutree: failure accessing kstats")
9803831d35Sstevel #define	ADD_TBL_ENTRY_FAIL gettext("piclfrutree: cannot add entry to table")
9903831d35Sstevel #define	PROP_LOOKUP_FAIL gettext("piclfrutree: cannot find %s property: %d")
10003831d35Sstevel #define	EM_DI_INIT_FAIL	gettext("frutree: di_init failed: %s")
10103831d35Sstevel #define	EM_THREAD_CREATE_FAILED gettext("frutree: pthread_create failed: %s")
10203831d35Sstevel #define	EM_MUTEX_FAIL gettext("frutree: pthread_mutex_lock returned: %s")
10303831d35Sstevel #define	EM_POLL_FAIL gettext("frutree: poll() failed: %s")
10403831d35Sstevel #define	DEVCTL_DEVICE_ACQUIRE_FAILED \
10503831d35Sstevel     gettext("frutree: devctl_device_acquire() failed: %s")
10603831d35Sstevel 
10703831d35Sstevel /*
10803831d35Sstevel  * PICL property values
10903831d35Sstevel  */
11003831d35Sstevel #define	PICL_PROPVAL_TRUE		"true"
11103831d35Sstevel #define	PICL_PROPVAL_SYSTEM		"system"
11203831d35Sstevel #define	PICL_PROPVAL_ON			"ON"
11303831d35Sstevel #define	PICL_PROPVAL_OFF		"OFF"
11403831d35Sstevel #define	PICL_PROPVAL_BLINKING		"BLINKING"
11503831d35Sstevel #define	PICL_PROPVAL_FLASHING		"FLASHING"
11603831d35Sstevel #define	PICL_PROPVAL_CHASSIS		"chassis"
11703831d35Sstevel #define	PICL_PROPVAL_AMBIENT		"Ambient"
11803831d35Sstevel #define	PICL_PROPVAL_DIE		"Die"
11903831d35Sstevel #define	PICL_PROPVAL_GREEN		"green"
12003831d35Sstevel #define	PICL_PROPVAL_AMBER		"amber"
12103831d35Sstevel #define	PICL_PROPVAL_OKAY		"okay"
12203831d35Sstevel #define	PICL_PROPVAL_FAILED		"failed"
12303831d35Sstevel #define	PICL_PROPVAL_WARNING		"warning"
12403831d35Sstevel #define	PICL_PROPVAL_DISABLED		"disabled"
12503831d35Sstevel #define	PICL_PROPVAL_UNKNOWN		"unknown"
12603831d35Sstevel #define	PICL_PROPVAL_SELF_REGULATING	"self-regulating"
12703831d35Sstevel #define	PICL_PROPVAL_PER_CENT		"%"
12803831d35Sstevel #define	PICL_PROP_BANK_STATUS		"bank-status"
12903831d35Sstevel 
13003831d35Sstevel /*
13103831d35Sstevel  * PICL property names
13203831d35Sstevel  */
13303831d35Sstevel #define	PICL_PROP_LOW_WARNING_THRESHOLD	"LowWarningThreshold"
13403831d35Sstevel 
13503831d35Sstevel /*
13603831d35Sstevel  * Local defines
13703831d35Sstevel  */
13803831d35Sstevel #define	MAX_LINE_SIZE		1024
13903831d35Sstevel #define	MAX_TRIES		4
14003831d35Sstevel #define	MAX_SPEED_UNIT_LEN	20
14103831d35Sstevel #define	MAX_OPERATIONAL_STATUS_LEN	10
14203831d35Sstevel #define	MAX_CONDITION_LEN	10
14303831d35Sstevel #define	MAX_LABEL_LEN		256
14403831d35Sstevel #define	MAX_STATE_LEN		10
14503831d35Sstevel #define	MAX_STATE_SIZE		32
14603831d35Sstevel #define	LED_PSEUDO_DEV "/devices/pseudo/lw8@0:lw8"
14703831d35Sstevel #define	SC_DEV "/platform/ssm@0,0/pci@18,700000/bootbus-controller@4"
14803831d35Sstevel #define	SC_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/bootbus-controller@3"
14903831d35Sstevel #define	CPU_DEV "/platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0"
15003831d35Sstevel #define	CPU_DEV2 "/platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0"
15103831d35Sstevel #define	CPU_DEV3C0 "/platform/ssm@0,0/cmp@%x,0/cpu@0"
15203831d35Sstevel #define	CPU_DEV3C1 "/platform/ssm@0,0/cmp@%x,0/cpu@1"
15303831d35Sstevel #define	MEMORY_DEV "/platform/ssm@0,0/memory-controller@%x,400000"
15403831d35Sstevel #define	IO_DEV "/platform/ssm@0,0/pci@%s"
15503831d35Sstevel #define	DISK0_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@0,0"
15680ab886dSwesolows #define	DISK0_DEV "/platform" DISK0_BASE_PATH
15703831d35Sstevel #define	DISK1_BASE_PATH "/ssm@0,0/pci@18,600000/scsi@2/sd@1,0"
15880ab886dSwesolows #define	DISK1_DEV "/platform" DISK1_BASE_PATH
15903831d35Sstevel #define	DISK0_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@0,0"
16080ab886dSwesolows #define	DISK0_DEV_PCIX "/platform" DISK0_BASE_PATH_PCIX
16103831d35Sstevel #define	DISK1_BASE_PATH_PCIX "/ssm@0,0/pci@18,700000/scsi@2/sd@1,0"
16280ab886dSwesolows #define	DISK1_DEV_PCIX "/platform" DISK1_BASE_PATH_PCIX
16303831d35Sstevel #define	TAPE_DEV "/platform/ssm@0,0/pci@18,600000/scsi@2/st@5,0"
16403831d35Sstevel #define	TAPE_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/scsi@2/st@5,0"
16503831d35Sstevel #define	DVD_DEV "/platform/ssm@0,0/pci@18,700000/ide@3/sd@0,0"
16603831d35Sstevel #define	DVD_DEV_PCIX "/platform/ssm@0,0/pci@18,700000/pci@4/ide@2/sd@0,0"
16703831d35Sstevel #define	CHASSIS_PATH "/frutree/chassis"
16803831d35Sstevel #define	CHASSIS_LOC_PATH "/frutree/chassis/%s"
16903831d35Sstevel #define	PROC_LOC_PATH "/frutree/chassis/SB%d/SB%d/P%d"
17003831d35Sstevel #define	PROC_FRU_PATH "/frutree/chassis/SB%d/SB%d/P%d/P%d"
17103831d35Sstevel /*
17203831d35Sstevel  * Calculate safari address to put in CPU_DEV/MEMORY_DEV string based on
17303831d35Sstevel  * SBx/Py fru path name
17403831d35Sstevel  */
17503831d35Sstevel #define	SB_P_TO_SAFARI_ADDR(sbname, pname) \
17603831d35Sstevel 	((pname[1] - '0') + (4 * (sbname[2] - '0')))
17703831d35Sstevel #define	SAFARI_ADDR_TO_SB(value) (value >> 2)
17803831d35Sstevel #define	SAFARI_ADDR_TO_P(value) (value & 3)
17903831d35Sstevel #define	AP_ID_PREAMBLE "ssm0:N0."
18003831d35Sstevel #define	AP_ID_PREAMBLE_LEN 8
18103831d35Sstevel #define	LABEL_PREAMBLE "N0/"
18203831d35Sstevel #define	LABEL_PREAMBLE_LEN 3
18303831d35Sstevel /*
18403831d35Sstevel  * work out type of fru based on name
18503831d35Sstevel  */
18603831d35Sstevel #define	IS_ECACHE_NODE(name)	(name[0] == 'E')
18703831d35Sstevel #define	IS_DIMM_NODE(name)	(name[0] == 'D' && name[1] != 'V')
18803831d35Sstevel #define	IS_PROC_NODE(name)	(name[0] == 'P' && name[1] != 'S')
18903831d35Sstevel #define	IS_PSU_NODE(name)	(name[0] == 'P' && name[1] == 'S')
19003831d35Sstevel #define	IS_SB_NODE(name)	(name[0] == 'S' && name[1] == 'B')
19103831d35Sstevel #define	IS_IB_NODE(name)	(name[0] == 'I')
19203831d35Sstevel #define	IS_FT_NODE(name)	(name[0] == 'F' && name[1] == 'T')
19303831d35Sstevel #define	IS_FAN_NODE(name)	(name[0] == 'F' && name[1] != 'T')
19403831d35Sstevel #define	IS_RP_NODE(name)	(name[0] == 'R')
19503831d35Sstevel /*
19603831d35Sstevel  * rename sgfru driver's node_t to sgfrunode_t to avoid confusion
19703831d35Sstevel  */
19803831d35Sstevel #define	sgfrunode_t node_t
19903831d35Sstevel 
20003831d35Sstevel /*
20103831d35Sstevel  * disk_led data
20203831d35Sstevel  */
20303831d35Sstevel #define	REMOK_LED "ok_to_remove"
20403831d35Sstevel #define	FAULT_LED "fault"
20503831d35Sstevel #define	POWER_LED "power"
20603831d35Sstevel 
20703831d35Sstevel /*
20803831d35Sstevel  * 'struct lw8_disk' contains the per-disk metadata needed to
20903831d35Sstevel  * manage the current state of one of the internal disks.
21003831d35Sstevel  *
21103831d35Sstevel  * 'lw8_disks[]' is an array that contains the metadata
21203831d35Sstevel  * for N_DISKS disks.
21303831d35Sstevel  *
21403831d35Sstevel  * The d_fruname field of 'struct lw8_disk' is static.
21503831d35Sstevel  * d_plat_path and d_devices_path are aliases for device-paths
21603831d35Sstevel  * to the disk.  They are logically static, as they are computed
21703831d35Sstevel  * when the disk_leds_thread() thread does its initialization.
21803831d35Sstevel  *
21903831d35Sstevel  * d_state is the most interesting field, as it changes
22003831d35Sstevel  * dynamically, based on whether the associated disk
22103831d35Sstevel  * is currently Configured or Unconfigured (by DR).  d_state
22203831d35Sstevel  * is an optimization that minimizes per-disk actions such
22303831d35Sstevel  * as setting of LEDs and updating the FRU Tree.
22403831d35Sstevel  *
22503831d35Sstevel  * A disk starts in a d_state of DISK_STATE_NOT_INIT
22603831d35Sstevel  * and moves to DISK_STATE_READY when the disk is
22703831d35Sstevel  * Configured (by DR) and it moves to DISK_STATE_NOT_READY
22803831d35Sstevel  * when it is Unconfigured (by DR).
22903831d35Sstevel  */
23003831d35Sstevel typedef enum {
23103831d35Sstevel 	DISK_STATE_NOT_INIT,
23203831d35Sstevel 	DISK_STATE_READY,
23303831d35Sstevel 	DISK_STATE_NOT_READY
23403831d35Sstevel } disk_state_t;
23503831d35Sstevel 
23603831d35Sstevel struct lw8_disk {
23703831d35Sstevel 	char		*d_fruname;		/* FRU name */
23803831d35Sstevel 	char		*d_plat_path;		/* /platform */
23903831d35Sstevel 	char		*d_devices_path;	/* /devices */
24003831d35Sstevel 	disk_state_t	d_state;
24103831d35Sstevel };
24203831d35Sstevel 
24303831d35Sstevel #define	N_DISKS 2
24403831d35Sstevel static	struct lw8_disk	lw8_disks[N_DISKS] = {
24503831d35Sstevel 	{"DISK0", NULL, NULL, DISK_STATE_NOT_INIT},
24603831d35Sstevel 	{"DISK1", NULL, NULL, DISK_STATE_NOT_INIT} };
24703831d35Sstevel 
24803831d35Sstevel /* Duration of inactivity within disk_leds_thread() */
24903831d35Sstevel #define	THR_POLL_PERIOD 5000    /* milliseconds */
25003831d35Sstevel 
25103831d35Sstevel static volatile boolean_t	disk_leds_thread_ack = B_FALSE;
25203831d35Sstevel static pthread_t		ledsthr_tid;
25303831d35Sstevel static pthread_attr_t		ledsthr_attr;
25403831d35Sstevel static boolean_t		ledsthr_created = B_FALSE;
25503831d35Sstevel static uint_t			ledsthr_poll_period =
25603831d35Sstevel 				    THR_POLL_PERIOD;
25703831d35Sstevel static boolean_t		g_mutex_init = B_FALSE;
25803831d35Sstevel static pthread_cond_t		g_cv;
25903831d35Sstevel static pthread_cond_t		g_cv_ack;
26003831d35Sstevel static pthread_mutex_t		g_mutex;
26103831d35Sstevel static volatile boolean_t	g_wait_now = B_FALSE;
26203831d35Sstevel 
26303831d35Sstevel static void disk_leds_init(void);
26403831d35Sstevel static void disk_leds_fini(void);
26503831d35Sstevel static void *disk_leds_thread(void *args);
26603831d35Sstevel 
26703831d35Sstevel /*
26803831d35Sstevel  * Tables to convert sgenv information
26903831d35Sstevel  */
27003831d35Sstevel static char *hpu_type_table[] = { "", "SSC", "SB", "RP", "FT",
27103831d35Sstevel 	"IB", "PS", "ID"};
27203831d35Sstevel static char *hpu_fru_type_table[] = { "", "SSC", "CPU", "RP", "FT",
27303831d35Sstevel 	"PCIB", "PS", "ID"};
27403831d35Sstevel static char *hpu_part_table[] = { "", "sbbc", "sdc",
27503831d35Sstevel 	"ar", "cbh", "dx", "cheetah", "1.5vdc", "3.3vdc",
27603831d35Sstevel 	"5vdc", "12vdc", "output", "current", "board", "sc-app",
27703831d35Sstevel 	"schizo", "fan", "input"};
27803831d35Sstevel static char *hpu_sensor_table[] = { "", "", "current",
27903831d35Sstevel 	"temp", "cooling", "1.5vdc", "1.8vdc", "3.3vdc", "5vdc",
28003831d35Sstevel 	"12vdc", "48vdc", NULL, "2.4vdc"};
28103831d35Sstevel static char *hpu_sensor_class_table[] = { "", "", PICL_CLASS_CURRENT_SENSOR,
28203831d35Sstevel 	PICL_CLASS_TEMPERATURE_SENSOR, PICL_CLASS_FAN,
28303831d35Sstevel 	PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR,
28403831d35Sstevel 	PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_SENSOR,
28503831d35Sstevel 	PICL_CLASS_VOLTAGE_SENSOR, PICL_CLASS_VOLTAGE_INDICATOR,
28603831d35Sstevel 	NULL, PICL_CLASS_VOLTAGE_SENSOR};
28703831d35Sstevel static char *hpu_sensor_prop_table[] = { "", "", PICL_PROP_CURRENT,
28803831d35Sstevel 	PICL_PROP_TEMPERATURE, PICL_PROP_FAN_SPEED, PICL_PROP_VOLTAGE,
28903831d35Sstevel 	PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE, PICL_PROP_VOLTAGE,
29003831d35Sstevel 	PICL_PROP_VOLTAGE, PICL_PROP_CONDITION, NULL, PICL_PROP_VOLTAGE};
29103831d35Sstevel static char *hpu_condition_table[] = {"unknown", "okay", "failing",
29203831d35Sstevel 	"failed", "unusable"};
29303831d35Sstevel 
29403831d35Sstevel /*
29503831d35Sstevel  * variables set up in init
29603831d35Sstevel  */
29703831d35Sstevel static picl_nodehdl_t	frutreeh;
298*ada2da53SToomas Soome static picl_nodehdl_t	sch = 0;
29903831d35Sstevel static int init_complete;
30003831d35Sstevel static int pcix_io = 0;
30103831d35Sstevel 
30203831d35Sstevel /*
30303831d35Sstevel  * forward reference
30403831d35Sstevel  */
30503831d35Sstevel static int add_all_nodes(void);
30603831d35Sstevel static int remove_subtree(picl_nodehdl_t parh);
30703831d35Sstevel static int add_subtree(picl_nodehdl_t parh, fru_hdl_t fruparent);
30803831d35Sstevel static int add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
30903831d35Sstevel     picl_nodehdl_t *childp);
31003831d35Sstevel static int add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
31103831d35Sstevel     picl_nodehdl_t *childp);
31203831d35Sstevel static int add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
31303831d35Sstevel     picl_nodehdl_t *childp);
31403831d35Sstevel static int add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
31503831d35Sstevel     picl_nodehdl_t *childp);
31603831d35Sstevel static int add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
31703831d35Sstevel     picl_prophdl_t tblhdl);
31803831d35Sstevel static int add_env_nodes(picl_nodehdl_t nodeh, char *nodename,
31903831d35Sstevel     picl_prophdl_t tblhdl);
32003831d35Sstevel static int add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
32103831d35Sstevel     picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name);
32203831d35Sstevel static int add_intermediate_location(picl_nodehdl_t *nodep, char *labelp,
32303831d35Sstevel     char *slot_name);
32403831d35Sstevel static int add_pci_location(picl_nodehdl_t childh, char *parent_addr,
32503831d35Sstevel     char bus_addr, char *slot_name);
32603831d35Sstevel static picl_nodehdl_t find_child_by_name(picl_nodehdl_t parh, char *name);
32703831d35Sstevel static int create_dimm_references(picl_nodehdl_t parh, int dimm_id,
32803831d35Sstevel     picl_nodehdl_t nodeh, picl_prophdl_t tblhdl);
32903831d35Sstevel static int create_cpu_references(char *pname, picl_nodehdl_t nodeh,
33003831d35Sstevel     picl_prophdl_t tblhdl);
33103831d35Sstevel static void post_frudr_event(char *ename, picl_nodehdl_t parenth,
33203831d35Sstevel     picl_nodehdl_t fruh);
33303831d35Sstevel static int remove_references(picl_prophdl_t refprop, char *class);
33403831d35Sstevel static int remove_picl_node(picl_nodehdl_t nodeh);
33503831d35Sstevel static sgfrunode_t *get_node_children(fru_hdl_t fruparent, int *num_childrenp);
33603831d35Sstevel static int add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name);
33703831d35Sstevel static int add_prop_void(picl_nodehdl_t nodeh, char *name);
33803831d35Sstevel static int add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name);
33903831d35Sstevel static int add_prop_int(picl_nodehdl_t nodeh, int value, char *name);
34003831d35Sstevel static int add_prop_float(picl_nodehdl_t nodeh, float value, char *name);
34103831d35Sstevel static int add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name);
34203831d35Sstevel static void frudr_evhandler(const char *ename, const void *earg,
34303831d35Sstevel     size_t size, void *cookie);
34403831d35Sstevel static void frumemcfg_evhandler(const char *ename, const void *earg,
34503831d35Sstevel     size_t size, void *cookie);
34603831d35Sstevel static int add_sensor_prop(picl_nodehdl_t nodeh, char *class);
34703831d35Sstevel static int add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl,
34803831d35Sstevel     char *nodename, char *class, char *prop_class,
34903831d35Sstevel     picl_prophdl_t tblhdl, picl_nodehdl_t *sensorhdlp);
35003831d35Sstevel static int create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp,
35103831d35Sstevel     char *tbl_name);
35203831d35Sstevel static int create_table_entry(picl_prophdl_t tblhdl,
35303831d35Sstevel     picl_nodehdl_t refhdl, char *class);
35403831d35Sstevel static int get_sensor_data(ptree_rarg_t *arg, void *result);
35503831d35Sstevel static int get_led(char *name, char *ptr, char *result);
35603831d35Sstevel static int get_led_data(ptree_rarg_t *arg, void *result);
35703831d35Sstevel static int set_led_data(ptree_warg_t *arg, const void *value);
35803831d35Sstevel static int get_cpu_status(ptree_rarg_t *arg, void *result);
35903831d35Sstevel static int add_board_status(picl_nodehdl_t nodeh, char *nodename);
36003831d35Sstevel static int get_board_status(ptree_rarg_t *arg, void *result);
36103831d35Sstevel static int get_op_status(ptree_rarg_t *arg, void *result);
36203831d35Sstevel 
36303831d35Sstevel #define	sprintf_buf2(buf, a1, a2) (void) snprintf(buf, sizeof (buf), a1, a2)
36403831d35Sstevel #define	sprintf_buf3(buf, a1, a2, a3) \
36503831d35Sstevel 	(void) snprintf(buf, sizeof (buf), a1, a2, a3)
36603831d35Sstevel #define	sprintf_buf4(buf, a1, a2, a3, a4) \
36703831d35Sstevel 	(void) snprintf(buf, sizeof (buf), a1, a2, a3, a4)
36803831d35Sstevel #define	sprintf_buf5(buf, a1, a2, a3, a4, a5) \
36903831d35Sstevel 	(void) snprintf(buf, sizeof (buf), a1, a2, a3, a4, a5)
37003831d35Sstevel /*
37103831d35Sstevel  * This function is executed as part of .init when the plugin is
37203831d35Sstevel  * dlopen()ed
37303831d35Sstevel  */
37403831d35Sstevel static void
piclfrutree_register(void)37503831d35Sstevel piclfrutree_register(void)
37603831d35Sstevel {
37703831d35Sstevel 	(void) picld_plugin_register(&my_reg_info);
37803831d35Sstevel }
37903831d35Sstevel 
38003831d35Sstevel /*
38103831d35Sstevel  * This function is the init entry point of the plugin.
38203831d35Sstevel  * It initializes the /frutree tree
38303831d35Sstevel  */
38403831d35Sstevel static void
piclfrutree_init(void)38503831d35Sstevel piclfrutree_init(void)
38603831d35Sstevel {
38703831d35Sstevel 	int err;
38803831d35Sstevel 
38903831d35Sstevel 	(void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
39003831d35Sstevel 	    frudr_evhandler, NULL);
39103831d35Sstevel 	(void) ptree_register_handler(PICLEVENT_MC_ADDED,
39203831d35Sstevel 	    frumemcfg_evhandler, NULL);
39303831d35Sstevel 	(void) ptree_register_handler(PICLEVENT_MC_REMOVED,
39403831d35Sstevel 	    frumemcfg_evhandler, NULL);
39503831d35Sstevel 	init_complete = 0;
39603831d35Sstevel 
39703831d35Sstevel 	err = add_all_nodes();
39803831d35Sstevel 	disk_leds_init();
39903831d35Sstevel 	init_complete = 1;
40003831d35Sstevel 	if (err != PICL_SUCCESS) {
40103831d35Sstevel 		syslog(LOG_ERR, ADD_NODES_FAIL, err);
40203831d35Sstevel 		piclfrutree_fini();
40303831d35Sstevel 	}
40403831d35Sstevel }
40503831d35Sstevel 
40603831d35Sstevel /*
40703831d35Sstevel  * This function is the fini entry point of the plugin.
40803831d35Sstevel  */
40903831d35Sstevel static void
piclfrutree_fini(void)41003831d35Sstevel piclfrutree_fini(void)
41103831d35Sstevel {
41203831d35Sstevel 	(void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
41303831d35Sstevel 	    frudr_evhandler, NULL);
41403831d35Sstevel 	(void) ptree_unregister_handler(PICLEVENT_MC_ADDED,
41503831d35Sstevel 	    frumemcfg_evhandler, NULL);
41603831d35Sstevel 	(void) ptree_unregister_handler(PICLEVENT_MC_REMOVED,
41703831d35Sstevel 	    frumemcfg_evhandler, NULL);
41803831d35Sstevel 	(void) remove_subtree(frutreeh);
41903831d35Sstevel 	disk_leds_fini();
42003831d35Sstevel }
42103831d35Sstevel 
42203831d35Sstevel /*
42303831d35Sstevel  * called from piclfrutree_init() to initialise picl frutree
42403831d35Sstevel  */
42503831d35Sstevel static int
add_all_nodes(void)42603831d35Sstevel add_all_nodes(void)
42703831d35Sstevel {
42803831d35Sstevel 	int err;
42903831d35Sstevel 	picl_nodehdl_t rooth;
43003831d35Sstevel 
43103831d35Sstevel 	/* Get the root node of the PICL tree */
43203831d35Sstevel 	err = ptree_get_root(&rooth);
43303831d35Sstevel 	if (err != PICL_SUCCESS) {
43403831d35Sstevel 		syslog(LOG_ERR, GET_ROOT_FAIL);
43503831d35Sstevel 		return (err);
43603831d35Sstevel 	}
43703831d35Sstevel 
43803831d35Sstevel 	/* find sc node so we can create sensor nodes under it */
43903831d35Sstevel 
44003831d35Sstevel 	err = ptree_get_node_by_path(SC_DEV, &sch);
44103831d35Sstevel 	if (err != PICL_SUCCESS) {
44203831d35Sstevel 
44303831d35Sstevel 		/*
44403831d35Sstevel 		 * There is a XMITS/PCI-X IO Board assembly implements
44503831d35Sstevel 		 * a different path for the the bootbus controller.
44603831d35Sstevel 		 */
44703831d35Sstevel 		err = ptree_get_node_by_path(SC_DEV_PCIX, &sch);
44803831d35Sstevel 		if (err == PICL_SUCCESS)
44903831d35Sstevel 			pcix_io = 1;
45003831d35Sstevel 	}
45103831d35Sstevel 
45203831d35Sstevel 	if (err != PICL_SUCCESS) {
45303831d35Sstevel 		syslog(LOG_ERR, NO_SC_FAIL);
45403831d35Sstevel 		return (err);
45503831d35Sstevel 	}
45603831d35Sstevel 
45703831d35Sstevel 	/* Create and add the root node of the FRU subtree */
45803831d35Sstevel 	err = ptree_create_and_add_node(rooth, PICL_NODE_FRUTREE,
45903831d35Sstevel 	    PICL_CLASS_PICL, &frutreeh);
46003831d35Sstevel 	if (err != PICL_SUCCESS) {
46103831d35Sstevel 		syslog(LOG_ERR, ADD_FRUTREE_FAIL);
46203831d35Sstevel 		return (err);
46303831d35Sstevel 	}
46403831d35Sstevel 
46503831d35Sstevel 	/* Recursively query the SC and add frutree nodes */
46603831d35Sstevel 	return (add_subtree(frutreeh, ROOTPARENT));
46703831d35Sstevel }
46803831d35Sstevel 
46903831d35Sstevel /*
47003831d35Sstevel  * Recursive routine to add picl nodes to the frutree. Called from
47103831d35Sstevel  * add_all_nodes() for the whole frutree at initialisation, and from
47203831d35Sstevel  * frudr_evhandler() for portions of the frutree on DR insert events
47303831d35Sstevel  */
47403831d35Sstevel static int
add_subtree(picl_nodehdl_t parh,fru_hdl_t handle)47503831d35Sstevel add_subtree(picl_nodehdl_t parh, fru_hdl_t handle)
47603831d35Sstevel {
47703831d35Sstevel 	int	err, i;
47803831d35Sstevel 	int	num_children;
47903831d35Sstevel 	sgfrunode_t	*cp, *fruchildren = NULL;
48003831d35Sstevel 	picl_nodehdl_t childh;
48103831d35Sstevel 
48203831d35Sstevel 	/* find children of the parent node */
48303831d35Sstevel 	fruchildren = get_node_children(handle, &num_children);
48403831d35Sstevel 	if (fruchildren == NULL)
48503831d35Sstevel 		return (PICL_FAILURE);
48603831d35Sstevel 
48703831d35Sstevel 	/* for each child, add a new picl node */
48803831d35Sstevel 	for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
48903831d35Sstevel 		/*
49003831d35Sstevel 		 * Add the appropriate PICL class
49103831d35Sstevel 		 */
49203831d35Sstevel 		childh = 0;
49303831d35Sstevel 		err = add_picl_node(parh, cp, &childh);
49403831d35Sstevel 		if (err == PICL_NOTNODE)
49503831d35Sstevel 			continue;
49603831d35Sstevel 		if (err != PICL_SUCCESS) {
49703831d35Sstevel 			free(fruchildren);
49803831d35Sstevel 			return (err);
49903831d35Sstevel 		}
50003831d35Sstevel 
50103831d35Sstevel 		/*
50203831d35Sstevel 		 * Recursively call this function based on has_children hint
50303831d35Sstevel 		 */
50403831d35Sstevel 		if (childh && cp->has_children) {
50503831d35Sstevel 			err = add_subtree(childh, cp->handle);
50603831d35Sstevel 			if (err != PICL_SUCCESS) {
50703831d35Sstevel 				free(fruchildren);
50803831d35Sstevel 				return (err);
50903831d35Sstevel 			}
51003831d35Sstevel 		}
51103831d35Sstevel 	}
51203831d35Sstevel 	free(fruchildren);
51303831d35Sstevel 	return (PICL_SUCCESS);
51403831d35Sstevel }
51503831d35Sstevel 
51603831d35Sstevel /*
51703831d35Sstevel  * Recursive routine to remove picl nodes to the frutree. Called from
51803831d35Sstevel  * piclfrutree_fini() for the whole frutree at termination, and from
51903831d35Sstevel  * frudr_completion_handler() for portions of the frutree on DR remove events
52003831d35Sstevel  */
52103831d35Sstevel static int
remove_subtree(picl_nodehdl_t parh)52203831d35Sstevel remove_subtree(picl_nodehdl_t parh)
52303831d35Sstevel {
52403831d35Sstevel 	picl_nodehdl_t chdh;
52503831d35Sstevel 
52603831d35Sstevel 	for (;;) {
52703831d35Sstevel 		if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh,
52803831d35Sstevel 		    sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
52903831d35Sstevel 			if (remove_subtree(chdh) != PICL_SUCCESS)
53003831d35Sstevel 				return (PICL_FAILURE);
53103831d35Sstevel 		} else {
53203831d35Sstevel 			return (remove_picl_node(parh));
53303831d35Sstevel 		}
53403831d35Sstevel 	}
53503831d35Sstevel 	/* NOTREACHED */
53603831d35Sstevel }
53703831d35Sstevel 
53803831d35Sstevel /*
53903831d35Sstevel  * Add fru and location nodes with SC_handle property
54003831d35Sstevel  * (aka, container handle, for frus).
54103831d35Sstevel  * Return picl_nodehdl of created node in *childp.
54203831d35Sstevel  */
54303831d35Sstevel static int
add_picl_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)54403831d35Sstevel add_picl_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
54503831d35Sstevel     picl_nodehdl_t *childp)
54603831d35Sstevel {
54703831d35Sstevel 	switch (sgfrunode->class) {
54803831d35Sstevel 	case PSEUDO_FRU_CLASS:
54903831d35Sstevel 		return (add_chassis_node(parh, sgfrunode, childp));
55003831d35Sstevel 
55103831d35Sstevel 	case FRU_CLASS:
55203831d35Sstevel 		return (add_fru_node(parh, sgfrunode, childp));
55303831d35Sstevel 
55403831d35Sstevel 	case LOCATION_CLASS:
55503831d35Sstevel 		return (add_location_node(parh, sgfrunode, childp));
55603831d35Sstevel 
55703831d35Sstevel 	default:
55803831d35Sstevel 		syslog(LOG_ERR, INVALID_PICL_CLASS, sgfrunode->class);
55903831d35Sstevel 		return (PICL_NOTNODE);
56003831d35Sstevel 	}
56103831d35Sstevel }
56203831d35Sstevel 
56303831d35Sstevel /*
56403831d35Sstevel  * create chassis node
56503831d35Sstevel  */
56603831d35Sstevel static int
add_chassis_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)56703831d35Sstevel add_chassis_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
56803831d35Sstevel     picl_nodehdl_t *childp)
56903831d35Sstevel {
57003831d35Sstevel 	int err;
57103831d35Sstevel 	uint64_t handle = (uint64_t)sgfrunode->handle;
57203831d35Sstevel 	picl_prophdl_t	tblhdl;
57303831d35Sstevel 	picl_nodehdl_t nodeh;
57403831d35Sstevel 	picl_nodehdl_t devhdl;
57503831d35Sstevel 	picl_nodehdl_t childh;
57603831d35Sstevel 
57703831d35Sstevel 	err = ptree_create_and_add_node(parh, PICL_PROPVAL_CHASSIS,
57803831d35Sstevel 	    PICL_CLASS_FRU, &childh);
57903831d35Sstevel 	if (err != PICL_SUCCESS) {
58003831d35Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, PICL_PROPVAL_CHASSIS, err);
58103831d35Sstevel 		return (err);
58203831d35Sstevel 	}
58303831d35Sstevel 	err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
58403831d35Sstevel 	if (err != PICL_SUCCESS)
58503831d35Sstevel 		return (err);
58603831d35Sstevel 
58703831d35Sstevel 	/*
58803831d35Sstevel 	 * add devices table to chassis node (may need references
58903831d35Sstevel 	 * to led devices)
59003831d35Sstevel 	 */
59103831d35Sstevel 	err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
59203831d35Sstevel 	if (err != PICL_SUCCESS)
59303831d35Sstevel 		return (err);
59403831d35Sstevel 
59503831d35Sstevel 	err = add_led_nodes(childh, "chassis", LOM_LED_POSITION_FRU, tblhdl);
59603831d35Sstevel 	if (err != PICL_SUCCESS)
59703831d35Sstevel 		return (err);
59803831d35Sstevel 
59903831d35Sstevel 	if (pcix_io)
60003831d35Sstevel 		err = ptree_get_node_by_path(DISK0_DEV_PCIX, &devhdl);
60103831d35Sstevel 	else
60203831d35Sstevel 		err = ptree_get_node_by_path(DISK0_DEV, &devhdl);
60303831d35Sstevel 
60403831d35Sstevel 	nodeh = childh;
60503831d35Sstevel 	if (err != PICL_SUCCESS) {
60603831d35Sstevel 		err = add_intermediate_location(&nodeh, "DISK0", "disk-slot");
60703831d35Sstevel 	} else {
60803831d35Sstevel 		err = add_intermediate_nodes(&nodeh, "DISK0", &tblhdl,
60903831d35Sstevel 		    "disk-slot", NULL);
61003831d35Sstevel 		if (err != PICL_SUCCESS)
61103831d35Sstevel 			return (err);
61203831d35Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
61303831d35Sstevel 		if (err != PICL_SUCCESS)
61403831d35Sstevel 			return (err);
61503831d35Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
61603831d35Sstevel 	}
61703831d35Sstevel 	if (err != PICL_SUCCESS)
61803831d35Sstevel 		return (err);
61903831d35Sstevel 
62003831d35Sstevel 	if (pcix_io)
62103831d35Sstevel 		err = ptree_get_node_by_path(DISK1_DEV_PCIX, &devhdl);
62203831d35Sstevel 	else
62303831d35Sstevel 		err = ptree_get_node_by_path(DISK1_DEV, &devhdl);
62403831d35Sstevel 
62503831d35Sstevel 	nodeh = childh;
62603831d35Sstevel 	if (err != PICL_SUCCESS) {
62703831d35Sstevel 		err = add_intermediate_location(&nodeh, "DISK1", "disk-slot");
62803831d35Sstevel 	} else {
62903831d35Sstevel 		err = add_intermediate_nodes(&nodeh, "DISK1", &tblhdl,
63003831d35Sstevel 		    "disk-slot", NULL);
63103831d35Sstevel 		if (err != PICL_SUCCESS)
63203831d35Sstevel 			return (err);
63303831d35Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
63403831d35Sstevel 		if (err != PICL_SUCCESS)
63503831d35Sstevel 			return (err);
63603831d35Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
63703831d35Sstevel 	}
63803831d35Sstevel 	if (err != PICL_SUCCESS)
63903831d35Sstevel 		return (err);
64003831d35Sstevel 
64103831d35Sstevel 	if (pcix_io)
64203831d35Sstevel 		err = ptree_get_node_by_path(TAPE_DEV_PCIX, &devhdl);
64303831d35Sstevel 	else
64403831d35Sstevel 		err = ptree_get_node_by_path(TAPE_DEV, &devhdl);
64503831d35Sstevel 
64603831d35Sstevel 	nodeh = childh;
64703831d35Sstevel 	if (err != PICL_SUCCESS) {
64803831d35Sstevel 		err = add_intermediate_location(&nodeh, "TAPE", "tape-slot");
64903831d35Sstevel 	} else {
65003831d35Sstevel 		err = add_intermediate_nodes(&nodeh, "TAPE", &tblhdl,
65103831d35Sstevel 		    "tape-slot", NULL);
65203831d35Sstevel 		if (err != PICL_SUCCESS)
65303831d35Sstevel 			return (err);
65403831d35Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
65503831d35Sstevel 		if (err != PICL_SUCCESS)
65603831d35Sstevel 			return (err);
65703831d35Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_TAPE);
65803831d35Sstevel 	}
65903831d35Sstevel 	if (err != PICL_SUCCESS)
66003831d35Sstevel 		return (err);
66103831d35Sstevel 
66203831d35Sstevel 	if (pcix_io)
66303831d35Sstevel 		err = ptree_get_node_by_path(DVD_DEV_PCIX, &devhdl);
66403831d35Sstevel 	else
66503831d35Sstevel 		err = ptree_get_node_by_path(DVD_DEV, &devhdl);
66603831d35Sstevel 
66703831d35Sstevel 	nodeh = childh;
66803831d35Sstevel 	if (err != PICL_SUCCESS) {
66903831d35Sstevel 		err = add_intermediate_location(&nodeh, "DVD", "dvd-slot");
67003831d35Sstevel 	} else {
67103831d35Sstevel 		err = add_intermediate_nodes(&nodeh, "DVD", &tblhdl,
67203831d35Sstevel 		    "dvd-slot", NULL);
67303831d35Sstevel 		if (err != PICL_SUCCESS)
67403831d35Sstevel 			return (err);
67503831d35Sstevel 		err = add_prop_ref(devhdl, nodeh, PICL_REFPROP_FRU_PARENT);
67603831d35Sstevel 		if (err != PICL_SUCCESS)
67703831d35Sstevel 			return (err);
67803831d35Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_CDROM);
67903831d35Sstevel 	}
68003831d35Sstevel 	if (err != PICL_SUCCESS)
68103831d35Sstevel 		return (err);
68203831d35Sstevel 
68303831d35Sstevel 	if (pcix_io) {
68403831d35Sstevel 		/*
68503831d35Sstevel 		 * The XMITS/PCI-X IO Assembly is layed out a bit differently.
68603831d35Sstevel 		 */
68703831d35Sstevel 		err = add_pci_location(childh, "19,600000", '1', "PCI0");
68803831d35Sstevel 		if (err != PICL_SUCCESS)
68903831d35Sstevel 			return (err);
69003831d35Sstevel 		err = add_pci_location(childh, "19,600000", '2', "PCI1");
69103831d35Sstevel 		if (err != PICL_SUCCESS)
69203831d35Sstevel 			return (err);
69303831d35Sstevel 		err = add_pci_location(childh, "19,700000", '1', "PCI2");
69403831d35Sstevel 		if (err != PICL_SUCCESS)
69503831d35Sstevel 			return (err);
69603831d35Sstevel 		err = add_pci_location(childh, "19,700000", '2', "PCI3");
69703831d35Sstevel 		if (err != PICL_SUCCESS)
69803831d35Sstevel 			return (err);
69903831d35Sstevel 		err = add_pci_location(childh, "18,600000", '1', "PCI4");
70003831d35Sstevel 		if (err != PICL_SUCCESS)
70103831d35Sstevel 			return (err);
70203831d35Sstevel 		err = add_pci_location(childh, "18,600000", '2', "PCI5");
70303831d35Sstevel 		if (err != PICL_SUCCESS)
70403831d35Sstevel 			return (err);
70503831d35Sstevel 	} else {
70603831d35Sstevel 		err = add_pci_location(childh, "18,700000", '1', "PCI0");
70703831d35Sstevel 		if (err != PICL_SUCCESS)
70803831d35Sstevel 			return (err);
70903831d35Sstevel 		err = add_pci_location(childh, "18,700000", '2', "PCI1");
71003831d35Sstevel 		if (err != PICL_SUCCESS)
71103831d35Sstevel 			return (err);
71203831d35Sstevel 		err = add_pci_location(childh, "19,700000", '1', "PCI2");
71303831d35Sstevel 		if (err != PICL_SUCCESS)
71403831d35Sstevel 			return (err);
71503831d35Sstevel 		err = add_pci_location(childh, "19,700000", '2', "PCI3");
71603831d35Sstevel 		if (err != PICL_SUCCESS)
71703831d35Sstevel 			return (err);
71803831d35Sstevel 		err = add_pci_location(childh, "19,700000", '3', "PCI4");
71903831d35Sstevel 		if (err != PICL_SUCCESS)
72003831d35Sstevel 			return (err);
72103831d35Sstevel 		err = add_pci_location(childh, "18,600000", '1', "PCI5");
72203831d35Sstevel 		if (err != PICL_SUCCESS)
72303831d35Sstevel 			return (err);
72403831d35Sstevel 	}
72503831d35Sstevel 	*childp = childh;
72603831d35Sstevel 	return (PICL_SUCCESS);
72703831d35Sstevel }
72803831d35Sstevel 
72903831d35Sstevel /*
73003831d35Sstevel  * create fru node, based on sgfru node "sgfrunode" under parent parh. Return
73103831d35Sstevel  * picl_nodehdl of created node in *childp.
73203831d35Sstevel  */
73303831d35Sstevel static int
add_fru_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)73403831d35Sstevel add_fru_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
73503831d35Sstevel     picl_nodehdl_t *childp)
73603831d35Sstevel {
73703831d35Sstevel 	int err;
73803831d35Sstevel 	picl_prophdl_t	tblhdl;
73903831d35Sstevel 	picl_nodehdl_t childh;
74003831d35Sstevel 	uint64_t handle = (uint64_t)sgfrunode->handle;
74103831d35Sstevel 	char *nodename = sgfrunode->nodename;
74203831d35Sstevel 
74303831d35Sstevel 	/*
74403831d35Sstevel 	 * if sgfrunode already there, then just carry on own the tree
74503831d35Sstevel 	 */
74603831d35Sstevel 	childh = find_child_by_name(parh, nodename);
747*ada2da53SToomas Soome 	if (childh != 0) {
74803831d35Sstevel 		/*
74903831d35Sstevel 		 * for frus other than dimms and ecaches, update environmental
75003831d35Sstevel 		 * sensors and board status if necessary
75103831d35Sstevel 		 */
75203831d35Sstevel 		if (IS_ECACHE_NODE(nodename)) {
75303831d35Sstevel 			*childp = childh;
75403831d35Sstevel 			return (PICL_SUCCESS);
75503831d35Sstevel 		}
75603831d35Sstevel 		if (IS_DIMM_NODE(nodename)) {
75703831d35Sstevel 			/*
75803831d35Sstevel 			 * for dimms we just want status
75903831d35Sstevel 			 */
76003831d35Sstevel 			err = add_board_status(childh, nodename);
76103831d35Sstevel 			if (err != PICL_SUCCESS)
76203831d35Sstevel 				return (err);
76303831d35Sstevel 			*childp = childh;
76403831d35Sstevel 			return (PICL_SUCCESS);
76503831d35Sstevel 		}
76603831d35Sstevel 		err = add_board_status(childh, nodename);
76703831d35Sstevel 		if (err != PICL_SUCCESS)
76803831d35Sstevel 			return (err);
76903831d35Sstevel 		err = ptree_get_propval_by_name(childh, PICL_PROP_DEVICES,
77003831d35Sstevel 		    &tblhdl, sizeof (tblhdl));
77103831d35Sstevel 		if (err != PICL_SUCCESS)
77203831d35Sstevel 			return (err);
77303831d35Sstevel 		err = add_env_nodes(childh, nodename, tblhdl);
77403831d35Sstevel 		if (err != PICL_SUCCESS)
77503831d35Sstevel 			return (err);
77603831d35Sstevel 		*childp = childh;
77703831d35Sstevel 		return (PICL_SUCCESS);
77803831d35Sstevel 	}
77903831d35Sstevel 
78003831d35Sstevel 	/*
78103831d35Sstevel 	 * create requested fru node
78203831d35Sstevel 	 */
78303831d35Sstevel 	err = ptree_create_and_add_node(parh, nodename, PICL_CLASS_FRU,
78403831d35Sstevel 	    &childh);
78503831d35Sstevel 	if (err != PICL_SUCCESS) {
78603831d35Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err);
78703831d35Sstevel 		return (err);
78803831d35Sstevel 	}
78903831d35Sstevel 
79003831d35Sstevel 	/*
79103831d35Sstevel 	 * if sgfru has sent us a valid handle, then there is fruid information.
79203831d35Sstevel 	 * create the SC_handle, and FRUDateAvailable properties for FRUID.
79303831d35Sstevel 	 */
79403831d35Sstevel 	if (handle != -1ULL) {
79503831d35Sstevel 		err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
79603831d35Sstevel 		if (err != PICL_SUCCESS)
79703831d35Sstevel 			return (err);
79803831d35Sstevel 		err = add_prop_void(childh, PICL_PROP_FRUDATA_AVAIL);
79903831d35Sstevel 		if (err != PICL_SUCCESS)
80003831d35Sstevel 			return (err);
80103831d35Sstevel 	}
80203831d35Sstevel 
80303831d35Sstevel 	/*
80403831d35Sstevel 	 * post fru added event to fru data plugin if this was due to
80503831d35Sstevel 	 * a dr event - ie post-initialisation
80603831d35Sstevel 	 */
80703831d35Sstevel 	if (init_complete)
808*ada2da53SToomas Soome 		post_frudr_event(PICL_FRU_ADDED, parh, 0);
80903831d35Sstevel 
81003831d35Sstevel 	/*
81103831d35Sstevel 	 * Create empty Devices table - we'll add lines to it as we go along
81203831d35Sstevel 	 */
81303831d35Sstevel 	err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
81403831d35Sstevel 	if (err != PICL_SUCCESS)
81503831d35Sstevel 		return (err);
81603831d35Sstevel 
81703831d35Sstevel 	/*
81803831d35Sstevel 	 * Ecache nodes don't have sensors - just set up FRUType
81903831d35Sstevel 	 */
82003831d35Sstevel 	if (IS_ECACHE_NODE(nodename)) {
82103831d35Sstevel 		err = add_prop_charstring(childh, "EEPROM", PICL_PROP_FRU_TYPE);
82203831d35Sstevel 		if (err != PICL_SUCCESS)
82303831d35Sstevel 			return (err);
82403831d35Sstevel 		*childp = childh;
82503831d35Sstevel 		return (PICL_SUCCESS);
82603831d35Sstevel 	}
82703831d35Sstevel 
82803831d35Sstevel 	/*
82903831d35Sstevel 	 * Dimm nodes don't have sensors - just set up FRUType and
83003831d35Sstevel 	 * also reference properties to memory module nodes and OpStatus
83103831d35Sstevel 	 */
83203831d35Sstevel 	if (IS_DIMM_NODE(nodename)) {
83303831d35Sstevel 		err = add_prop_charstring(childh, "DIMM", PICL_PROP_FRU_TYPE);
83403831d35Sstevel 		if (err != PICL_SUCCESS)
83503831d35Sstevel 			return (err);
83603831d35Sstevel 		err = create_dimm_references(parh, nodename[1] - '0',
83703831d35Sstevel 		    childh, tblhdl);
83803831d35Sstevel 		if (err != PICL_SUCCESS)
83903831d35Sstevel 			return (err);
84003831d35Sstevel 		err = add_board_status(childh, nodename);
84103831d35Sstevel 		if (err != PICL_SUCCESS)
84203831d35Sstevel 			return (err);
84303831d35Sstevel 		*childp = childh;
84403831d35Sstevel 		return (PICL_SUCCESS);
84503831d35Sstevel 	}
84603831d35Sstevel 
84703831d35Sstevel 	/*
84803831d35Sstevel 	 * not a Dimm or Ecache node - set up environmental info,
84903831d35Sstevel 	 * board status and led info
85003831d35Sstevel 	 */
85103831d35Sstevel 	err = add_env_nodes(childh, nodename, tblhdl);
85203831d35Sstevel 	if (err != PICL_SUCCESS)
85303831d35Sstevel 		return (err);
85403831d35Sstevel 
85503831d35Sstevel 	err = add_board_status(childh, nodename);
85603831d35Sstevel 	if (err != PICL_SUCCESS)
85703831d35Sstevel 		return (err);
85803831d35Sstevel 
85903831d35Sstevel 	err = add_led_nodes(childh, nodename, LOM_LED_POSITION_FRU, tblhdl);
86003831d35Sstevel 	if (err != PICL_SUCCESS)
86103831d35Sstevel 		return (err);
86203831d35Sstevel 
86303831d35Sstevel 	*childp = childh;
86403831d35Sstevel 	return (PICL_SUCCESS);
86503831d35Sstevel }
86603831d35Sstevel 
86703831d35Sstevel /*
86803831d35Sstevel  * create location node, based on sgfru node "sgfrunode" under parent parh.
86903831d35Sstevel  * Return picl_nodehdl of created node in *childp.
87003831d35Sstevel  */
87103831d35Sstevel static int
add_location_node(picl_nodehdl_t parh,sgfrunode_t * sgfrunode,picl_nodehdl_t * childp)87203831d35Sstevel add_location_node(picl_nodehdl_t parh, sgfrunode_t *sgfrunode,
87303831d35Sstevel     picl_nodehdl_t *childp)
87403831d35Sstevel {
87503831d35Sstevel 	int err;
87603831d35Sstevel 	uint64_t handle = (uint64_t)sgfrunode->handle;
87703831d35Sstevel 	char *labelp;
87803831d35Sstevel 	char	label[MAX_LABEL_LEN];
87903831d35Sstevel 	char *ptr;
88003831d35Sstevel 	picl_prophdl_t tblhdl;
88103831d35Sstevel 	picl_nodehdl_t childh;
88203831d35Sstevel 
88303831d35Sstevel 	/*
88403831d35Sstevel 	 * strip "N0/" off the label if present (hang-over from wildcat)
88503831d35Sstevel 	 */
88603831d35Sstevel 	if (strncmp(sgfrunode->location_label, LABEL_PREAMBLE,
88703831d35Sstevel 	    LABEL_PREAMBLE_LEN) == 0)
88803831d35Sstevel 		(void) strlcpy(label, &sgfrunode->location_label[
88903831d35Sstevel 		    LABEL_PREAMBLE_LEN], sizeof (label));
89003831d35Sstevel 	else
89103831d35Sstevel 		(void) strlcpy(label, &sgfrunode->location_label[0],
89203831d35Sstevel 		    sizeof (label));
89303831d35Sstevel 
89403831d35Sstevel 	/*
89503831d35Sstevel 	 * some of the locations returned by sgfru are actually of the form
89603831d35Sstevel 	 * XX/YY/ZZ - we need to create multiple levels in the picl tree for
89703831d35Sstevel 	 * these.
89803831d35Sstevel 	 */
89903831d35Sstevel 	labelp = label;
90003831d35Sstevel 	while ((ptr = strchr(labelp, '/')) != NULL) {
90103831d35Sstevel 		/*
90203831d35Sstevel 		 * null end of this section of label
90303831d35Sstevel 		 */
90403831d35Sstevel 		*ptr = '\0';
90503831d35Sstevel 
90603831d35Sstevel 		/*
90703831d35Sstevel 		 * add intermediate nodes - parh will point to the created node
90803831d35Sstevel 		 */
90903831d35Sstevel 		if (IS_PROC_NODE(labelp)) {
91003831d35Sstevel 			err = add_intermediate_nodes(&parh, labelp, &tblhdl,
91103831d35Sstevel 			    "cpu", "PROC");
91203831d35Sstevel 		} else {
91303831d35Sstevel 			err = add_intermediate_nodes(&parh, labelp, &tblhdl,
91403831d35Sstevel 			    NULL, NULL);
91503831d35Sstevel 		}
91603831d35Sstevel 		if (err != PICL_SUCCESS)
91703831d35Sstevel 			return (err);
91803831d35Sstevel 		/*
91903831d35Sstevel 		 * if processor node, then create links to associated cpu node
92003831d35Sstevel 		 * and OpStatus property
92103831d35Sstevel 		 */
92203831d35Sstevel 		if (IS_PROC_NODE(labelp)) {
92303831d35Sstevel 			err = create_cpu_references(labelp, parh, tblhdl);
92403831d35Sstevel 			if (err != PICL_SUCCESS)
92503831d35Sstevel 				return (err);
92603831d35Sstevel 			err = add_board_status(parh, labelp);
92703831d35Sstevel 			if (err != PICL_SUCCESS)
92803831d35Sstevel 				return (err);
92903831d35Sstevel 		}
93003831d35Sstevel 		labelp = ptr + 1;
93103831d35Sstevel 
93203831d35Sstevel 		/*
93303831d35Sstevel 		 * set back to "/"
93403831d35Sstevel 		 */
93503831d35Sstevel 		*ptr = '/';
93603831d35Sstevel 	}
93703831d35Sstevel 
93803831d35Sstevel 	/*
93903831d35Sstevel 	 * if node already there, then just carry on down the tree
94003831d35Sstevel 	 */
94103831d35Sstevel 	childh = find_child_by_name(parh, labelp);
942*ada2da53SToomas Soome 	if (childh != 0) {
94303831d35Sstevel 		*childp = childh;
94403831d35Sstevel 		return (PICL_SUCCESS);
94503831d35Sstevel 	}
94603831d35Sstevel 
94703831d35Sstevel 	/*
94803831d35Sstevel 	 * now just have the final level of the node left. First create it.
94903831d35Sstevel 	 */
95003831d35Sstevel 	err = ptree_create_and_add_node(parh, labelp, PICL_CLASS_LOCATION,
95103831d35Sstevel 	    &childh);
95203831d35Sstevel 	if (err != PICL_SUCCESS) {
95303831d35Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
95403831d35Sstevel 		return (err);
95503831d35Sstevel 	}
95603831d35Sstevel 
95703831d35Sstevel 	/*
95803831d35Sstevel 	 * if sgfru has sent us a valid handle, then there is fruid information.
95903831d35Sstevel 	 * create the SC_handle property for FRUID.
96003831d35Sstevel 	 */
96103831d35Sstevel 	if (handle != -1ULL) {
96203831d35Sstevel 		err = add_prop_ull(childh, handle, PICL_PROP_SC_HANDLE);
96303831d35Sstevel 		if (err != PICL_SUCCESS)
96403831d35Sstevel 			return (err);
96503831d35Sstevel 	}
96603831d35Sstevel 
96703831d35Sstevel 	/* create label property for location class */
96803831d35Sstevel 	err = add_prop_charstring(childh, labelp, PICL_PROP_LABEL);
96903831d35Sstevel 	if (err != PICL_SUCCESS)
97003831d35Sstevel 		return (err);
97103831d35Sstevel 
97203831d35Sstevel 	/* create SlotType property where appropriate */
97303831d35Sstevel 	if (IS_ECACHE_NODE(sgfrunode->nodename)) {
97403831d35Sstevel 		err = add_prop_charstring(childh,
97503831d35Sstevel 		    "ecache", PICL_PROP_SLOT_TYPE);
97603831d35Sstevel 		/*
97703831d35Sstevel 		 * For Ecache, don't need to add environmental info
97803831d35Sstevel 		 * so return here
97903831d35Sstevel 		 */
98003831d35Sstevel 		*childp = childh;
98103831d35Sstevel 		return (err);
98203831d35Sstevel 	} else if (IS_DIMM_NODE(sgfrunode->nodename)) {
98303831d35Sstevel 		err = add_prop_charstring(childh, "memory-module",
98403831d35Sstevel 		    PICL_PROP_SLOT_TYPE);
98503831d35Sstevel 		/*
98603831d35Sstevel 		 * For Dimm, don't need to add environmental info
98703831d35Sstevel 		 * so return here
98803831d35Sstevel 		 */
98903831d35Sstevel 		*childp = childh;
99003831d35Sstevel 		return (err);
99103831d35Sstevel 	} else if (IS_SB_NODE(sgfrunode->nodename)) {
99203831d35Sstevel 		err = add_prop_charstring(childh, "system-board",
99303831d35Sstevel 		    PICL_PROP_SLOT_TYPE);
99403831d35Sstevel 	} else if (IS_PSU_NODE(sgfrunode->nodename)) {
99503831d35Sstevel 		err = add_prop_charstring(childh, "power-supply",
99603831d35Sstevel 		    PICL_PROP_SLOT_TYPE);
99703831d35Sstevel 	} else if (IS_FT_NODE(sgfrunode->nodename)) {
99803831d35Sstevel 		err = add_prop_charstring(childh, "fan-tray",
99903831d35Sstevel 		    PICL_PROP_SLOT_TYPE);
100003831d35Sstevel 	}
100103831d35Sstevel 	if (err != PICL_SUCCESS)
100203831d35Sstevel 		return (err);
100303831d35Sstevel 
100403831d35Sstevel 	/*
100503831d35Sstevel 	 * add devices table to location node (may need
100603831d35Sstevel 	 * references to led devices)
100703831d35Sstevel 	 */
100803831d35Sstevel 	err = create_table(childh, &tblhdl, PICL_PROP_DEVICES);
100903831d35Sstevel 	if (err != PICL_SUCCESS)
101003831d35Sstevel 		return (err);
101103831d35Sstevel 
101203831d35Sstevel 	err = add_led_nodes(childh, labelp, LOM_LED_POSITION_LOCATION, tblhdl);
101303831d35Sstevel 	if (err != PICL_SUCCESS)
101403831d35Sstevel 		return (err);
101503831d35Sstevel 	*childp = childh;
101603831d35Sstevel 	return (PICL_SUCCESS);
101703831d35Sstevel }
101803831d35Sstevel 
101903831d35Sstevel /*
102003831d35Sstevel  * remove an individual picl node - called from remove_subtree()
102103831d35Sstevel  * also removes any sensor nodes pointed at by Devices table
102203831d35Sstevel  */
102303831d35Sstevel static int
remove_picl_node(picl_nodehdl_t nodeh)102403831d35Sstevel remove_picl_node(picl_nodehdl_t nodeh)
102503831d35Sstevel {
102603831d35Sstevel 	int err;
102703831d35Sstevel 	picl_prophdl_t  tblhdl;
102803831d35Sstevel 	picl_prophdl_t  nextprop;
102903831d35Sstevel 	picl_prophdl_t  refprop;
103003831d35Sstevel 	char	class[PICL_CLASSNAMELEN_MAX];
103103831d35Sstevel 
103203831d35Sstevel 	/*
103303831d35Sstevel 	 * first scan Devices table so we can find any sensor nodes
103403831d35Sstevel 	 * we need to delete as well
103503831d35Sstevel 	 */
103603831d35Sstevel 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_DEVICES,
103703831d35Sstevel 	    &tblhdl, sizeof (tblhdl));
103803831d35Sstevel 
103903831d35Sstevel 	/*
104003831d35Sstevel 	 * If Devices table present, then read first column.
104103831d35Sstevel 	 * Devices table may be empty so don't treat this as an error
104203831d35Sstevel 	 */
104303831d35Sstevel 	if (err == PICL_SUCCESS &&
104403831d35Sstevel 	    ptree_get_next_by_row(tblhdl, &nextprop) == PICL_SUCCESS) {
104503831d35Sstevel 		/* find second column */
104603831d35Sstevel 		err = ptree_get_next_by_row(nextprop, &nextprop);
104703831d35Sstevel 		if (err != PICL_SUCCESS) {
104803831d35Sstevel 			syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL,
104903831d35Sstevel 			    PICL_PROP_DEVICES, err);
105003831d35Sstevel 			return (err);
105103831d35Sstevel 		}
105203831d35Sstevel 
105303831d35Sstevel 		/*
105403831d35Sstevel 		 * walk down second column (ref ptr)
105503831d35Sstevel 		 * deleting the referenced nodes
105603831d35Sstevel 		 */
105703831d35Sstevel 		while (err == PICL_SUCCESS) {
105803831d35Sstevel 			err = ptree_get_propval(nextprop, &refprop,
105903831d35Sstevel 			    sizeof (refprop));
106003831d35Sstevel 			if (err != PICL_SUCCESS) {
106103831d35Sstevel 				syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
106203831d35Sstevel 				return (err);
106303831d35Sstevel 			}
106403831d35Sstevel 
106503831d35Sstevel 			/*
106603831d35Sstevel 			 * don't delete memory-module nodes
106703831d35Sstevel 			 * or cpu nodes (they weren't created
106803831d35Sstevel 			 * by this plugin)
106903831d35Sstevel 			 */
107003831d35Sstevel 			err = ptree_get_propval_by_name(refprop,
107103831d35Sstevel 			    PICL_PROP_CLASSNAME, class, sizeof (class));
107203831d35Sstevel 			if (err == PICL_STALEHANDLE) {
107303831d35Sstevel 				/*
107403831d35Sstevel 				 * if another plugin has already deleted the
107503831d35Sstevel 				 * node for us then that is ok
107603831d35Sstevel 				 */
107703831d35Sstevel 				err = ptree_get_next_by_col(nextprop,
107803831d35Sstevel 				    &nextprop);
107903831d35Sstevel 				continue;
108003831d35Sstevel 			}
108103831d35Sstevel 			if (err != PICL_SUCCESS) {
108203831d35Sstevel 				syslog(LOG_ERR, PROP_LOOKUP_FAIL,
108303831d35Sstevel 				    PICL_PROP_CLASSNAME, err);
108403831d35Sstevel 				return (err);
108503831d35Sstevel 			}
108603831d35Sstevel 			if (strcmp(class, PICL_CLASS_MEMORY_MODULE) == 0 ||
108703831d35Sstevel 			    strcmp(class, PICL_CLASS_CPU) == 0) {
108803831d35Sstevel 				/*
108903831d35Sstevel 				 * but - do need to remove _fru_parent
109003831d35Sstevel 				 * property and Environment table (for cpu)
109103831d35Sstevel 				 */
109203831d35Sstevel 				err = remove_references(refprop, class);
109303831d35Sstevel 				if (err != PICL_SUCCESS)
109403831d35Sstevel 					return (err);
109503831d35Sstevel 			} else {
109603831d35Sstevel 				/*
109703831d35Sstevel 				 * sensor node - need to delete it
109803831d35Sstevel 				 */
109903831d35Sstevel 				err = ptree_delete_node(refprop);
110003831d35Sstevel 				if (err != PICL_SUCCESS) {
110103831d35Sstevel 					syslog(LOG_ERR, DELETE_PROP_FAIL, err);
110203831d35Sstevel 					return (err);
110303831d35Sstevel 				}
110403831d35Sstevel 				(void) ptree_destroy_node(refprop);
110503831d35Sstevel 			}
110603831d35Sstevel 			err = ptree_get_next_by_col(nextprop, &nextprop);
110703831d35Sstevel 		}
110803831d35Sstevel 	}
110903831d35Sstevel 
111003831d35Sstevel 	/*
111103831d35Sstevel 	 * now we can remove the frutree node
111203831d35Sstevel 	 */
111303831d35Sstevel 	err = ptree_delete_node(nodeh);
111403831d35Sstevel 	if (err != PICL_SUCCESS) {
111503831d35Sstevel 		syslog(LOG_ERR, DELETE_PROP_FAIL, err);
111603831d35Sstevel 		return (err);
111703831d35Sstevel 	}
111803831d35Sstevel 	(void) ptree_destroy_node(nodeh);
111903831d35Sstevel 	return (PICL_SUCCESS);
112003831d35Sstevel }
112103831d35Sstevel 
112203831d35Sstevel static int
add_child_pci_references(picl_nodehdl_t nodeh,picl_prophdl_t tblhdl,picl_nodehdl_t devnodeh)112303831d35Sstevel add_child_pci_references(picl_nodehdl_t nodeh, picl_prophdl_t tblhdl,
112403831d35Sstevel     picl_nodehdl_t devnodeh)
112503831d35Sstevel {
112603831d35Sstevel 	int err = PICL_SUCCESS;
112703831d35Sstevel 	picl_nodehdl_t childnodeh;
112803831d35Sstevel 	char	class[PICL_CLASSNAMELEN_MAX];
112903831d35Sstevel 
113003831d35Sstevel 	if (ptree_get_propval_by_name(devnodeh, PICL_PROP_CHILD, &childnodeh,
113103831d35Sstevel 	    sizeof (childnodeh)) != PICL_SUCCESS) {
113203831d35Sstevel 		return (PICL_SUCCESS);
113303831d35Sstevel 	}
113403831d35Sstevel 	for (;;) {
113503831d35Sstevel 		err = ptree_get_propval_by_name(childnodeh,
113603831d35Sstevel 		    PICL_PROP_CLASSNAME, class, sizeof (class));
113703831d35Sstevel 		if (err != PICL_SUCCESS)
113803831d35Sstevel 			break;
113903831d35Sstevel 		err = add_prop_ref(childnodeh, nodeh, PICL_REFPROP_FRU_PARENT);
114003831d35Sstevel 		if (err != PICL_SUCCESS)
114103831d35Sstevel 			break;
114203831d35Sstevel 		err = create_table_entry(tblhdl, childnodeh, class);
114303831d35Sstevel 		if (err != PICL_SUCCESS)
114403831d35Sstevel 			break;
114503831d35Sstevel 		err = add_child_pci_references(nodeh, tblhdl, childnodeh);
114603831d35Sstevel 		if (err != PICL_SUCCESS)
114703831d35Sstevel 			break;
114803831d35Sstevel 		err = ptree_get_propval_by_name(childnodeh,
114903831d35Sstevel 		    PICL_PROP_PEER, &childnodeh, sizeof (picl_nodehdl_t));
115003831d35Sstevel 		if (err != PICL_SUCCESS) {
115103831d35Sstevel 			err = PICL_SUCCESS;
115203831d35Sstevel 			break;
115303831d35Sstevel 		}
115403831d35Sstevel 	}
115503831d35Sstevel 	return (err);
115603831d35Sstevel }
115703831d35Sstevel 
115803831d35Sstevel static int
add_pci_location(picl_nodehdl_t childh,char * parent_addr,char bus_addr,char * slot_name)115903831d35Sstevel add_pci_location(picl_nodehdl_t childh, char *parent_addr, char bus_addr,
116003831d35Sstevel     char *slot_name)
116103831d35Sstevel {
116203831d35Sstevel 	int err;
116303831d35Sstevel 	int got_one = 0;
116403831d35Sstevel 	picl_nodehdl_t nodeh;
116503831d35Sstevel 	picl_nodehdl_t devnodeh;
116603831d35Sstevel 	picl_nodehdl_t devhdl;
116703831d35Sstevel 	char	addr[MAXPATHLEN];
116803831d35Sstevel 	char parent_path[MAXPATHLEN];
116903831d35Sstevel 	picl_prophdl_t tblhdl;
117003831d35Sstevel 	char	class[PICL_CLASSNAMELEN_MAX];
117103831d35Sstevel 
117203831d35Sstevel 	/*
117303831d35Sstevel 	 * search for any device nodes whose BUS_ADDR or UNIT_ADDRESS
117403831d35Sstevel 	 * are appropriate for this pci slot
117503831d35Sstevel 	 */
117603831d35Sstevel 	sprintf_buf2(parent_path, IO_DEV, parent_addr);
117703831d35Sstevel 	if (ptree_get_node_by_path(parent_path, &devhdl) == PICL_SUCCESS &&
117803831d35Sstevel 	    ptree_get_propval_by_name(devhdl, PICL_PROP_CHILD, &devnodeh,
117903831d35Sstevel 	    sizeof (devnodeh)) == PICL_SUCCESS) {
118003831d35Sstevel 		while (!got_one) {
118103831d35Sstevel 			err = ptree_get_propval_by_name(devnodeh,
118203831d35Sstevel 			    PICL_PROP_BUS_ADDR, addr, sizeof (addr));
118303831d35Sstevel 			if (err == PICL_SUCCESS && addr[0] == bus_addr &&
118403831d35Sstevel 			    (addr[1] == ',' || addr[1] == '\0')) {
118503831d35Sstevel 				got_one = 1;
118603831d35Sstevel 				break;
118703831d35Sstevel 			}
118803831d35Sstevel 			err = ptree_get_propval_by_name(devnodeh,
118903831d35Sstevel 			    PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr));
119003831d35Sstevel 			if (err == PICL_SUCCESS && addr[0] == bus_addr &&
119103831d35Sstevel 			    (addr[1] == ',' || addr[1] == '\0')) {
119203831d35Sstevel 				got_one = 1;
119303831d35Sstevel 				break;
119403831d35Sstevel 			}
119503831d35Sstevel 			err = ptree_get_propval_by_name(devnodeh,
119603831d35Sstevel 			    PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
119703831d35Sstevel 			if (err != PICL_SUCCESS)
119803831d35Sstevel 				break;
119903831d35Sstevel 		}
120003831d35Sstevel 	}
120103831d35Sstevel 	nodeh = childh;
120203831d35Sstevel 	if (got_one == 0) {
120303831d35Sstevel 		/*
120403831d35Sstevel 		 * no devnodes for this slot. Create location node but
120503831d35Sstevel 		 * no fru node (empty slot)
120603831d35Sstevel 		 */
120703831d35Sstevel 		return (add_intermediate_location(&nodeh, slot_name, "pci"));
120803831d35Sstevel 	}
120903831d35Sstevel 
121003831d35Sstevel 	/*
121103831d35Sstevel 	 * we've got the first devnode for this slot. Create the fru node
121203831d35Sstevel 	 * then walk along other nodes looking for further devnodes
121303831d35Sstevel 	 */
121403831d35Sstevel 	err = add_intermediate_nodes(&nodeh, slot_name, &tblhdl, "pci", NULL);
121503831d35Sstevel 	if (err != PICL_SUCCESS)
121603831d35Sstevel 		return (err);
121703831d35Sstevel 
121803831d35Sstevel 	for (;;) {
121903831d35Sstevel 		if (((err = ptree_get_propval_by_name(devnodeh,
122003831d35Sstevel 		    PICL_PROP_BUS_ADDR, addr, sizeof (addr))) ==
122103831d35Sstevel 		    PICL_SUCCESS && addr[0] == bus_addr &&
122203831d35Sstevel 		    (addr[1] == ',' || addr[1] == '\0')) ||
122303831d35Sstevel 		    ((err = ptree_get_propval_by_name(devnodeh,
122403831d35Sstevel 		    PICL_PROP_UNIT_ADDRESS, addr, sizeof (addr))) ==
122503831d35Sstevel 		    PICL_SUCCESS && addr[0] == bus_addr &&
122603831d35Sstevel 		    (addr[1] == ',' || addr[1] == '\0'))) {
122703831d35Sstevel 			err = ptree_get_propval_by_name(devnodeh,
122803831d35Sstevel 			    PICL_PROP_CLASSNAME, class, sizeof (class));
122903831d35Sstevel 			if (err != PICL_SUCCESS)
123003831d35Sstevel 				break;
123103831d35Sstevel 			err = add_prop_ref(devnodeh, nodeh,
123203831d35Sstevel 			    PICL_REFPROP_FRU_PARENT);
123303831d35Sstevel 			if (err != PICL_SUCCESS)
123403831d35Sstevel 				break;
123503831d35Sstevel 			err = create_table_entry(tblhdl, devnodeh, class);
123603831d35Sstevel 			if (err != PICL_SUCCESS)
123703831d35Sstevel 				break;
123803831d35Sstevel 			err = add_child_pci_references(nodeh, tblhdl, devnodeh);
123903831d35Sstevel 			if (err != PICL_SUCCESS)
124003831d35Sstevel 				break;
124103831d35Sstevel 		}
124203831d35Sstevel 		err = ptree_get_propval_by_name(devnodeh,
124303831d35Sstevel 		    PICL_PROP_PEER, &devnodeh, sizeof (picl_nodehdl_t));
124403831d35Sstevel 		if (err != PICL_SUCCESS) {
124503831d35Sstevel 			err = PICL_SUCCESS;
124603831d35Sstevel 			break;
124703831d35Sstevel 		}
124803831d35Sstevel 	}
124903831d35Sstevel 	return (err);
125003831d35Sstevel }
125103831d35Sstevel 
125203831d35Sstevel /*
125303831d35Sstevel  * add intermediate location into frutree (ie a location that we know
125403831d35Sstevel  * exists but sgfru doesn't)
125503831d35Sstevel  */
125603831d35Sstevel static int
add_intermediate_location(picl_nodehdl_t * nodep,char * labelp,char * slot_name)125703831d35Sstevel add_intermediate_location(picl_nodehdl_t *nodep, char *labelp, char *slot_name)
125803831d35Sstevel {
125903831d35Sstevel 	int err;
126003831d35Sstevel 	picl_nodehdl_t intermediate;
126103831d35Sstevel 	picl_prophdl_t tblhdl;
126203831d35Sstevel 	char	parent_name[PICL_PROPNAMELEN_MAX];
126303831d35Sstevel 
126403831d35Sstevel 	err = ptree_create_and_add_node(*nodep, labelp, PICL_CLASS_LOCATION,
126503831d35Sstevel 	    &intermediate);
126603831d35Sstevel 	if (err != PICL_SUCCESS) {
126703831d35Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
126803831d35Sstevel 		return (err);
126903831d35Sstevel 	}
127003831d35Sstevel 
127103831d35Sstevel 	/*
127203831d35Sstevel 	 * create label property for location class
127303831d35Sstevel 	 */
127403831d35Sstevel 	err = add_prop_charstring(intermediate, labelp, PICL_PROP_LABEL);
127503831d35Sstevel 	if (err != PICL_SUCCESS)
127603831d35Sstevel 		return (err);
127703831d35Sstevel 
127803831d35Sstevel 	/*
127903831d35Sstevel 	 * add devices table to location node (may need references to led
128003831d35Sstevel 	 * devices)
128103831d35Sstevel 	 */
128203831d35Sstevel 	err = create_table(intermediate, &tblhdl, PICL_PROP_DEVICES);
128303831d35Sstevel 	if (err != PICL_SUCCESS)
128403831d35Sstevel 		return (err);
128503831d35Sstevel 
128603831d35Sstevel 	/*
128703831d35Sstevel 	 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
128803831d35Sstevel 	 */
128903831d35Sstevel 	err = ptree_get_propval_by_name(*nodep, PICL_PROP_NAME, parent_name,
129003831d35Sstevel 	    sizeof (parent_name));
129103831d35Sstevel 	if (err != PICL_SUCCESS)
129203831d35Sstevel 		return (err);
129303831d35Sstevel 	if (strcmp(labelp, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0)
129403831d35Sstevel 		err = add_led_nodes(intermediate, "FAN8",
129503831d35Sstevel 		    LOM_LED_POSITION_LOCATION, tblhdl);
129603831d35Sstevel 	else if (strcmp(labelp, "FAN1") == 0 && strcmp(parent_name, "IB6") == 0)
129703831d35Sstevel 		err = add_led_nodes(intermediate, "FAN9",
129803831d35Sstevel 		    LOM_LED_POSITION_LOCATION, tblhdl);
129903831d35Sstevel 	else
130003831d35Sstevel 		err = add_led_nodes(intermediate, labelp,
130103831d35Sstevel 		    LOM_LED_POSITION_LOCATION, tblhdl);
130203831d35Sstevel 	if (err != PICL_SUCCESS)
130303831d35Sstevel 		return (err);
130403831d35Sstevel 
130503831d35Sstevel 	if (slot_name) {
130603831d35Sstevel 		err = add_prop_charstring(intermediate, slot_name,
130703831d35Sstevel 		    PICL_PROP_SLOT_TYPE);
130803831d35Sstevel 		if (err != PICL_SUCCESS)
130903831d35Sstevel 			return (err);
131003831d35Sstevel 	}
131103831d35Sstevel 	*nodep = intermediate;
131203831d35Sstevel 	return (PICL_SUCCESS);
131303831d35Sstevel }
131403831d35Sstevel 
131503831d35Sstevel /*
131603831d35Sstevel  * adds an intermediate location/fru pair into frutree
131703831d35Sstevel  */
131803831d35Sstevel static int
add_intermediate_nodes(picl_nodehdl_t * nodep,char * labelp,picl_prophdl_t * tblhdlp,char * slot_name,char * fru_name)131903831d35Sstevel add_intermediate_nodes(picl_nodehdl_t *nodep, char *labelp,
132003831d35Sstevel     picl_prophdl_t *tblhdlp, char *slot_name, char *fru_name)
132103831d35Sstevel {
132203831d35Sstevel 	int err;
132303831d35Sstevel 	picl_nodehdl_t intermediate;
132403831d35Sstevel 	picl_nodehdl_t intermediate2;
132503831d35Sstevel 
132603831d35Sstevel 	/*
132703831d35Sstevel 	 * create intermediate location node (unless it has already been
132803831d35Sstevel 	 * created)
132903831d35Sstevel 	 */
133003831d35Sstevel 	intermediate = find_child_by_name(*nodep, labelp);
1331*ada2da53SToomas Soome 	if (intermediate == 0) {
133203831d35Sstevel 		intermediate = *nodep;
133303831d35Sstevel 		err = add_intermediate_location(&intermediate, labelp,
133403831d35Sstevel 		    slot_name);
133503831d35Sstevel 		if (err != PICL_SUCCESS) {
133603831d35Sstevel 			return (err);
133703831d35Sstevel 		}
133803831d35Sstevel 	}
133903831d35Sstevel 
134003831d35Sstevel 	/*
134103831d35Sstevel 	 * create intermediate fru node (unless it has already been
134203831d35Sstevel 	 * created)
134303831d35Sstevel 	 */
134403831d35Sstevel 	intermediate2 = find_child_by_name(intermediate, labelp);
1345*ada2da53SToomas Soome 	if (intermediate2 == 0) {
134603831d35Sstevel 		/*
134703831d35Sstevel 		 * need to create intermediate fru node node
134803831d35Sstevel 		 */
134903831d35Sstevel 		err = ptree_create_and_add_node(intermediate, labelp,
135003831d35Sstevel 		    PICL_CLASS_FRU, &intermediate2);
135103831d35Sstevel 		if (err != PICL_SUCCESS) {
135203831d35Sstevel 			syslog(LOG_ERR, ADD_NODE_FAIL, labelp, err);
135303831d35Sstevel 			return (err);
135403831d35Sstevel 		}
135503831d35Sstevel 
135603831d35Sstevel 		/*
135703831d35Sstevel 		 * Create empty Devices table
135803831d35Sstevel 		 */
135903831d35Sstevel 		err = create_table(intermediate2, tblhdlp, PICL_PROP_DEVICES);
136003831d35Sstevel 		if (err != PICL_SUCCESS)
136103831d35Sstevel 			return (err);
136203831d35Sstevel 
136303831d35Sstevel 		if (fru_name) {
136403831d35Sstevel 			err = add_prop_charstring(intermediate2, fru_name,
136503831d35Sstevel 			    PICL_PROP_FRU_TYPE);
136603831d35Sstevel 			if (err != PICL_SUCCESS)
136703831d35Sstevel 				return (err);
136803831d35Sstevel 		}
136903831d35Sstevel 	} else  {
137003831d35Sstevel 		err = ptree_get_propval_by_name(intermediate2,
137103831d35Sstevel 		    PICL_PROP_DEVICES, tblhdlp, sizeof (*tblhdlp));
137203831d35Sstevel 		if (err != PICL_SUCCESS)
137303831d35Sstevel 			return (err);
137403831d35Sstevel 	}
137503831d35Sstevel 	*nodep = intermediate2;
137603831d35Sstevel 	return (PICL_SUCCESS);
137703831d35Sstevel }
137803831d35Sstevel 
137903831d35Sstevel /*
138003831d35Sstevel  * need to remove _fru_parent property and Environment table (for cpu)
138103831d35Sstevel  */
138203831d35Sstevel static int
remove_references(picl_prophdl_t refprop,char * class)138303831d35Sstevel remove_references(picl_prophdl_t refprop, char *class)
138403831d35Sstevel {
138503831d35Sstevel 	picl_prophdl_t  platprop;
138603831d35Sstevel 	int err;
138703831d35Sstevel 
138803831d35Sstevel 	err = ptree_get_prop_by_name(refprop, PICL_REFPROP_FRU_PARENT,
138903831d35Sstevel 	    &platprop);
139003831d35Sstevel 	if (err != PICL_SUCCESS) {
139103831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
139203831d35Sstevel 		return (err);
139303831d35Sstevel 	}
139403831d35Sstevel 	err = ptree_delete_prop(platprop);
139503831d35Sstevel 	if (err != PICL_SUCCESS) {
139603831d35Sstevel 		syslog(LOG_ERR, DELETE_PROP_FAIL, err);
139703831d35Sstevel 		return (err);
139803831d35Sstevel 	}
139903831d35Sstevel 	(void) ptree_destroy_prop(platprop);
140003831d35Sstevel 	if (strcmp(class, PICL_CLASS_CPU) == 0) {
140103831d35Sstevel 		err = ptree_get_prop_by_name(refprop, PICL_PROP_ENV, &platprop);
140203831d35Sstevel 		if (err != PICL_SUCCESS) {
140303831d35Sstevel 			/*
140403831d35Sstevel 			 * multi-core cpu is setup with only one cpu having
140503831d35Sstevel 			 * env table so ignore PICL_PROPNOTFOUND error.
140603831d35Sstevel 			 */
140703831d35Sstevel 			if (err == PICL_PROPNOTFOUND) {
140803831d35Sstevel 				return (PICL_SUCCESS);
140903831d35Sstevel 			}
141003831d35Sstevel 			syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_ENV, err);
141103831d35Sstevel 			return (err);
141203831d35Sstevel 		}
141303831d35Sstevel 		err = ptree_delete_prop(platprop);
141403831d35Sstevel 		if (err != PICL_SUCCESS) {
141503831d35Sstevel 			syslog(LOG_ERR, DELETE_PROP_FAIL, err);
141603831d35Sstevel 			return (err);
141703831d35Sstevel 		}
141803831d35Sstevel 		(void) ptree_destroy_prop(platprop);
141903831d35Sstevel 	}
142003831d35Sstevel 	return (PICL_SUCCESS);
142103831d35Sstevel }
142203831d35Sstevel 
142303831d35Sstevel /*
142403831d35Sstevel  * subroutine for various functions. Finds immediate child of parh with
142503831d35Sstevel  * requested name if present. Otherwise returns NULL.
142603831d35Sstevel  */
142703831d35Sstevel static picl_nodehdl_t
find_child_by_name(picl_nodehdl_t parh,char * name)142803831d35Sstevel find_child_by_name(picl_nodehdl_t parh, char *name)
142903831d35Sstevel {
143003831d35Sstevel 	picl_nodehdl_t nodeh;
143103831d35Sstevel 	int err;
143203831d35Sstevel 	char	nodename[PICL_PROPNAMELEN_MAX];
143303831d35Sstevel 
143403831d35Sstevel 	err = ptree_get_propval_by_name(parh, PICL_PROP_CHILD,
143503831d35Sstevel 	    &nodeh, sizeof (picl_nodehdl_t));
143603831d35Sstevel 	if (err != PICL_SUCCESS)
1437*ada2da53SToomas Soome 		return (0);
143803831d35Sstevel 	for (;;) {
143903831d35Sstevel 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_NAME, nodename,
144003831d35Sstevel 		    sizeof (nodename));
144103831d35Sstevel 		if (err != PICL_SUCCESS)
1442*ada2da53SToomas Soome 			return (0);
144303831d35Sstevel 		if (strcmp(name, nodename) == 0) {
144403831d35Sstevel 			return (nodeh);
144503831d35Sstevel 		}
144603831d35Sstevel 		err = ptree_get_propval_by_name(nodeh, PICL_PROP_PEER,
144703831d35Sstevel 		    &nodeh, sizeof (picl_nodehdl_t));
144803831d35Sstevel 		if (err != PICL_SUCCESS)
1449*ada2da53SToomas Soome 			return (0);
145003831d35Sstevel 	}
145103831d35Sstevel }
145203831d35Sstevel 
145303831d35Sstevel static int
create_dimm_references(picl_nodehdl_t parh,int dimm_id,picl_nodehdl_t nodeh,picl_prophdl_t tblhdl)145403831d35Sstevel create_dimm_references(picl_nodehdl_t parh, int dimm_id,
145503831d35Sstevel     picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
145603831d35Sstevel {
145703831d35Sstevel 	int err;
1458*ada2da53SToomas Soome 	picl_nodehdl_t memctlhdl = 0;
145903831d35Sstevel 	picl_nodehdl_t memgrphdl;
146003831d35Sstevel 	picl_nodehdl_t memhdl;
146103831d35Sstevel 	char name[MAXPATHLEN];
146203831d35Sstevel 	char	sbname[PICL_PROPNAMELEN_MAX];
146303831d35Sstevel 	char	pname[PICL_PROPNAMELEN_MAX];
146403831d35Sstevel 	char	bname[PICL_PROPNAMELEN_MAX];
146503831d35Sstevel 	picl_nodehdl_t parentfruh;
146603831d35Sstevel 	picl_nodehdl_t parentloch;
146703831d35Sstevel 	int id;
146803831d35Sstevel 
146903831d35Sstevel 	/*
147003831d35Sstevel 	 * create reference properties for memory nodes
147103831d35Sstevel 	 * - first find names of ancestor frus - ie "SBx/Py/Bz"
147203831d35Sstevel 	 */
147303831d35Sstevel 	err = ptree_get_propval_by_name(parh, PICL_PROP_PARENT, &parentfruh,
147403831d35Sstevel 	    sizeof (picl_nodehdl_t));
147503831d35Sstevel 	if (err != PICL_SUCCESS) {
147603831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
147703831d35Sstevel 		return (err);
147803831d35Sstevel 	}
147903831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME,
148003831d35Sstevel 	    bname, sizeof (bname));
148103831d35Sstevel 	if (err != PICL_SUCCESS) {
148203831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
148303831d35Sstevel 		return (err);
148403831d35Sstevel 	}
148503831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT,
148603831d35Sstevel 	    &parentloch, sizeof (picl_nodehdl_t));
148703831d35Sstevel 	if (err != PICL_SUCCESS) {
148803831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
148903831d35Sstevel 		return (err);
149003831d35Sstevel 	}
149103831d35Sstevel 	err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
149203831d35Sstevel 	    &parentfruh, sizeof (picl_nodehdl_t));
149303831d35Sstevel 	if (err != PICL_SUCCESS) {
149403831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
149503831d35Sstevel 		return (err);
149603831d35Sstevel 	}
149703831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME,
149803831d35Sstevel 	    pname, sizeof (pname));
149903831d35Sstevel 	if (err != PICL_SUCCESS) {
150003831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
150103831d35Sstevel 		return (err);
150203831d35Sstevel 	}
150303831d35Sstevel 
150403831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_PARENT,
150503831d35Sstevel 	    &parentloch, sizeof (picl_nodehdl_t));
150603831d35Sstevel 	if (err != PICL_SUCCESS) {
150703831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
150803831d35Sstevel 		return (err);
150903831d35Sstevel 	}
151003831d35Sstevel 	err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
151103831d35Sstevel 	    &parentfruh, sizeof (picl_nodehdl_t));
151203831d35Sstevel 	if (err != PICL_SUCCESS) {
151303831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
151403831d35Sstevel 		return (err);
151503831d35Sstevel 	}
151603831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname,
151703831d35Sstevel 	    sizeof (sbname));
151803831d35Sstevel 	if (err != PICL_SUCCESS) {
151903831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
152003831d35Sstevel 		return (err);
152103831d35Sstevel 	}
152203831d35Sstevel 
152303831d35Sstevel 	/*
152403831d35Sstevel 	 * ok - we've now got name of system board node in sbname and
152503831d35Sstevel 	 * name of processor node in pname.
152603831d35Sstevel 	 * Now find corresponding memory-controller node if present
152703831d35Sstevel 	 */
152803831d35Sstevel 	sprintf_buf2(name, MEMORY_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
152903831d35Sstevel 	err = ptree_get_node_by_path(name, &memctlhdl);
153003831d35Sstevel 	if (err != PICL_SUCCESS)
153103831d35Sstevel 		return (PICL_SUCCESS);
153203831d35Sstevel 
153303831d35Sstevel 	/*
153403831d35Sstevel 	 * now find corresponding memory-module-group node if present
153503831d35Sstevel 	 */
153603831d35Sstevel 	err = ptree_get_propval_by_name(memctlhdl, PICL_PROP_CHILD, &memgrphdl,
153703831d35Sstevel 	    sizeof (picl_nodehdl_t));
153803831d35Sstevel 	if (err != PICL_SUCCESS)
153903831d35Sstevel 		return (PICL_SUCCESS);
154003831d35Sstevel 
154103831d35Sstevel 	/*
154203831d35Sstevel 	 * check if this is the right bank - if not move on to sibling
154303831d35Sstevel 	 */
154403831d35Sstevel 	err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID,
154503831d35Sstevel 	    &id, sizeof (int));
154603831d35Sstevel 	if (err != PICL_SUCCESS)
154703831d35Sstevel 		return (PICL_SUCCESS);
154803831d35Sstevel 	if (bname[1] != id + '0') {
154903831d35Sstevel 		err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_PEER,
155003831d35Sstevel 		    &memgrphdl, sizeof (picl_nodehdl_t));
155103831d35Sstevel 		if (err != PICL_SUCCESS)
155203831d35Sstevel 			return (PICL_SUCCESS);
155303831d35Sstevel 		err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_ID,
155403831d35Sstevel 		    &id, sizeof (int));
155503831d35Sstevel 		if (err != PICL_SUCCESS)
155603831d35Sstevel 			return (PICL_SUCCESS);
155703831d35Sstevel 		if (bname[1] != id + '0')
155803831d35Sstevel 			return (PICL_SUCCESS);
155903831d35Sstevel 	}
156003831d35Sstevel 
156103831d35Sstevel 	/*
156203831d35Sstevel 	 * now find corresponding memory-module node if present
156303831d35Sstevel 	 */
156403831d35Sstevel 	err = ptree_get_propval_by_name(memgrphdl, PICL_PROP_CHILD, &memhdl,
156503831d35Sstevel 	    sizeof (picl_nodehdl_t));
156603831d35Sstevel 	if (err != PICL_SUCCESS)
156703831d35Sstevel 		return (PICL_SUCCESS);
156803831d35Sstevel 
156903831d35Sstevel 	/*
157003831d35Sstevel 	 * for each DIMM set up links with matching memory-module node
157103831d35Sstevel 	 */
157203831d35Sstevel 	for (;;) {
157303831d35Sstevel 		err = ptree_get_propval_by_name(memhdl, PICL_PROP_ID,
157403831d35Sstevel 		    &id, sizeof (int));
157503831d35Sstevel 		if (err == PICL_SUCCESS && dimm_id == id) {
157603831d35Sstevel 			err = add_prop_ref(memhdl, nodeh,
157703831d35Sstevel 			    PICL_REFPROP_FRU_PARENT);
157803831d35Sstevel 			if (err != PICL_SUCCESS)
157903831d35Sstevel 				return (err);
158003831d35Sstevel 			err = create_table_entry(tblhdl, memhdl,
158103831d35Sstevel 			    PICL_CLASS_MEMORY_MODULE);
158203831d35Sstevel 			if (err != PICL_SUCCESS)
158303831d35Sstevel 				return (err);
158403831d35Sstevel 		}
158503831d35Sstevel 		err = ptree_get_propval_by_name(memhdl, PICL_PROP_PEER,
158603831d35Sstevel 		    &memhdl, sizeof (picl_nodehdl_t));
158703831d35Sstevel 		if (err != PICL_SUCCESS)
158803831d35Sstevel 			break;
158903831d35Sstevel 	}
159003831d35Sstevel 	return (PICL_SUCCESS);
159103831d35Sstevel }
159203831d35Sstevel 
159303831d35Sstevel static int
create_cpu_references(char * pname,picl_nodehdl_t nodeh,picl_prophdl_t tblhdl)159403831d35Sstevel create_cpu_references(char *pname, picl_nodehdl_t nodeh, picl_prophdl_t tblhdl)
159503831d35Sstevel {
159603831d35Sstevel 	int err;
159703831d35Sstevel 	picl_nodehdl_t sensorhdl;
159803831d35Sstevel 	picl_nodehdl_t parentloch;
159903831d35Sstevel 	picl_nodehdl_t parentfruh;
160003831d35Sstevel 	picl_nodehdl_t cpuhdl;
160103831d35Sstevel 	picl_nodehdl_t cpuhdl1;
160203831d35Sstevel 	picl_prophdl_t envtblhdl;
160303831d35Sstevel 	picl_prophdl_t prophdl;
160403831d35Sstevel 	char name[MAXPATHLEN];
160503831d35Sstevel 	char	sbname[PICL_PROPNAMELEN_MAX];
160603831d35Sstevel 
160703831d35Sstevel 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_PARENT,
160803831d35Sstevel 	    &parentloch, sizeof (picl_nodehdl_t));
160903831d35Sstevel 	if (err != PICL_SUCCESS) {
161003831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
161103831d35Sstevel 		return (err);
161203831d35Sstevel 	}
161303831d35Sstevel 	err = ptree_get_propval_by_name(parentloch, PICL_PROP_PARENT,
161403831d35Sstevel 	    &parentfruh, sizeof (picl_nodehdl_t));
161503831d35Sstevel 	if (err != PICL_SUCCESS) {
161603831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
161703831d35Sstevel 		return (err);
161803831d35Sstevel 	}
161903831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, sbname,
162003831d35Sstevel 	    sizeof (sbname));
162103831d35Sstevel 	if (err != PICL_SUCCESS) {
162203831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
162303831d35Sstevel 		return (err);
162403831d35Sstevel 	}
162503831d35Sstevel 
162603831d35Sstevel 	/*
162703831d35Sstevel 	 * Find corresponding cpu node if present. Note, this code will
162803831d35Sstevel 	 * attempt to find a corresponding cpu node, by searching for devices
162903831d35Sstevel 	 * of the types  /platform/ssm@0,0/SUNW,UltraSPARC-III+@%x,0,
163003831d35Sstevel 	 * /platform/ssm@0,0/SUNW,UltraSPARC-III@%x,0 or
163103831d35Sstevel 	 * /platform/ssm@0,0/cmp@%x,0/cpu@0 or 1. If we can not find
163203831d35Sstevel 	 * any such device, we return PICL_SUCCESS such that we
163303831d35Sstevel 	 * continue the construction of the remaining part of the
163403831d35Sstevel 	 * tree. We first check for UltraSPARC-III. If we do not
163503831d35Sstevel 	 * find such a device we check for UltraSPARC-III+. If
163603831d35Sstevel 	 * we are unsuccesful again we try one of the jaguar cores
163703831d35Sstevel 	 * /platform/ssm@0,0/cmp@%x,0/cpu@. If we do not find the
163803831d35Sstevel 	 * first one, there's no point in continuing and we just
163903831d35Sstevel 	 * return PICL_SUCCESS. Similarly if we find one core
164003831d35Sstevel 	 * but not the other, something must be wrong, so we
164103831d35Sstevel 	 * again just return PICL_SUCCESS without creating any
164203831d35Sstevel 	 * references.
164303831d35Sstevel 	 */
164403831d35Sstevel 	sprintf_buf2(name, CPU_DEV, SB_P_TO_SAFARI_ADDR(sbname, pname));
164503831d35Sstevel 
164603831d35Sstevel 	err = ptree_get_node_by_path(name, &cpuhdl);
164703831d35Sstevel 
164803831d35Sstevel 	if (err != PICL_SUCCESS) {
164903831d35Sstevel 		sprintf_buf2(name, CPU_DEV2,
165003831d35Sstevel 		    SB_P_TO_SAFARI_ADDR(sbname, pname));
165103831d35Sstevel 		err = ptree_get_node_by_path(name, &cpuhdl);
165203831d35Sstevel 		if (err != PICL_SUCCESS) {
165303831d35Sstevel 			/* check for jaguar cores */
165403831d35Sstevel 			sprintf_buf2(name, CPU_DEV3C1,
165503831d35Sstevel 			    SB_P_TO_SAFARI_ADDR(sbname, pname));
165603831d35Sstevel 			err = ptree_get_node_by_path(name, &cpuhdl1);
165703831d35Sstevel 			if (err != PICL_SUCCESS)
165803831d35Sstevel 				return (PICL_SUCCESS);
165903831d35Sstevel 			/* add fru parent reference for the second core */
166003831d35Sstevel 			err = ptree_get_prop_by_name(cpuhdl1,
166103831d35Sstevel 			    PICL_REFPROP_FRU_PARENT, &prophdl);
166203831d35Sstevel 			if (err != PICL_SUCCESS) {
166303831d35Sstevel 				err = add_prop_ref(cpuhdl1, nodeh,
166403831d35Sstevel 				    PICL_REFPROP_FRU_PARENT);
166503831d35Sstevel 			if (err != PICL_SUCCESS)
166603831d35Sstevel 				return (err);
166703831d35Sstevel 			err = create_table_entry(tblhdl, cpuhdl1,
166803831d35Sstevel 			    PICL_CLASS_CPU);
166903831d35Sstevel 			if (err != PICL_SUCCESS)
167003831d35Sstevel 				return (err);
167103831d35Sstevel 			}
167203831d35Sstevel 			sprintf_buf2(name, CPU_DEV3C0,
167303831d35Sstevel 			    SB_P_TO_SAFARI_ADDR(sbname, pname));
167403831d35Sstevel 			err = ptree_get_node_by_path(name, &cpuhdl);
167503831d35Sstevel 			if (err != PICL_SUCCESS)
167603831d35Sstevel 				return (PICL_SUCCESS);
167703831d35Sstevel 
167803831d35Sstevel 		}
167903831d35Sstevel 	}
168003831d35Sstevel 
168103831d35Sstevel 	/*
168203831d35Sstevel 	 * now create reference properties
168303831d35Sstevel 	 */
168403831d35Sstevel 	err = ptree_get_prop_by_name(cpuhdl, PICL_REFPROP_FRU_PARENT, &prophdl);
168503831d35Sstevel 	if (err != PICL_SUCCESS) {
168603831d35Sstevel 		err = add_prop_ref(cpuhdl, nodeh, PICL_REFPROP_FRU_PARENT);
168703831d35Sstevel 		if (err != PICL_SUCCESS)
168803831d35Sstevel 			return (err);
168903831d35Sstevel 		err = create_table_entry(tblhdl, cpuhdl, PICL_CLASS_CPU);
169003831d35Sstevel 		if (err != PICL_SUCCESS)
169103831d35Sstevel 			return (err);
169203831d35Sstevel 	}
169303831d35Sstevel 
169403831d35Sstevel 	/*
169503831d35Sstevel 	 * create Environment table on cpu node - with Die and Ambient
169603831d35Sstevel 	 * temperature sensors if present. If already there, delete and start
169703831d35Sstevel 	 * again
169803831d35Sstevel 	 */
169903831d35Sstevel 	err = ptree_get_prop_by_name(cpuhdl, PICL_PROP_ENV, &prophdl);
170003831d35Sstevel 	if (err == PICL_SUCCESS) {
170103831d35Sstevel 		err = ptree_delete_prop(prophdl);
170203831d35Sstevel 		if (err != PICL_SUCCESS)
170303831d35Sstevel 			return (err);
170403831d35Sstevel 		(void) ptree_destroy_prop(prophdl);
170503831d35Sstevel 	}
170603831d35Sstevel 	err = create_table(cpuhdl, &envtblhdl, PICL_PROP_ENV);
170703831d35Sstevel 	if (err != PICL_SUCCESS)
170803831d35Sstevel 		return (err);
170903831d35Sstevel 
171003831d35Sstevel 	if (pcix_io)
171103831d35Sstevel 		sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV_PCIX, sbname,
171203831d35Sstevel 		    (pname[1] - '0'));
171303831d35Sstevel 	else
171403831d35Sstevel 		sprintf_buf4(name, "%s/%s_t_cheetah%d@0", SC_DEV, sbname,
171503831d35Sstevel 		    (pname[1] - '0'));
171603831d35Sstevel 
171703831d35Sstevel 	err = ptree_get_node_by_path(name, &sensorhdl);
171803831d35Sstevel 	if (err == PICL_SUCCESS) {
171903831d35Sstevel 		err = create_table_entry(envtblhdl, sensorhdl,
172003831d35Sstevel 		    PICL_CLASS_TEMPERATURE_SENSOR);
172103831d35Sstevel 		if (err != PICL_SUCCESS)
172203831d35Sstevel 			return (err);
172303831d35Sstevel 	}
172403831d35Sstevel 
172503831d35Sstevel 	if (pcix_io)
172603831d35Sstevel 		sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV_PCIX, sbname,
172703831d35Sstevel 		    (pname[1] - '0'));
172803831d35Sstevel 	else
172903831d35Sstevel 		sprintf_buf4(name, "%s/%s_t_ambient%d@0", SC_DEV, sbname,
173003831d35Sstevel 		    (pname[1] - '0'));
173103831d35Sstevel 
173203831d35Sstevel 	err = ptree_get_node_by_path(name, &sensorhdl);
173303831d35Sstevel 	if (err == PICL_SUCCESS) {
173403831d35Sstevel 		return (create_table_entry(envtblhdl, sensorhdl,
173503831d35Sstevel 		    PICL_CLASS_TEMPERATURE_SENSOR));
173603831d35Sstevel 	}
173703831d35Sstevel 	return (PICL_SUCCESS);
173803831d35Sstevel }
173903831d35Sstevel 
174003831d35Sstevel /*
174103831d35Sstevel  * subroutine of add_subtree - get a list of children of a parent node
174203831d35Sstevel  */
174303831d35Sstevel static sgfrunode_t *
get_node_children(fru_hdl_t fruparent,int * num_childrenp)174403831d35Sstevel get_node_children(fru_hdl_t fruparent, int *num_childrenp)
174503831d35Sstevel {
174603831d35Sstevel 	int	max_children, i;
174703831d35Sstevel 	sgfrunode_t	*fruchildren = NULL;
174803831d35Sstevel 	child_info_t child_info;
174903831d35Sstevel 	int  frufd;
175003831d35Sstevel 
175103831d35Sstevel 	/*
175203831d35Sstevel 	 * Open the sgfru pseudo dev
175303831d35Sstevel 	 */
175403831d35Sstevel 	if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, 0)) == -1) {
175503831d35Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, FRU_PSEUDO_DEV, strerror(errno));
175603831d35Sstevel 		return (NULL);
175703831d35Sstevel 	}
175803831d35Sstevel 	for (i = 1; i <= MAX_TRIES; i++) {
175903831d35Sstevel 		max_children = i * MAX_NODE_CHILDREN;
176003831d35Sstevel 		if ((fruchildren = calloc(max_children,
176103831d35Sstevel 		    sizeof (sgfrunode_t))) == NULL) {
176203831d35Sstevel 			(void) close(frufd);
176303831d35Sstevel 			syslog(LOG_ERR, MALLOC_FAIL);
176403831d35Sstevel 			return (NULL);
176503831d35Sstevel 		}
176603831d35Sstevel 		child_info.fru_hdl = fruparent;
176703831d35Sstevel 		child_info.fru_cnt = max_children;
176803831d35Sstevel 		child_info.frus = (void *)fruchildren;
176903831d35Sstevel 		if (ioctl(frufd, SGFRU_GETCHILDLIST, &child_info) == 0) {
177003831d35Sstevel 			/*
177103831d35Sstevel 			 * got them - return success
177203831d35Sstevel 			 */
177303831d35Sstevel 			(void) close(frufd);
177403831d35Sstevel 			*num_childrenp = child_info.fru_cnt;
177503831d35Sstevel 			return (fruchildren);
177603831d35Sstevel 		}
177703831d35Sstevel 		free(fruchildren);
177803831d35Sstevel 
177903831d35Sstevel 		/*
178003831d35Sstevel 		 * if ENOMEM, need to calloc more space - so go round loop again
178103831d35Sstevel 		 * otherwise fail
178203831d35Sstevel 		 */
178303831d35Sstevel 		if (errno != ENOMEM) {
178403831d35Sstevel 			(void) close(frufd);
178503831d35Sstevel 			syslog(LOG_ERR, SGFRU_IOCTL_FAIL, SGFRU_GETCHILDLIST,
178603831d35Sstevel 			    fruparent, strerror(errno));
178703831d35Sstevel 			return (NULL);
178803831d35Sstevel 		}
178903831d35Sstevel 	}
179003831d35Sstevel 	(void) close(frufd);
179103831d35Sstevel 	syslog(LOG_ERR, MALLOC_FAIL);
179203831d35Sstevel 	return (NULL);
179303831d35Sstevel }
179403831d35Sstevel 
179503831d35Sstevel /* Creates an unsigned longlong property for a given PICL node */
179603831d35Sstevel static int
add_prop_ull(picl_nodehdl_t nodeh,uint64_t handle,char * name)179703831d35Sstevel add_prop_ull(picl_nodehdl_t nodeh, uint64_t handle, char *name)
179803831d35Sstevel {
179903831d35Sstevel 	picl_prophdl_t proph;
180003831d35Sstevel 	ptree_propinfo_t propinfo;
180103831d35Sstevel 	int err;
180203831d35Sstevel 
180303831d35Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
180403831d35Sstevel 	    PICL_PTYPE_UNSIGNED_INT, PICL_READ, sizeof (unsigned long long),
180503831d35Sstevel 	    PICL_PROP_SC_HANDLE, NULL, NULL);
180603831d35Sstevel 	if (err != PICL_SUCCESS) {
180703831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
180803831d35Sstevel 		return (err);
180903831d35Sstevel 	}
181003831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &handle, &proph);
181103831d35Sstevel 	if (err != PICL_SUCCESS) {
181203831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
181303831d35Sstevel 		return (err);
181403831d35Sstevel 	}
181503831d35Sstevel 	return (PICL_SUCCESS);
181603831d35Sstevel }
181703831d35Sstevel 
181803831d35Sstevel /* Creates a void property for a given PICL node */
181903831d35Sstevel static int
add_prop_void(picl_nodehdl_t nodeh,char * name)182003831d35Sstevel add_prop_void(picl_nodehdl_t nodeh, char *name)
182103831d35Sstevel {
182203831d35Sstevel 	picl_prophdl_t proph;
182303831d35Sstevel 	ptree_propinfo_t propinfo;
182403831d35Sstevel 	int err;
182503831d35Sstevel 
182603831d35Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
182703831d35Sstevel 	    PICL_PTYPE_VOID, PICL_READ, 0, PICL_PROP_FRUDATA_AVAIL, NULL, NULL);
182803831d35Sstevel 	if (err != PICL_SUCCESS) {
182903831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
183003831d35Sstevel 		return (err);
183103831d35Sstevel 	}
183203831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, &proph);
183303831d35Sstevel 	if (err != PICL_SUCCESS) {
183403831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
183503831d35Sstevel 		return (err);
183603831d35Sstevel 	}
183703831d35Sstevel 	return (PICL_SUCCESS);
183803831d35Sstevel }
183903831d35Sstevel 
184003831d35Sstevel /* Creates a reference property for a given PICL node */
184103831d35Sstevel static int
add_prop_ref(picl_nodehdl_t nodeh,picl_nodehdl_t value,char * name)184203831d35Sstevel add_prop_ref(picl_nodehdl_t nodeh, picl_nodehdl_t value, char *name)
184303831d35Sstevel {
184403831d35Sstevel 	picl_prophdl_t proph;
184503831d35Sstevel 	ptree_propinfo_t propinfo;
184603831d35Sstevel 	int err;
184703831d35Sstevel 
184803831d35Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
184903831d35Sstevel 	    PICL_PTYPE_REFERENCE, PICL_READ, sizeof (picl_nodehdl_t), name,
185003831d35Sstevel 	    NULL, NULL);
185103831d35Sstevel 	if (err != PICL_SUCCESS) {
185203831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
185303831d35Sstevel 		return (err);
185403831d35Sstevel 	}
185503831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
185603831d35Sstevel 	if (err != PICL_SUCCESS) {
185703831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
185803831d35Sstevel 		return (err);
185903831d35Sstevel 	}
186003831d35Sstevel 	return (PICL_SUCCESS);
186103831d35Sstevel }
186203831d35Sstevel 
186303831d35Sstevel /* Creates an integer property for a given PICL node */
186403831d35Sstevel static int
add_prop_int(picl_nodehdl_t nodeh,int value,char * name)186503831d35Sstevel add_prop_int(picl_nodehdl_t nodeh, int value, char *name)
186603831d35Sstevel {
186703831d35Sstevel 	picl_prophdl_t proph;
186803831d35Sstevel 	ptree_propinfo_t propinfo;
186903831d35Sstevel 	int err;
187003831d35Sstevel 
187103831d35Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
187203831d35Sstevel 	    PICL_PTYPE_INT, PICL_READ, sizeof (int), name, NULL, NULL);
187303831d35Sstevel 	if (err != PICL_SUCCESS) {
187403831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
187503831d35Sstevel 		return (err);
187603831d35Sstevel 	}
187703831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
187803831d35Sstevel 	if (err != PICL_SUCCESS) {
187903831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
188003831d35Sstevel 		return (err);
188103831d35Sstevel 	}
188203831d35Sstevel 	return (PICL_SUCCESS);
188303831d35Sstevel }
188403831d35Sstevel 
188503831d35Sstevel /* Creates an integer property for a given PICL node */
188603831d35Sstevel static int
add_prop_float(picl_nodehdl_t nodeh,float value,char * name)188703831d35Sstevel add_prop_float(picl_nodehdl_t nodeh, float value, char *name)
188803831d35Sstevel {
188903831d35Sstevel 	picl_prophdl_t proph;
189003831d35Sstevel 	ptree_propinfo_t propinfo;
189103831d35Sstevel 	int err;
189203831d35Sstevel 
189303831d35Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
189403831d35Sstevel 	    PICL_PTYPE_FLOAT, PICL_READ, sizeof (float), name, NULL, NULL);
189503831d35Sstevel 	if (err != PICL_SUCCESS) {
189603831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
189703831d35Sstevel 		return (err);
189803831d35Sstevel 	}
189903831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, &value, &proph);
190003831d35Sstevel 	if (err != PICL_SUCCESS) {
190103831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
190203831d35Sstevel 		return (err);
190303831d35Sstevel 	}
190403831d35Sstevel 	return (PICL_SUCCESS);
190503831d35Sstevel }
190603831d35Sstevel 
190703831d35Sstevel /* Creates a charstring property for a given PICL node */
190803831d35Sstevel static int
add_prop_charstring(picl_nodehdl_t nodeh,char * value,char * name)190903831d35Sstevel add_prop_charstring(picl_nodehdl_t nodeh, char *value, char *name)
191003831d35Sstevel {
191103831d35Sstevel 	picl_prophdl_t proph;
191203831d35Sstevel 	ptree_propinfo_t propinfo;
191303831d35Sstevel 	int err;
191403831d35Sstevel 
191503831d35Sstevel 	err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
191603831d35Sstevel 	    PICL_PTYPE_CHARSTRING, PICL_READ, strlen(value) + 1,
191703831d35Sstevel 	    name, NULL, NULL);
191803831d35Sstevel 	if (err != PICL_SUCCESS) {
191903831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, name, err);
192003831d35Sstevel 		return (err);
192103831d35Sstevel 	}
192203831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, value, &proph);
192303831d35Sstevel 	if (err != PICL_SUCCESS) {
192403831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, name, err);
192503831d35Sstevel 		return (err);
192603831d35Sstevel 	}
192703831d35Sstevel 	return (PICL_SUCCESS);
192803831d35Sstevel }
192903831d35Sstevel 
193003831d35Sstevel /* create an entry in the specified table */
193103831d35Sstevel static int
create_table_entry(picl_prophdl_t tblhdl,picl_nodehdl_t refhdl,char * class)193203831d35Sstevel create_table_entry(picl_prophdl_t tblhdl, picl_nodehdl_t refhdl, char *class)
193303831d35Sstevel {
193403831d35Sstevel 	int			err;
193503831d35Sstevel 	ptree_propinfo_t	prop;
193603831d35Sstevel 	picl_prophdl_t		prophdl[2];
193703831d35Sstevel 
193803831d35Sstevel 	/* first column is class */
193903831d35Sstevel 	prop.version = PTREE_PROPINFO_VERSION;
194003831d35Sstevel 	prop.piclinfo.type =  PICL_PTYPE_CHARSTRING;
194103831d35Sstevel 	prop.piclinfo.accessmode = PICL_READ;
194203831d35Sstevel 	prop.piclinfo.size = PICL_CLASSNAMELEN_MAX;
194303831d35Sstevel 	prop.read = NULL;
194403831d35Sstevel 	prop.write = NULL;
194503831d35Sstevel 	(void) strlcpy(prop.piclinfo.name, PICL_PROP_CLASS,
194603831d35Sstevel 	    sizeof (prop.piclinfo.name));
194703831d35Sstevel 	err = ptree_create_prop(&prop, class, &prophdl[0]);
194803831d35Sstevel 	if (err != PICL_SUCCESS) {
194903831d35Sstevel 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
195003831d35Sstevel 		return (err);
195103831d35Sstevel 	}
195203831d35Sstevel 
195303831d35Sstevel 	/* second column is refernce property */
195403831d35Sstevel 	prop.version = PTREE_PROPINFO_VERSION;
195503831d35Sstevel 	prop.piclinfo.type =  PICL_PTYPE_REFERENCE;
195603831d35Sstevel 	prop.piclinfo.accessmode = PICL_READ;
195703831d35Sstevel 	prop.piclinfo.size = sizeof (picl_nodehdl_t);
195803831d35Sstevel 	prop.read = NULL;
195903831d35Sstevel 	prop.write = NULL;
196003831d35Sstevel 	sprintf_buf2(prop.piclinfo.name, "_%s_", class);
196103831d35Sstevel 	err = ptree_create_prop(&prop, &refhdl, &prophdl[1]);
196203831d35Sstevel 	if (err != PICL_SUCCESS) {
196303831d35Sstevel 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
196403831d35Sstevel 		return (err);
196503831d35Sstevel 	}
196603831d35Sstevel 
196703831d35Sstevel 	/* add row to table */
196803831d35Sstevel 	err = ptree_add_row_to_table(tblhdl, 2, prophdl);
196903831d35Sstevel 	if (err != PICL_SUCCESS)
197003831d35Sstevel 		syslog(LOG_ERR, ADD_TBL_ENTRY_FAIL, err);
197103831d35Sstevel 	return (err);
197203831d35Sstevel }
197303831d35Sstevel 
197403831d35Sstevel /* create an empty table property */
197503831d35Sstevel static int
create_table(picl_nodehdl_t fruhdl,picl_prophdl_t * tblhdlp,char * tbl_name)197603831d35Sstevel create_table(picl_nodehdl_t fruhdl, picl_prophdl_t *tblhdlp, char *tbl_name)
197703831d35Sstevel {
197803831d35Sstevel 	int			err;
197903831d35Sstevel 	ptree_propinfo_t	prop;
198003831d35Sstevel 	picl_prophdl_t		tblprophdl;
198103831d35Sstevel 
198203831d35Sstevel 	err = ptree_create_table(tblhdlp);
198303831d35Sstevel 	if (err != PICL_SUCCESS) {
198403831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
198503831d35Sstevel 		return (err);
198603831d35Sstevel 	}
198703831d35Sstevel 	prop.version = PTREE_PROPINFO_VERSION;
198803831d35Sstevel 	prop.piclinfo.type =  PICL_PTYPE_TABLE;
198903831d35Sstevel 	prop.piclinfo.accessmode = PICL_READ;
199003831d35Sstevel 	prop.piclinfo.size = sizeof (picl_prophdl_t);
199103831d35Sstevel 	prop.read = NULL;
199203831d35Sstevel 	prop.write = NULL;
199303831d35Sstevel 	(void) strlcpy(prop.piclinfo.name, tbl_name,
199403831d35Sstevel 	    sizeof (prop.piclinfo.name));
199503831d35Sstevel 	err = ptree_create_and_add_prop(fruhdl, &prop, tblhdlp, &tblprophdl);
199603831d35Sstevel 	if (err != PICL_SUCCESS)
199703831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, tbl_name, err);
199803831d35Sstevel 	return (err);
199903831d35Sstevel }
200003831d35Sstevel 
200103831d35Sstevel static void
frudr_add_subtree(picl_nodehdl_t parh)200203831d35Sstevel frudr_add_subtree(picl_nodehdl_t parh)
200303831d35Sstevel {
200403831d35Sstevel 	fru_hdl_t	sgfruhdl;
200503831d35Sstevel 	if (ptree_get_propval_by_name(parh, PICL_PROP_SC_HANDLE,
200603831d35Sstevel 	    &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
200703831d35Sstevel 		return;
200803831d35Sstevel 	}
200903831d35Sstevel 	(void) add_subtree(parh, sgfruhdl);
201003831d35Sstevel }
201103831d35Sstevel 
201203831d35Sstevel /* event completion handler for PICL_FRU_ADDED/PICL_FRU_REMOVED events */
201303831d35Sstevel /*ARGSUSED*/
201403831d35Sstevel static void
frudr_completion_handler(char * ename,void * earg,size_t size)201503831d35Sstevel frudr_completion_handler(char *ename, void *earg, size_t size)
201603831d35Sstevel {
201703831d35Sstevel 	picl_nodehdl_t	fruh;
201803831d35Sstevel 	picl_nodehdl_t	parh;
201903831d35Sstevel 
202003831d35Sstevel 	if (strcmp(ename, PICL_FRU_REMOVED) == 0) {
202103831d35Sstevel 		/*
202203831d35Sstevel 		 * now frudata has been notified that the node is to be
202303831d35Sstevel 		 * removed, we can actually remove it
202403831d35Sstevel 		 */
2025*ada2da53SToomas Soome 		fruh = 0;
202603831d35Sstevel 		(void) nvlist_lookup_uint64(earg,
202703831d35Sstevel 		    PICLEVENTARG_FRUHANDLE, &fruh);
2028*ada2da53SToomas Soome 		if (fruh != 0) {
202903831d35Sstevel 			(void) remove_subtree(fruh);
203003831d35Sstevel 
203103831d35Sstevel 			/*
203203831d35Sstevel 			 * Now repopulate the frutree with current data.
203303831d35Sstevel 			 */
2034*ada2da53SToomas Soome 			parh = 0;
203503831d35Sstevel 			(void) nvlist_lookup_uint64(earg,
203603831d35Sstevel 			    PICLEVENTARG_PARENTHANDLE, &parh);
2037*ada2da53SToomas Soome 			if (parh != 0) {
203803831d35Sstevel 				frudr_add_subtree(parh);
203903831d35Sstevel 			}
204003831d35Sstevel 		}
204103831d35Sstevel 	}
204203831d35Sstevel 	nvlist_free(earg);
204303831d35Sstevel 	free(earg);
204403831d35Sstevel 	free(ename);
204503831d35Sstevel }
204603831d35Sstevel 
204703831d35Sstevel /*
204803831d35Sstevel  * Post the PICL_FRU_ADDED/PICL_FRU_REMOVED event
204903831d35Sstevel  */
205003831d35Sstevel static void
post_frudr_event(char * ename,picl_nodehdl_t parenth,picl_nodehdl_t fruh)205103831d35Sstevel post_frudr_event(char *ename, picl_nodehdl_t parenth, picl_nodehdl_t fruh)
205203831d35Sstevel {
205303831d35Sstevel 	nvlist_t	*nvl;
205403831d35Sstevel 	char		*ev_name;
205503831d35Sstevel 
205603831d35Sstevel 	ev_name = strdup(ename);
205703831d35Sstevel 	if (ev_name == NULL)
205803831d35Sstevel 		return;
2059*ada2da53SToomas Soome 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) {
206003831d35Sstevel 		free(ev_name);
206103831d35Sstevel 		return;
206203831d35Sstevel 	}
206303831d35Sstevel 	if (parenth != 0L &&
206403831d35Sstevel 	    nvlist_add_uint64(nvl, PICLEVENTARG_PARENTHANDLE, parenth)) {
206503831d35Sstevel 		free(ev_name);
206603831d35Sstevel 		nvlist_free(nvl);
206703831d35Sstevel 		return;
206803831d35Sstevel 	}
206903831d35Sstevel 	if (fruh != 0L &&
207003831d35Sstevel 	    nvlist_add_uint64(nvl, PICLEVENTARG_FRUHANDLE, fruh)) {
207103831d35Sstevel 		free(ev_name);
207203831d35Sstevel 		nvlist_free(nvl);
207303831d35Sstevel 		return;
207403831d35Sstevel 	}
207503831d35Sstevel 	if (ptree_post_event(ev_name, nvl, sizeof (nvl),
207603831d35Sstevel 	    frudr_completion_handler) != 0) {
207703831d35Sstevel 		free(ev_name);
207803831d35Sstevel 		nvlist_free(nvl);
207903831d35Sstevel 	}
208003831d35Sstevel }
208103831d35Sstevel 
208203831d35Sstevel /*
2083768a4bffSjfrank  * updates the picl node 'loc' with the new fru handle (PICL_PROP_SC_HANDLE)
2084768a4bffSjfrank  * (helper function for frudr_evhandler, when a stale fru handle is
2085768a4bffSjfrank  * detected)
2086768a4bffSjfrank  */
2087768a4bffSjfrank static void
update_fru_hdl(picl_nodehdl_t loc,fru_hdl_t newsgfruhdl)2088768a4bffSjfrank update_fru_hdl(picl_nodehdl_t loc, fru_hdl_t newsgfruhdl)
2089768a4bffSjfrank {
2090768a4bffSjfrank 	picl_prophdl_t	schproph;
2091768a4bffSjfrank 	int		err;
2092768a4bffSjfrank 
2093768a4bffSjfrank 	err = ptree_get_prop_by_name(loc, PICL_PROP_SC_HANDLE, &schproph);
2094768a4bffSjfrank 	if (err == PICL_SUCCESS) {
2095768a4bffSjfrank 		if (ptree_delete_prop(schproph) == PICL_SUCCESS) {
2096768a4bffSjfrank 			(void) ptree_destroy_prop(schproph);
2097768a4bffSjfrank 		}
2098768a4bffSjfrank 	}
2099768a4bffSjfrank 	(void) add_prop_ull(loc, (uint64_t)newsgfruhdl, PICL_PROP_SC_HANDLE);
2100768a4bffSjfrank }
2101768a4bffSjfrank 
2102768a4bffSjfrank /*
2103768a4bffSjfrank  * Get the fru handle of loc by iterating through the parent's children.
2104768a4bffSjfrank  * Sets fruhdl and returns PICL_SUCCESS unless an error is encountered.
2105768a4bffSjfrank  */
2106768a4bffSjfrank static int
get_fruhdl_from_parent(picl_nodehdl_t loc,fru_hdl_t * fruhdl)2107768a4bffSjfrank get_fruhdl_from_parent(picl_nodehdl_t loc, fru_hdl_t *fruhdl)
2108768a4bffSjfrank {
2109768a4bffSjfrank 	picl_nodehdl_t	parlocnodeh;
2110768a4bffSjfrank 	fru_hdl_t	parsgfruhdl;
2111768a4bffSjfrank 	sgfrunode_t	*cp;
2112768a4bffSjfrank 	sgfrunode_t	*fruchildren;
2113768a4bffSjfrank 	char		nodename[PICL_PROPNAMELEN_MAX];
2114768a4bffSjfrank 	int		err;
2115768a4bffSjfrank 	int		num_children;
2116768a4bffSjfrank 	int		i;
2117768a4bffSjfrank 
2118768a4bffSjfrank 	err = ptree_get_propval_by_name(loc, PICL_PROP_NAME, (void *)nodename,
2119768a4bffSjfrank 	    PICL_PROPNAMELEN_MAX);
2120768a4bffSjfrank 	if (err != PICL_SUCCESS)
2121768a4bffSjfrank 		return (err);
2122768a4bffSjfrank 	err = ptree_get_propval_by_name(loc, PICL_PROP_PARENT, &parlocnodeh,
2123768a4bffSjfrank 	    sizeof (picl_nodehdl_t));
2124768a4bffSjfrank 	if (err != PICL_SUCCESS)
2125768a4bffSjfrank 		return (err);
2126768a4bffSjfrank 	if ((err = ptree_get_propval_by_name(parlocnodeh, PICL_PROP_SC_HANDLE,
2127768a4bffSjfrank 	    &parsgfruhdl, sizeof (parsgfruhdl))) != PICL_SUCCESS)
2128768a4bffSjfrank 		return (err);
2129768a4bffSjfrank 	/* find children of the parent node */
2130768a4bffSjfrank 	fruchildren = get_node_children(parsgfruhdl, &num_children);
2131768a4bffSjfrank 	if (fruchildren == NULL)
2132768a4bffSjfrank 		return (PICL_FAILURE);
2133768a4bffSjfrank 	for (i = 0, cp = fruchildren; i < num_children; i++, cp++) {
2134768a4bffSjfrank 		/* find the child we're interested in */
2135768a4bffSjfrank 		if (strcmp(cp->nodename, nodename) == 0) {
2136768a4bffSjfrank 			*fruhdl = cp->handle;
2137768a4bffSjfrank 			free(fruchildren);
2138768a4bffSjfrank 			return (PICL_SUCCESS);
2139768a4bffSjfrank 		}
2140768a4bffSjfrank 	}
2141768a4bffSjfrank 	free(fruchildren);
2142768a4bffSjfrank 	return (PICL_FAILURE);
2143768a4bffSjfrank }
2144768a4bffSjfrank 
2145768a4bffSjfrank /*
214603831d35Sstevel  * handle EC_DR picl events
214703831d35Sstevel  */
214803831d35Sstevel /*ARGSUSED*/
214903831d35Sstevel static void
frudr_evhandler(const char * ename,const void * earg,size_t size,void * cookie)215003831d35Sstevel frudr_evhandler(const char *ename, const void *earg, size_t size, void *cookie)
215103831d35Sstevel {
215203831d35Sstevel 	nvlist_t		*nvlp;
215303831d35Sstevel 	char			*dtype;
215403831d35Sstevel 	char			*ap_id;
215503831d35Sstevel 	char			*hint;
215603831d35Sstevel 	char			path[MAXPATHLEN];
215703831d35Sstevel 	picl_nodehdl_t		fruh;
215803831d35Sstevel 	picl_nodehdl_t		locnodeh;
215903831d35Sstevel 	fru_hdl_t		sgfruhdl;
2160768a4bffSjfrank 	fru_hdl_t		sgfruhdl_from_parent;
216103831d35Sstevel 
216203831d35Sstevel 	if (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) != 0)
216303831d35Sstevel 		return;
216403831d35Sstevel 
2165*ada2da53SToomas Soome 	if (nvlist_unpack((char *)earg, size, &nvlp, 0))
216603831d35Sstevel 		return;
216703831d35Sstevel 
216803831d35Sstevel 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
216903831d35Sstevel 		nvlist_free(nvlp);
217003831d35Sstevel 		return;
217103831d35Sstevel 	}
217203831d35Sstevel 
217303831d35Sstevel 	if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) != 0) {
217403831d35Sstevel 		nvlist_free(nvlp);
217503831d35Sstevel 		return;
217603831d35Sstevel 	}
217703831d35Sstevel 
217803831d35Sstevel 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_AP_ID, &ap_id)) {
217903831d35Sstevel 		nvlist_free(nvlp);
218003831d35Sstevel 		return;
218103831d35Sstevel 	}
218203831d35Sstevel 
218303831d35Sstevel 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_HINT, &hint)) {
218403831d35Sstevel 		nvlist_free(nvlp);
218503831d35Sstevel 		return;
218603831d35Sstevel 	}
218703831d35Sstevel 
218803831d35Sstevel 	if (strncmp(ap_id, AP_ID_PREAMBLE, AP_ID_PREAMBLE_LEN) != 0) {
218903831d35Sstevel 		nvlist_free(nvlp);
219003831d35Sstevel 		return;
219103831d35Sstevel 	}
219203831d35Sstevel 
219303831d35Sstevel 	/*
219403831d35Sstevel 	 * OK - so this is an EC_DR event - let's handle it.
219503831d35Sstevel 	 */
219603831d35Sstevel 	sprintf_buf2(path, CHASSIS_LOC_PATH, &ap_id[AP_ID_PREAMBLE_LEN]);
219703831d35Sstevel 
219803831d35Sstevel 	/*
219903831d35Sstevel 	 * special case - SSC arrival means that SSC has been reset - we
220003831d35Sstevel 	 * need to flush the cached sgfru handles
220103831d35Sstevel 	 */
220203831d35Sstevel 	if (strcmp(&ap_id[AP_ID_PREAMBLE_LEN], "SSC1") == 0) {
220303831d35Sstevel 		picl_nodehdl_t chdh;
220403831d35Sstevel 		picl_nodehdl_t peerh;
220503831d35Sstevel 		picl_nodehdl_t parh;
220603831d35Sstevel 		int got_peer;
220703831d35Sstevel 		char	label[MAX_LABEL_LEN];
220803831d35Sstevel 		int err;
220903831d35Sstevel 		sgfrunode_t	*sgfruchassisp = NULL;
221003831d35Sstevel 		int num_children;
221103831d35Sstevel 		picl_prophdl_t	schproph;
221203831d35Sstevel 
221303831d35Sstevel 		/* find existing chassis node */
221403831d35Sstevel 		if (ptree_get_node_by_path(CHASSIS_PATH, &parh) !=
221503831d35Sstevel 		    PICL_SUCCESS) {
221603831d35Sstevel 			nvlist_free(nvlp);
221703831d35Sstevel 			return;
221803831d35Sstevel 		}
221903831d35Sstevel 
222003831d35Sstevel 		/* find new chassis sgfru node */
222103831d35Sstevel 		sgfruchassisp = get_node_children(ROOTPARENT, &num_children);
222203831d35Sstevel 		if (sgfruchassisp == NULL || num_children != 1) {
222303831d35Sstevel 			nvlist_free(nvlp);
222403831d35Sstevel 			return;
222503831d35Sstevel 		}
222603831d35Sstevel 
222703831d35Sstevel 		/* update chassis SC_HANDLE property */
222803831d35Sstevel 		err = ptree_get_prop_by_name(parh, PICL_PROP_SC_HANDLE,
222903831d35Sstevel 		    &schproph);
223003831d35Sstevel 		if (err != PICL_SUCCESS) {
223103831d35Sstevel 			nvlist_free(nvlp);
223203831d35Sstevel 			return;
223303831d35Sstevel 		}
223403831d35Sstevel 		err = ptree_delete_prop(schproph);
223503831d35Sstevel 		if (err != PICL_SUCCESS) {
223603831d35Sstevel 			nvlist_free(nvlp);
223703831d35Sstevel 			return;
223803831d35Sstevel 		}
223903831d35Sstevel 		(void) ptree_destroy_prop(schproph);
224003831d35Sstevel 		err = add_prop_ull(parh, sgfruchassisp->handle,
224103831d35Sstevel 		    PICL_PROP_SC_HANDLE);
224203831d35Sstevel 		if (err != PICL_SUCCESS) {
224303831d35Sstevel 			nvlist_free(nvlp);
224403831d35Sstevel 			return;
224503831d35Sstevel 		}
224603831d35Sstevel 
224703831d35Sstevel 		/*
224803831d35Sstevel 		 * remove all subtrees except DISK, TAPE, DVD and PCI subtrees
224903831d35Sstevel 		 */
225003831d35Sstevel 		if (ptree_get_propval_by_name(parh, PICL_PROP_CHILD, &chdh,
225103831d35Sstevel 		    sizeof (picl_nodehdl_t)) == PICL_SUCCESS) {
225203831d35Sstevel 			for (;;) {
225303831d35Sstevel 				if (ptree_get_propval_by_name(chdh,
225403831d35Sstevel 				    PICL_PROP_PEER, &peerh,
225503831d35Sstevel 				    sizeof (picl_nodehdl_t)) != PICL_SUCCESS)
225603831d35Sstevel 					got_peer = 0;
225703831d35Sstevel 				else
225803831d35Sstevel 					got_peer = 1;
225903831d35Sstevel 				err = ptree_get_propval_by_name(chdh,
226003831d35Sstevel 				    PICL_PROP_LABEL, label, sizeof (label));
226103831d35Sstevel 				if (err == PICL_SUCCESS) {
226203831d35Sstevel 					if (strncmp(label, "DISK",
226303831d35Sstevel 					    strlen("DISK")) != 0 &&
226403831d35Sstevel 					    strncmp(label, "TAPE",
226503831d35Sstevel 					    strlen("TAPE")) != 0 &&
226603831d35Sstevel 					    strncmp(label, "PCI",
226703831d35Sstevel 					    strlen("PCI")) != 0 &&
226803831d35Sstevel 					    strncmp(label, "DVD",
226903831d35Sstevel 					    strlen("DVD")) != 0) {
227003831d35Sstevel 						(void) remove_subtree(chdh);
227103831d35Sstevel 					}
227203831d35Sstevel 				}
227303831d35Sstevel 				if (got_peer == 0)
227403831d35Sstevel 					break;
227503831d35Sstevel 				chdh = peerh;
227603831d35Sstevel 			}
227703831d35Sstevel 		}
227803831d35Sstevel 
227903831d35Sstevel 		/* add new subtrees */
228003831d35Sstevel 		(void) add_subtree(parh, sgfruchassisp->handle);
228103831d35Sstevel 		free(sgfruchassisp);
228203831d35Sstevel 
228303831d35Sstevel 		nvlist_free(nvlp);
228403831d35Sstevel 		return;
228503831d35Sstevel 	}
228603831d35Sstevel 
228703831d35Sstevel 	if (ptree_get_node_by_path(path, &locnodeh) != PICL_SUCCESS) {
228803831d35Sstevel 		nvlist_free(nvlp);
228903831d35Sstevel 		return;
229003831d35Sstevel 	}
229103831d35Sstevel 	if (ptree_get_propval_by_name(locnodeh, PICL_PROP_SC_HANDLE,
229203831d35Sstevel 	    &sgfruhdl, sizeof (sgfruhdl)) != PICL_SUCCESS) {
229303831d35Sstevel 		nvlist_free(nvlp);
229403831d35Sstevel 		return;
229503831d35Sstevel 	}
229603831d35Sstevel 
229703831d35Sstevel 	/*
229803831d35Sstevel 	 * now either add or delete the fru node as appropriate. If no
229903831d35Sstevel 	 * hint, treat as insert - add_subtree will update the tree if
230003831d35Sstevel 	 * necessary.
230103831d35Sstevel 	 */
230203831d35Sstevel 	if (strcmp(hint, DR_HINT_REMOVE) == 0) {
230303831d35Sstevel 		if (ptree_get_propval_by_name(locnodeh, PICL_PROP_CHILD,
230403831d35Sstevel 		    &fruh, sizeof (picl_nodehdl_t)) != PICL_PROPNOTFOUND) {
230503831d35Sstevel 			/*
230603831d35Sstevel 			 * fru was there - but has gone away
230703831d35Sstevel 			 */
230803831d35Sstevel 			post_frudr_event(PICL_FRU_REMOVED, locnodeh, fruh);
230903831d35Sstevel 		}
231003831d35Sstevel 	} else {
231103831d35Sstevel 		/*
231203831d35Sstevel 		 * fru has been inserted (or may need to update)
2313768a4bffSjfrank 		 *
2314768a4bffSjfrank 		 * sgfruhdl may be stale due to hotplugging. We check this
2315768a4bffSjfrank 		 * by getting the fru_hdl_t from the parent's children
2316768a4bffSjfrank 		 * and compare it to the cached value in sgfruhdl.  If we
2317768a4bffSjfrank 		 * have a stale handle, we update the cached value and
2318768a4bffSjfrank 		 * use it in the call to add_subtree.
231903831d35Sstevel 		 */
2320768a4bffSjfrank 		if (get_fruhdl_from_parent(locnodeh, &sgfruhdl_from_parent) ==
2321768a4bffSjfrank 		    PICL_SUCCESS) {
2322768a4bffSjfrank 			if (sgfruhdl != sgfruhdl_from_parent) {
2323768a4bffSjfrank 				update_fru_hdl(locnodeh, sgfruhdl_from_parent);
2324768a4bffSjfrank 				sgfruhdl = sgfruhdl_from_parent;
2325768a4bffSjfrank 			}
2326768a4bffSjfrank 		}
2327768a4bffSjfrank 
232803831d35Sstevel 		(void) add_subtree(locnodeh, sgfruhdl);
232903831d35Sstevel 	}
233003831d35Sstevel 	nvlist_free(nvlp);
233103831d35Sstevel }
233203831d35Sstevel 
233303831d35Sstevel /*
233403831d35Sstevel  * handle memcfg picl events - need to update reference properties
233503831d35Sstevel  */
233603831d35Sstevel /*ARGSUSED*/
233703831d35Sstevel static void
frumemcfg_evhandler(const char * ename,const void * earg,size_t size,void * cookie)233803831d35Sstevel frumemcfg_evhandler(const char *ename, const void *earg, size_t size,
233903831d35Sstevel     void *cookie)
234003831d35Sstevel {
234103831d35Sstevel 	picl_nodehdl_t	nodeh;
234203831d35Sstevel 	picl_nodehdl_t	lochdl;
234303831d35Sstevel 	picl_nodehdl_t	fruhdl;
234403831d35Sstevel 	picl_nodehdl_t	memgrphdl;
234503831d35Sstevel 	picl_nodehdl_t	memhdl;
234603831d35Sstevel 	picl_prophdl_t	tblhdl;
234703831d35Sstevel 	picl_prophdl_t	tblproph;
234803831d35Sstevel 	nvlist_t	*nvlp;
234903831d35Sstevel 	char	addr[MAXPATHLEN];
235003831d35Sstevel 	char	bname[PICL_PROPNAMELEN_MAX];
235103831d35Sstevel 	picl_nodehdl_t	banklochdl;
235203831d35Sstevel 	picl_nodehdl_t	bankfruhdl;
235303831d35Sstevel 	char	label[MAX_LABEL_LEN];
235403831d35Sstevel 	int err;
235503831d35Sstevel 	int id;
235603831d35Sstevel 	char *ptr;
235703831d35Sstevel 	int value;
235803831d35Sstevel 	char buf[MAX_LINE_SIZE];
235903831d35Sstevel 
236003831d35Sstevel 	if (strcmp(ename, PICLEVENT_MC_ADDED) != 0 &&
236103831d35Sstevel 	    strcmp(ename, PICLEVENT_MC_REMOVED) != 0)
236203831d35Sstevel 		return;
236303831d35Sstevel 
236403831d35Sstevel 	/*
236503831d35Sstevel 	 * find corresponding frutree dimm nodes
236603831d35Sstevel 	 */
2367*ada2da53SToomas Soome 	if (nvlist_unpack((char *)earg, size, &nvlp, 0))
236803831d35Sstevel 		return;
236903831d35Sstevel 	if (nvlist_lookup_uint64(nvlp, PICLEVENTARG_NODEHANDLE, &nodeh)) {
237003831d35Sstevel 		nvlist_free(nvlp);
237103831d35Sstevel 		return;
237203831d35Sstevel 	}
237303831d35Sstevel 	nvlist_free(nvlp);
237403831d35Sstevel 	err = ptree_get_propval_by_name(nodeh, PICL_PROP_UNIT_ADDRESS, addr,
237503831d35Sstevel 	    sizeof (addr));
237603831d35Sstevel 	if (err != PICL_SUCCESS)
237703831d35Sstevel 		return;
237803831d35Sstevel 	ptr = strchr(addr, ',');
237903831d35Sstevel 	if (ptr == NULL)
238003831d35Sstevel 		return;
238103831d35Sstevel 	*ptr = '\0';
238203831d35Sstevel 	value = strtol(addr, NULL, 16);
238303831d35Sstevel 	sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value),
238403831d35Sstevel 	    SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value),
238503831d35Sstevel 	    SAFARI_ADDR_TO_P(value));
238603831d35Sstevel 	err = ptree_get_node_by_path(buf, &fruhdl);
238703831d35Sstevel 	if (err != PICL_SUCCESS)
238803831d35Sstevel 		return;
238903831d35Sstevel 	err = ptree_get_propval_by_name(fruhdl, PICL_PROP_CHILD,
239003831d35Sstevel 	    &banklochdl, sizeof (banklochdl));
239103831d35Sstevel 	if (err != PICL_SUCCESS)
239203831d35Sstevel 		return;
239303831d35Sstevel 
239403831d35Sstevel 	/*
239503831d35Sstevel 	 * walk through the DIMM locations
239603831d35Sstevel 	 */
239703831d35Sstevel 	for (;;) {
239803831d35Sstevel 		err = ptree_get_propval_by_name(banklochdl, PICL_PROP_CHILD,
239903831d35Sstevel 		    &bankfruhdl, sizeof (bankfruhdl));
240003831d35Sstevel 		if (err != PICL_SUCCESS)
240103831d35Sstevel 			goto next_bank;
240203831d35Sstevel 		err = ptree_get_propval_by_name(bankfruhdl, PICL_PROP_CHILD,
240303831d35Sstevel 		    &lochdl, sizeof (lochdl));
240403831d35Sstevel 		if (err != PICL_SUCCESS)
240503831d35Sstevel 			goto next_bank;
240603831d35Sstevel 		for (;;) {
240703831d35Sstevel 			err = ptree_get_propval_by_name(lochdl, PICL_PROP_CHILD,
240803831d35Sstevel 			    &fruhdl, sizeof (fruhdl));
240903831d35Sstevel 			if (err != PICL_SUCCESS)
241003831d35Sstevel 				goto next_dimm;
241103831d35Sstevel 
241203831d35Sstevel 			/*
241303831d35Sstevel 			 * this is a frutree dimm node corresponding to the
241403831d35Sstevel 			 * memory controller that has been added/deleted
241503831d35Sstevel 			 * - so create/delete reference properties
241603831d35Sstevel 			 */
241703831d35Sstevel 			if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
241803831d35Sstevel 				/*
241903831d35Sstevel 				 * find bank name
242003831d35Sstevel 				 */
242103831d35Sstevel 				err = ptree_get_propval_by_name(fruhdl,
242203831d35Sstevel 				    PICL_PROP_DEVICES, &tblhdl,
242303831d35Sstevel 				    sizeof (tblhdl));
242403831d35Sstevel 				if (err != PICL_SUCCESS)
242503831d35Sstevel 					goto next_dimm;
242603831d35Sstevel 				err = ptree_get_propval_by_name(lochdl,
242703831d35Sstevel 				    PICL_PROP_LABEL, label, sizeof (label));
242803831d35Sstevel 				if (err != PICL_SUCCESS)
242903831d35Sstevel 					goto next_dimm;
243003831d35Sstevel 
243103831d35Sstevel 				err = ptree_get_propval_by_name(bankfruhdl,
243203831d35Sstevel 				    PICL_PROP_NAME, bname, sizeof (bname));
243303831d35Sstevel 				if (err != PICL_SUCCESS)
243403831d35Sstevel 					goto next_dimm;
243503831d35Sstevel 
243603831d35Sstevel 				/*
243703831d35Sstevel 				 * find memory group node
243803831d35Sstevel 				 */
243903831d35Sstevel 				err = ptree_get_propval_by_name(nodeh,
244003831d35Sstevel 				    PICL_PROP_CHILD, &memgrphdl,
244103831d35Sstevel 				    sizeof (memgrphdl));
244203831d35Sstevel 				if (err != PICL_SUCCESS)
244303831d35Sstevel 					goto next_dimm;
244403831d35Sstevel 
244503831d35Sstevel 				/*
244603831d35Sstevel 				 * check if this is the right bank - if not
244703831d35Sstevel 				 * move on to sibling
244803831d35Sstevel 				 */
244903831d35Sstevel 				err = ptree_get_propval_by_name(memgrphdl,
245003831d35Sstevel 				    PICL_PROP_ID, &id, sizeof (id));
245103831d35Sstevel 				if (err != PICL_SUCCESS)
245203831d35Sstevel 					goto next_dimm;
245303831d35Sstevel 				if (bname[1] != id + '0') {
245403831d35Sstevel 					err =
245503831d35Sstevel 					    ptree_get_propval_by_name(memgrphdl,
245603831d35Sstevel 					    PICL_PROP_PEER, &memgrphdl,
245703831d35Sstevel 					    sizeof (memgrphdl));
245803831d35Sstevel 					if (err != PICL_SUCCESS)
245903831d35Sstevel 						goto next_dimm;
246003831d35Sstevel 					err =
246103831d35Sstevel 					    ptree_get_propval_by_name(memgrphdl,
246203831d35Sstevel 					    PICL_PROP_ID, &id, sizeof (id));
246303831d35Sstevel 					if (err != PICL_SUCCESS)
246403831d35Sstevel 						goto next_dimm;
246503831d35Sstevel 					if (bname[1] != id + '0')
246603831d35Sstevel 						goto next_dimm;
246703831d35Sstevel 				}
246803831d35Sstevel 
246903831d35Sstevel 				/*
247003831d35Sstevel 				 * got the right bank - now create appropriate
247103831d35Sstevel 				 * link
247203831d35Sstevel 				 */
247303831d35Sstevel 				err = ptree_get_propval_by_name(memgrphdl,
247403831d35Sstevel 				    PICL_PROP_CHILD, &memhdl,
247503831d35Sstevel 				    sizeof (memhdl));
247603831d35Sstevel 				if (err != PICL_SUCCESS)
247703831d35Sstevel 					goto next_dimm;
247803831d35Sstevel 				for (;;) {
247903831d35Sstevel 					err = ptree_get_propval_by_name(memhdl,
248003831d35Sstevel 					    PICL_PROP_ID, &id, sizeof (id));
248103831d35Sstevel 					if (err != PICL_SUCCESS)
248203831d35Sstevel 						goto next_dimm;
248303831d35Sstevel 					if (label[1] == ('0' + id)) {
248403831d35Sstevel 						err = add_prop_ref(memhdl,
248503831d35Sstevel 						    fruhdl,
248603831d35Sstevel 						    PICL_REFPROP_FRU_PARENT);
248703831d35Sstevel 						if (err != PICL_SUCCESS)
248803831d35Sstevel 							return;
248903831d35Sstevel 						err = create_table_entry(tblhdl,
249003831d35Sstevel 						    memhdl,
249103831d35Sstevel 						    PICL_CLASS_MEMORY_MODULE);
249203831d35Sstevel 						if (err != PICL_SUCCESS)
249303831d35Sstevel 							return;
249403831d35Sstevel 					}
249503831d35Sstevel 					err = ptree_get_propval_by_name(memhdl,
249603831d35Sstevel 					    PICL_PROP_PEER,
249703831d35Sstevel 					    &memhdl, sizeof (memhdl));
249803831d35Sstevel 					if (err == PICL_PROPNOTFOUND)
249903831d35Sstevel 						break;
250003831d35Sstevel 					if (err != PICL_SUCCESS)
250103831d35Sstevel 						return;
250203831d35Sstevel 				}
250303831d35Sstevel 			} else if (strcmp(ename, PICLEVENT_MC_REMOVED) == 0) {
250403831d35Sstevel 				/*
250503831d35Sstevel 				 * XXX - no mechanism for deleting row - so
250603831d35Sstevel 				 * delete whole tabel and start again
250703831d35Sstevel 				 */
250803831d35Sstevel 				err = ptree_get_prop_by_name(fruhdl,
250903831d35Sstevel 				    PICL_PROP_DEVICES, &tblproph);
251003831d35Sstevel 				if (err == PICL_SUCCESS) {
251103831d35Sstevel 					err = ptree_delete_prop(tblproph);
251203831d35Sstevel 					if (err != PICL_SUCCESS)
251303831d35Sstevel 						return;
251403831d35Sstevel 					(void) ptree_destroy_prop(tblproph);
251503831d35Sstevel 				}
251603831d35Sstevel 				err = create_table(fruhdl, &tblhdl,
251703831d35Sstevel 				    PICL_PROP_DEVICES);
251803831d35Sstevel 				if (err != PICL_SUCCESS)
251903831d35Sstevel 					return;
252003831d35Sstevel 			}
252103831d35Sstevel next_dimm:
252203831d35Sstevel 			err = ptree_get_propval_by_name(lochdl,
252303831d35Sstevel 			    PICL_PROP_PEER, &lochdl, sizeof (lochdl));
252403831d35Sstevel 			if (err == PICL_PROPNOTFOUND)
252503831d35Sstevel 				break;
252603831d35Sstevel 			if (err != PICL_SUCCESS)
252703831d35Sstevel 				return;
252803831d35Sstevel 		}
252903831d35Sstevel next_bank:
253003831d35Sstevel 		err = ptree_get_propval_by_name(banklochdl,
253103831d35Sstevel 		    PICL_PROP_PEER, &banklochdl, sizeof (banklochdl));
253203831d35Sstevel 		if (err == PICL_PROPNOTFOUND)
253303831d35Sstevel 			break;
253403831d35Sstevel 		if (err != PICL_SUCCESS)
253503831d35Sstevel 			return;
253603831d35Sstevel 	}
253703831d35Sstevel 	/*
253803831d35Sstevel 	 * We don't get an event to say that cpu nodes have been added/
253903831d35Sstevel 	 * deleted (in fact as things stand they are never deleted). However
254003831d35Sstevel 	 * we know that all cpus must be configured before the MC_ADDED event
254103831d35Sstevel 	 * we are handling here. So if the cpu links haven't been set up yet
254203831d35Sstevel 	 * then we do it now.
254303831d35Sstevel 	 */
254403831d35Sstevel 	if (strcmp(ename, PICLEVENT_MC_ADDED) == 0) {
254503831d35Sstevel 		sprintf_buf4(buf, PROC_LOC_PATH, SAFARI_ADDR_TO_SB(value),
254603831d35Sstevel 		    SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value));
254703831d35Sstevel 		err = ptree_get_node_by_path(buf, &lochdl);
254803831d35Sstevel 		if (err != PICL_SUCCESS)
254903831d35Sstevel 			return;
255003831d35Sstevel 		sprintf_buf5(buf, PROC_FRU_PATH, SAFARI_ADDR_TO_SB(value),
255103831d35Sstevel 		    SAFARI_ADDR_TO_SB(value), SAFARI_ADDR_TO_P(value),
255203831d35Sstevel 		    SAFARI_ADDR_TO_P(value));
255303831d35Sstevel 		err = ptree_get_node_by_path(buf, &fruhdl);
255403831d35Sstevel 		if (err != PICL_SUCCESS)
255503831d35Sstevel 			return;
255603831d35Sstevel 		sprintf_buf2(buf, "P%d", SAFARI_ADDR_TO_P(value));
255703831d35Sstevel 		err = ptree_get_propval_by_name(fruhdl,
255803831d35Sstevel 		    PICL_PROP_DEVICES, &tblhdl, sizeof (tblhdl));
255903831d35Sstevel 		if (err != PICL_SUCCESS)
256003831d35Sstevel 			return;
256103831d35Sstevel 		(void) create_cpu_references(buf, fruhdl, tblhdl);
256203831d35Sstevel 	}
256303831d35Sstevel }
256403831d35Sstevel 
256503831d35Sstevel /*
256603831d35Sstevel  * subroutine for add_env_nodes(), and add_led_node(). Adds a sensor
256703831d35Sstevel  * node under the sc node in the platform tree, of name "nodename" and
256803831d35Sstevel  * class "class". Also add UnitAddress property (always 0 as the nodenames
256903831d35Sstevel  * are unique anyway). Add reference property back to parent fru/location node
257003831d35Sstevel  * in frutree and a Devices table entry pointing to this node from the
257103831d35Sstevel  * parent fru/location node in frutree.
257203831d35Sstevel  */
257303831d35Sstevel 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)257403831d35Sstevel add_sensor_node(picl_nodehdl_t fruhdl, picl_nodehdl_t lochdl, char *nodename,
257503831d35Sstevel     char *class, char *prop_class, picl_prophdl_t tblhdl,
257603831d35Sstevel     picl_nodehdl_t *sensorhdlp)
257703831d35Sstevel {
257803831d35Sstevel 	int err;
257903831d35Sstevel 
258003831d35Sstevel 	err = ptree_create_and_add_node(sch, nodename, class, sensorhdlp);
258103831d35Sstevel 	if (err != PICL_SUCCESS) {
258203831d35Sstevel 		syslog(LOG_ERR, ADD_NODE_FAIL, nodename, err);
258303831d35Sstevel 		return (err);
258403831d35Sstevel 	}
258503831d35Sstevel 
258603831d35Sstevel 	err = create_table_entry(tblhdl, *sensorhdlp, class);
258703831d35Sstevel 	if (err != PICL_SUCCESS)
258803831d35Sstevel 		return (err);
258903831d35Sstevel 
259003831d35Sstevel 	err = add_sensor_prop(*sensorhdlp, prop_class);
259103831d35Sstevel 	if (err != PICL_SUCCESS)
259203831d35Sstevel 		return (err);
259303831d35Sstevel 
259403831d35Sstevel 	err = add_prop_charstring(*sensorhdlp, "0", PICL_PROP_UNIT_ADDRESS);
259503831d35Sstevel 	if (err != PICL_SUCCESS)
259603831d35Sstevel 		return (err);
259703831d35Sstevel 
2598*ada2da53SToomas Soome 	if (fruhdl != 0) {
259903831d35Sstevel 		err = add_prop_ref(*sensorhdlp, fruhdl,
260003831d35Sstevel 		    PICL_REFPROP_FRU_PARENT);
260103831d35Sstevel 	} else {
260203831d35Sstevel 		err = add_prop_ref(*sensorhdlp, lochdl,
260303831d35Sstevel 		    PICL_REFPROP_LOC_PARENT);
260403831d35Sstevel 	}
260503831d35Sstevel 	return (err);
260603831d35Sstevel }
260703831d35Sstevel 
260803831d35Sstevel /*
260903831d35Sstevel  * subroutine for add_sensor_node()/add_env_nodes(). Used for adding dynamic
261003831d35Sstevel  * properties
261103831d35Sstevel  */
261203831d35Sstevel static int
add_sensor_prop(picl_nodehdl_t nodeh,char * class)261303831d35Sstevel add_sensor_prop(picl_nodehdl_t nodeh, char *class)
261403831d35Sstevel {
261503831d35Sstevel 	ptree_propinfo_t propinfo;
261603831d35Sstevel 	int err;
261703831d35Sstevel 
261803831d35Sstevel 	if (strcmp(class, PICL_PROP_TEMPERATURE) == 0) {
261903831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
262003831d35Sstevel 		    PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE,
262103831d35Sstevel 		    sizeof (int), class, get_sensor_data, NULL);
262203831d35Sstevel 	} else if (strcmp(class, PICL_PROP_FAN_SPEED) == 0) {
262303831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
262403831d35Sstevel 		    PICL_PTYPE_INT, PICL_READ + PICL_VOLATILE,
262503831d35Sstevel 		    sizeof (int), class, get_sensor_data, NULL);
262603831d35Sstevel 	} else if (strcmp(class, PICL_PROP_FAN_SPEED_UNIT) == 0) {
262703831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
262803831d35Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
262903831d35Sstevel 		    MAX_SPEED_UNIT_LEN, class, get_sensor_data, NULL);
263003831d35Sstevel 	} else if (strcmp(class, PICL_PROP_CONDITION) == 0) {
263103831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
263203831d35Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
263303831d35Sstevel 		    MAX_CONDITION_LEN, class, get_sensor_data, NULL);
263403831d35Sstevel 	} else if (strcmp(class, PICL_PROP_STATE) == 0) {
263503831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
263603831d35Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_WRITE +
263703831d35Sstevel 		    PICL_VOLATILE, MAX_STATE_LEN, class, get_led_data,
263803831d35Sstevel 		    set_led_data);
263903831d35Sstevel 	} else {
264003831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
264103831d35Sstevel 		    PICL_PTYPE_FLOAT, PICL_READ + PICL_VOLATILE,
264203831d35Sstevel 		    sizeof (float), class, get_sensor_data, NULL);
264303831d35Sstevel 	}
264403831d35Sstevel 	if (err != PICL_SUCCESS) {
264503831d35Sstevel 		syslog(LOG_ERR, PROPINFO_FAIL, class, err);
264603831d35Sstevel 		return (err);
264703831d35Sstevel 	}
264803831d35Sstevel 
264903831d35Sstevel 	err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
265003831d35Sstevel 	if (err != PICL_SUCCESS) {
265103831d35Sstevel 		syslog(LOG_ERR, ADD_PROP_FAIL, class, err);
265203831d35Sstevel 		return (err);
265303831d35Sstevel 	}
265403831d35Sstevel 	return (PICL_SUCCESS);
265503831d35Sstevel }
265603831d35Sstevel 
265703831d35Sstevel /*
265803831d35Sstevel  * Get requested kstat
265903831d35Sstevel  */
266003831d35Sstevel static int
open_kstat(char * name,void ** ptr,kstat_ctl_t ** kcp)266103831d35Sstevel open_kstat(char *name, void **ptr, kstat_ctl_t **kcp)
266203831d35Sstevel {
266303831d35Sstevel 	kstat_t *info_ksp;
266403831d35Sstevel 
266503831d35Sstevel 	*kcp = kstat_open();
266603831d35Sstevel 	if (*kcp == NULL) {
266703831d35Sstevel 		syslog(LOG_ERR, KSTAT_FAIL);
266803831d35Sstevel 		return (PICL_FAILURE);
266903831d35Sstevel 	}
267003831d35Sstevel 	info_ksp = kstat_lookup(*kcp, NULL, -1, name);
267103831d35Sstevel 	if (info_ksp == NULL) {
267203831d35Sstevel 		kstat_close(*kcp);
267303831d35Sstevel 		syslog(LOG_ERR, KSTAT_FAIL);
267403831d35Sstevel 		return (PICL_FAILURE);
267503831d35Sstevel 	}
267603831d35Sstevel 	if (kstat_read(*kcp, info_ksp, NULL) == -1) {
267703831d35Sstevel 		kstat_close(*kcp);
267803831d35Sstevel 		syslog(LOG_ERR, KSTAT_FAIL);
267903831d35Sstevel 		return (PICL_FAILURE);
268003831d35Sstevel 	}
268103831d35Sstevel 	*ptr = info_ksp;
268203831d35Sstevel 	return (PICL_SUCCESS);
268303831d35Sstevel }
268403831d35Sstevel 
268503831d35Sstevel /*
268603831d35Sstevel  * dimm status - uses bank-status property on memory-controller node
268703831d35Sstevel  */
268803831d35Sstevel 
268903831d35Sstevel static int
get_dimm_status(ptree_rarg_t * arg,void * result)269003831d35Sstevel get_dimm_status(ptree_rarg_t *arg, void *result)
269103831d35Sstevel {
269203831d35Sstevel 	int err;
269303831d35Sstevel 	int i;
269403831d35Sstevel 	picl_prophdl_t	tblhdl;
269503831d35Sstevel 	picl_prophdl_t  nextprop;
269603831d35Sstevel 	picl_prophdl_t  refprop;
269703831d35Sstevel 	picl_prophdl_t  mmgprop;
269803831d35Sstevel 	picl_prophdl_t  mcprop;
269903831d35Sstevel 	picl_prophdl_t  bankprop;
270003831d35Sstevel 	char	nodename[PICL_PROPNAMELEN_MAX];
270103831d35Sstevel 	char    class[PICL_CLASSNAMELEN_MAX];
270203831d35Sstevel 	char	bankname[PICL_PROPNAMELEN_MAX];
270303831d35Sstevel 	char    state[MAX_STATE_SIZE];
270403831d35Sstevel 
270503831d35Sstevel 	/*
270603831d35Sstevel 	 * find the name of this node
270703831d35Sstevel 	 */
270803831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, nodename,
270903831d35Sstevel 	    sizeof (nodename));
271003831d35Sstevel 	if (err != PICL_SUCCESS) {
271103831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
271203831d35Sstevel 		return (err);
271303831d35Sstevel 	}
271403831d35Sstevel 
271503831d35Sstevel 	/*
271603831d35Sstevel 	 * find the name of grandparent (dimm bank) node
271703831d35Sstevel 	 */
271803831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &bankprop,
271903831d35Sstevel 	    sizeof (picl_nodehdl_t));
272003831d35Sstevel 	if (err != PICL_SUCCESS) {
272103831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
272203831d35Sstevel 		return (err);
272303831d35Sstevel 	}
272403831d35Sstevel 	err = ptree_get_propval_by_name(bankprop, PICL_PROP_PARENT, &bankprop,
272503831d35Sstevel 	    sizeof (picl_nodehdl_t));
272603831d35Sstevel 	if (err != PICL_SUCCESS) {
272703831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
272803831d35Sstevel 		return (err);
272903831d35Sstevel 	}
273003831d35Sstevel 	err = ptree_get_propval_by_name(bankprop, PICL_PROP_NAME, bankname,
273103831d35Sstevel 	    sizeof (bankname));
273203831d35Sstevel 	if (err != PICL_SUCCESS) {
273303831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_NAME, err);
273403831d35Sstevel 		return (err);
273503831d35Sstevel 	}
273603831d35Sstevel 
273703831d35Sstevel 	/*
273803831d35Sstevel 	 * lookup memory-module node in Devices table
273903831d35Sstevel 	 */
274003831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl,
274103831d35Sstevel 	    sizeof (tblhdl));
274203831d35Sstevel 	if (err != PICL_SUCCESS) {
274303831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err);
274403831d35Sstevel 		return (err);
274503831d35Sstevel 	}
274603831d35Sstevel 	err = ptree_get_next_by_row(tblhdl, &nextprop);
274703831d35Sstevel 	if (err != PICL_SUCCESS) {
274803831d35Sstevel 		/*
274903831d35Sstevel 		 * if Devices table empty then dimm is unconfigured
275003831d35Sstevel 		 */
275103831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_DISABLED,
275203831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
275303831d35Sstevel 		return (PICL_SUCCESS);
275403831d35Sstevel 	}
275503831d35Sstevel 	err = ptree_get_next_by_row(nextprop, &nextprop);
275603831d35Sstevel 	if (err != PICL_SUCCESS) {
275703831d35Sstevel 		syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err);
275803831d35Sstevel 		return (err);
275903831d35Sstevel 	}
276003831d35Sstevel 
276103831d35Sstevel 	/*
276203831d35Sstevel 	 * walk down second column (ref ptr)
276303831d35Sstevel 	 */
276403831d35Sstevel 	while (err == PICL_SUCCESS) {
276503831d35Sstevel 		err = ptree_get_propval(nextprop, &refprop, sizeof (refprop));
276603831d35Sstevel 		if (err != PICL_SUCCESS) {
276703831d35Sstevel 			syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
276803831d35Sstevel 			return (PICL_PROPVALUNAVAILABLE);
276903831d35Sstevel 		}
277003831d35Sstevel 		err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME,
277103831d35Sstevel 		    class, sizeof (class));
277203831d35Sstevel 		if (err == PICL_SUCCESS && strcmp(class,
277303831d35Sstevel 		    PICL_CLASS_MEMORY_MODULE) == 0)
277403831d35Sstevel 			break;
277503831d35Sstevel 		if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) {
277603831d35Sstevel 			syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME,
277703831d35Sstevel 			    err);
277803831d35Sstevel 			return (err);
277903831d35Sstevel 		}
278003831d35Sstevel 		err = ptree_get_next_by_col(nextprop, &nextprop);
278103831d35Sstevel 		if (err != PICL_SUCCESS) {
278203831d35Sstevel 			/*
278303831d35Sstevel 			 * if no memory-module in Devices table
278403831d35Sstevel 			 *  then dimm is unconfigured
278503831d35Sstevel 			 */
278603831d35Sstevel 			(void) strlcpy(result, PICL_PROPVAL_DISABLED,
278703831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
278803831d35Sstevel 			return (PICL_SUCCESS);
278903831d35Sstevel 		}
279003831d35Sstevel 	}
279103831d35Sstevel 
279203831d35Sstevel 	/*
279303831d35Sstevel 	 * we've finally found the associated memory-module
279403831d35Sstevel 	 * node. Now need to find the bank-status property on
279503831d35Sstevel 	 * its parent memory-controller.
279603831d35Sstevel 	 */
279703831d35Sstevel 	err = ptree_get_propval_by_name(refprop, PICL_PROP_PARENT,
279803831d35Sstevel 	    &mmgprop, sizeof (picl_nodehdl_t));
279903831d35Sstevel 	if (err != PICL_SUCCESS) {
280003831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
280103831d35Sstevel 		return (err);
280203831d35Sstevel 	}
280303831d35Sstevel 	err = ptree_get_propval_by_name(mmgprop, PICL_PROP_PARENT, &mcprop,
280403831d35Sstevel 	    sizeof (picl_nodehdl_t));
280503831d35Sstevel 	if (err != PICL_SUCCESS) {
280603831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_PARENT, err);
280703831d35Sstevel 		return (err);
280803831d35Sstevel 	}
280903831d35Sstevel 	err = ptree_get_propval_by_name(mcprop, PICL_PROP_BANK_STATUS, &tblhdl,
281003831d35Sstevel 	    sizeof (tblhdl));
281103831d35Sstevel 	if (err != PICL_SUCCESS) {
281203831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
281303831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
281403831d35Sstevel 		return (PICL_SUCCESS);
281503831d35Sstevel 	}
281603831d35Sstevel 
281703831d35Sstevel 	/*
281803831d35Sstevel 	 * bank-status is a table. Need to find the entry corresponding
281903831d35Sstevel 	 * to this node
282003831d35Sstevel 	 */
282103831d35Sstevel 	err = ptree_get_next_by_row(tblhdl, &nextprop);
282203831d35Sstevel 	if (err != PICL_SUCCESS) {
282303831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
282403831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
282503831d35Sstevel 		return (PICL_SUCCESS);
282603831d35Sstevel 	}
282703831d35Sstevel 	for (i = 0; i < 4; i++) {
282803831d35Sstevel 		err = ptree_get_propval(nextprop, &state, sizeof (state));
282903831d35Sstevel 		if (err != PICL_SUCCESS) {
283003831d35Sstevel 			(void) strlcpy(result, PICL_PROPVAL_UNKNOWN,
283103831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
283203831d35Sstevel 			return (err);
283303831d35Sstevel 		}
283403831d35Sstevel 		if ((i & 1) == (bankname[1] - '0')) {
283503831d35Sstevel 			if (strcmp(state, "pass") == 0) {
283603831d35Sstevel 				(void) strlcpy(result, PICL_PROPVAL_OKAY,
283703831d35Sstevel 				    MAX_OPERATIONAL_STATUS_LEN);
283803831d35Sstevel 			} else if (strcmp(state, "fail") == 0) {
283903831d35Sstevel 				(void) strlcpy(result, PICL_PROPVAL_FAILED,
284003831d35Sstevel 				    MAX_OPERATIONAL_STATUS_LEN);
284103831d35Sstevel 			} else {
284203831d35Sstevel 				(void) strlcpy(result, state,
284303831d35Sstevel 				    MAX_OPERATIONAL_STATUS_LEN);
284403831d35Sstevel 			}
284503831d35Sstevel 			break;
284603831d35Sstevel 		}
284703831d35Sstevel 		err = ptree_get_next_by_col(nextprop, &nextprop);
284803831d35Sstevel 		if (err != PICL_SUCCESS) {
284903831d35Sstevel 			(void) strlcpy(result, PICL_PROPVAL_OKAY,
285003831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
285103831d35Sstevel 			break;
285203831d35Sstevel 		}
285303831d35Sstevel 	}
285403831d35Sstevel 	return (PICL_SUCCESS);
285503831d35Sstevel }
285603831d35Sstevel 
285703831d35Sstevel /*
285803831d35Sstevel  * cpu status - uses State property on cpu node
285903831d35Sstevel  */
286003831d35Sstevel 
286103831d35Sstevel static int
get_cpu_status(ptree_rarg_t * arg,void * result)286203831d35Sstevel get_cpu_status(ptree_rarg_t *arg, void *result)
286303831d35Sstevel {
286403831d35Sstevel 	int err;
286503831d35Sstevel 	picl_prophdl_t	tblhdl;
286603831d35Sstevel 	picl_prophdl_t  nextprop;
286703831d35Sstevel 	picl_prophdl_t  refprop;
286803831d35Sstevel 	char    class[PICL_CLASSNAMELEN_MAX];
286903831d35Sstevel 	char    state[MAX_STATE_SIZE];
287003831d35Sstevel 
287103831d35Sstevel 	/*
287203831d35Sstevel 	 * lookup cpu node in Devices table
287303831d35Sstevel 	 */
287403831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_DEVICES, &tblhdl,
287503831d35Sstevel 	    sizeof (tblhdl));
287603831d35Sstevel 	if (err != PICL_SUCCESS) {
287703831d35Sstevel 		syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_DEVICES, err);
287803831d35Sstevel 		return (err);
287903831d35Sstevel 	}
288003831d35Sstevel 	err = ptree_get_next_by_row(tblhdl, &nextprop);
288103831d35Sstevel 	if (err != PICL_SUCCESS) {
288203831d35Sstevel 		/*
288303831d35Sstevel 		 * if Devices table empty then cpu is unconfigured
288403831d35Sstevel 		 */
288503831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_DISABLED,
288603831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
288703831d35Sstevel 		return (PICL_SUCCESS);
288803831d35Sstevel 	}
288903831d35Sstevel 	err = ptree_get_next_by_row(nextprop, &nextprop);
289003831d35Sstevel 	if (err != PICL_SUCCESS) {
289103831d35Sstevel 		syslog(LOG_ERR, GET_NEXT_BY_ROW_FAIL, PICL_PROP_DEVICES, err);
289203831d35Sstevel 		return (err);
289303831d35Sstevel 	}
289403831d35Sstevel 
289503831d35Sstevel 	/*
289603831d35Sstevel 	 * walk down second column (ref ptr)
289703831d35Sstevel 	 */
289803831d35Sstevel 	while (err == PICL_SUCCESS) {
289903831d35Sstevel 		err = ptree_get_propval(nextprop, &refprop, sizeof (refprop));
290003831d35Sstevel 		if (err != PICL_SUCCESS) {
290103831d35Sstevel 			syslog(LOG_ERR, GET_PROPVAL_FAIL, err);
290203831d35Sstevel 			return (err);
290303831d35Sstevel 		}
290403831d35Sstevel 		err = ptree_get_propval_by_name(refprop, PICL_PROP_CLASSNAME,
290503831d35Sstevel 		    class, sizeof (class));
290603831d35Sstevel 		if (err == PICL_SUCCESS && strcmp(class, PICL_CLASS_CPU) == 0)
290703831d35Sstevel 			break;
290803831d35Sstevel 		if (err != PICL_SUCCESS && err != PICL_STALEHANDLE) {
290903831d35Sstevel 			syslog(LOG_ERR, PROP_LOOKUP_FAIL, PICL_PROP_CLASSNAME,
291003831d35Sstevel 			    err);
291103831d35Sstevel 			return (err);
291203831d35Sstevel 		}
291303831d35Sstevel 		err = ptree_get_next_by_col(nextprop, &nextprop);
291403831d35Sstevel 		if (err != PICL_SUCCESS) {
291503831d35Sstevel 			/*
291603831d35Sstevel 			 * if no cpu in Devices table
291703831d35Sstevel 			 *  then cpu is unconfigured
291803831d35Sstevel 			 */
291903831d35Sstevel 			(void) strlcpy(result, PICL_PROPVAL_DISABLED,
292003831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
292103831d35Sstevel 			return (PICL_SUCCESS);
292203831d35Sstevel 		}
292303831d35Sstevel 	}
292403831d35Sstevel 
292503831d35Sstevel 	/*
292603831d35Sstevel 	 * we've finally found the associated cpu node. Now need to find its
292703831d35Sstevel 	 * status property if present (if not assume OK)
292803831d35Sstevel 	 */
292903831d35Sstevel 	err = ptree_get_propval_by_name(refprop, OBP_STATUS,
293003831d35Sstevel 	    state, sizeof (state));
293103831d35Sstevel 	if (err == PICL_SUCCESS) {
293203831d35Sstevel 		if (strcmp(state, "fail") == 0)
293303831d35Sstevel 			(void) strlcpy(result, PICL_PROPVAL_FAILED,
293403831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
293503831d35Sstevel 		else
293603831d35Sstevel 			(void) strlcpy(result, state,
293703831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
293803831d35Sstevel 		return (PICL_SUCCESS);
293903831d35Sstevel 	}
294003831d35Sstevel 
294103831d35Sstevel 	(void) strlcpy(result, PICL_PROPVAL_OKAY, MAX_OPERATIONAL_STATUS_LEN);
294203831d35Sstevel 	return (PICL_SUCCESS);
294303831d35Sstevel }
294403831d35Sstevel 
294503831d35Sstevel /*
294603831d35Sstevel  * system/io board condition - uses sgenv driver kstats
294703831d35Sstevel  */
294803831d35Sstevel 
294903831d35Sstevel static int
get_board_status(ptree_rarg_t * arg,void * result)295003831d35Sstevel get_board_status(ptree_rarg_t *arg, void *result)
295103831d35Sstevel {
295203831d35Sstevel 	int err = PICL_SUCCESS;
295303831d35Sstevel 	int i;
295403831d35Sstevel 	sg_board_info_t	*brd;
295503831d35Sstevel 	char name[PICL_PROPNAMELEN_MAX];
295603831d35Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
295703831d35Sstevel 	kstat_ctl_t *kc;
295803831d35Sstevel 	kstat_t *board_info_ksp;
295903831d35Sstevel 
296003831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
296103831d35Sstevel 	    sizeof (name));
296203831d35Sstevel 	if (err != PICL_SUCCESS) {
296303831d35Sstevel 		return (err);
296403831d35Sstevel 	}
296503831d35Sstevel 
296603831d35Sstevel 	err = open_kstat(SG_BOARD_STATUS_KSTAT_NAME, (void **)&board_info_ksp,
296703831d35Sstevel 	    &kc);
296803831d35Sstevel 	if (err != PICL_SUCCESS) {
296903831d35Sstevel 		return (err);
297003831d35Sstevel 	}
297103831d35Sstevel 
297203831d35Sstevel 	brd = board_info_ksp->ks_data;
297303831d35Sstevel 	for (i = 0; i < SGENV_NUM_BOARD_READINGS(board_info_ksp); i++, brd++) {
297403831d35Sstevel 		/*
297503831d35Sstevel 		 * check this kstat matches the name of the node
297603831d35Sstevel 		 */
297703831d35Sstevel 		if (SG_BOARD_IS_CPU_TYPE(brd->board_num)) {
297803831d35Sstevel 			sprintf_buf3(buf, "%s%d",
297903831d35Sstevel 			    SG_HPU_TYPE_CPU_BOARD_ID, brd->board_num);
298003831d35Sstevel 		} else {
298103831d35Sstevel 			sprintf_buf3(buf, "%s%d",
298203831d35Sstevel 			    SG_HPU_TYPE_PCI_IO_BOARD_ID, brd->board_num);
298303831d35Sstevel 		}
298403831d35Sstevel 		if (strncmp(buf, name, strlen(buf)) != 0)
298503831d35Sstevel 			continue;
298603831d35Sstevel 
298703831d35Sstevel 		/*
298803831d35Sstevel 		 * ok - got the right kstat - get it's value
298903831d35Sstevel 		 * note that values 0-4 are defined in sbdp_mbox.h
299003831d35Sstevel 		 */
299103831d35Sstevel 		if (brd->condition >= 0 && brd->condition < 5)
299203831d35Sstevel 			(void) strlcpy(result,
299303831d35Sstevel 			    hpu_condition_table[brd->condition],
299403831d35Sstevel 			    MAX_OPERATIONAL_STATUS_LEN);
299503831d35Sstevel 		kstat_close(kc);
299603831d35Sstevel 		return (PICL_SUCCESS);
299703831d35Sstevel 	}
299803831d35Sstevel 	kstat_close(kc);
299903831d35Sstevel 	return (PICL_PROPVALUNAVAILABLE);
300003831d35Sstevel }
300103831d35Sstevel 
300203831d35Sstevel static int
get_op_status(ptree_rarg_t * arg,void * result)300303831d35Sstevel get_op_status(ptree_rarg_t *arg, void *result)
300403831d35Sstevel {
300503831d35Sstevel 	int err = PICL_SUCCESS;
300603831d35Sstevel 	char name[PICL_PROPNAMELEN_MAX];
300703831d35Sstevel 	char value[MAX_STATE_LEN];
300803831d35Sstevel 	char	parent_name[PICL_PROPNAMELEN_MAX];
300903831d35Sstevel 	picl_nodehdl_t loch;
301003831d35Sstevel 	picl_nodehdl_t parentfruh;
301103831d35Sstevel 
301203831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
301303831d35Sstevel 	    sizeof (name));
301403831d35Sstevel 	if (err != PICL_SUCCESS) {
301503831d35Sstevel 		return (err);
301603831d35Sstevel 	}
301703831d35Sstevel 
301803831d35Sstevel 	/*
301903831d35Sstevel 	 * handle dimms, cpus and system boards specially
302003831d35Sstevel 	 */
302103831d35Sstevel 	if (IS_PROC_NODE(name)) {
302203831d35Sstevel 		return (get_cpu_status(arg, result));
302303831d35Sstevel 	} else if (IS_DIMM_NODE(name)) {
302403831d35Sstevel 		return (get_dimm_status(arg, result));
302503831d35Sstevel 	} else if (IS_SB_NODE(name) || IS_IB_NODE(name)) {
302603831d35Sstevel 		return (get_board_status(arg, result));
302703831d35Sstevel 	}
302803831d35Sstevel 
302903831d35Sstevel 	/*
303003831d35Sstevel 	 * otherwise OperationalStatus is derived from the fault led state
303103831d35Sstevel 	 */
303203831d35Sstevel 
303303831d35Sstevel 	/*
303403831d35Sstevel 	 * scapp knows FANs 0 and 1 on IB as FAN8 and FAN9
303503831d35Sstevel 	 */
303603831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_PARENT, &loch,
303703831d35Sstevel 	    sizeof (loch));
303803831d35Sstevel 	if (err != PICL_SUCCESS)
303903831d35Sstevel 		return (PICL_PROPVALUNAVAILABLE);
304003831d35Sstevel 	err = ptree_get_propval_by_name(loch, PICL_PROP_PARENT, &parentfruh,
304103831d35Sstevel 	    sizeof (parentfruh));
304203831d35Sstevel 	if (err != PICL_SUCCESS)
304303831d35Sstevel 		return (PICL_PROPVALUNAVAILABLE);
304403831d35Sstevel 	err = ptree_get_propval_by_name(parentfruh, PICL_PROP_NAME, parent_name,
304503831d35Sstevel 	    sizeof (parent_name));
304603831d35Sstevel 	if (err != PICL_SUCCESS)
304703831d35Sstevel 		return (PICL_PROPVALUNAVAILABLE);
304803831d35Sstevel 	if (strcmp(name, "FAN0") == 0 && strcmp(parent_name, "IB6") == 0) {
304903831d35Sstevel 		if (get_led("FAN8", FAULT_LED, value) != PICL_SUCCESS) {
305003831d35Sstevel 			return (PICL_PROPVALUNAVAILABLE);
305103831d35Sstevel 		}
305203831d35Sstevel 	} else if (strcmp(name, "FAN1") == 0 && strcmp(parent_name,
305303831d35Sstevel 	    "IB6") == 0) {
305403831d35Sstevel 		if (get_led("FAN9", FAULT_LED, value) != PICL_SUCCESS) {
305503831d35Sstevel 			return (PICL_PROPVALUNAVAILABLE);
305603831d35Sstevel 		}
305703831d35Sstevel 	} else {
305803831d35Sstevel 		if (get_led(name, FAULT_LED, value) != PICL_SUCCESS) {
305903831d35Sstevel 			return (PICL_PROPVALUNAVAILABLE);
306003831d35Sstevel 		}
306103831d35Sstevel 	}
306203831d35Sstevel 	if (strcmp(value, PICL_PROPVAL_ON) == 0)
306303831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_FAILED,
306403831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
306503831d35Sstevel 	else
306603831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_OKAY,
306703831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN);
306803831d35Sstevel 	return (PICL_SUCCESS);
306903831d35Sstevel }
307003831d35Sstevel 
307103831d35Sstevel static int
add_board_status(picl_nodehdl_t nodeh,char * nodename)307203831d35Sstevel add_board_status(picl_nodehdl_t nodeh, char *nodename)
307303831d35Sstevel {
307403831d35Sstevel 	ptree_propinfo_t propinfo;
307503831d35Sstevel 	int err;
307603831d35Sstevel 	picl_prophdl_t prophdl;
307703831d35Sstevel 
307803831d35Sstevel 	/*
307903831d35Sstevel 	 * check if OperationalStatus property already created for this fru
308003831d35Sstevel 	 */
308103831d35Sstevel 	err = ptree_get_prop_by_name(nodeh, PICL_PROP_OPERATIONAL_STATUS,
308203831d35Sstevel 	    &prophdl);
308303831d35Sstevel 	if (err == PICL_SUCCESS)
308403831d35Sstevel 		return (PICL_SUCCESS);
308503831d35Sstevel 
308603831d35Sstevel 	/*
308703831d35Sstevel 	 * put operational status on dimms, cpus, SBs, IBs, PSUs, FTs, Fans, RPs
308803831d35Sstevel 	 */
308903831d35Sstevel 	if (IS_DIMM_NODE(nodename) || IS_PROC_NODE(nodename) ||
309003831d35Sstevel 	    IS_SB_NODE(nodename) || IS_IB_NODE(nodename) ||
309103831d35Sstevel 	    IS_PSU_NODE(nodename) || IS_FT_NODE(nodename) ||
309203831d35Sstevel 	    IS_FAN_NODE(nodename) || IS_RP_NODE(nodename)) {
309303831d35Sstevel 		err = ptree_init_propinfo(&propinfo, PTREE_PROPINFO_VERSION,
309403831d35Sstevel 		    PICL_PTYPE_CHARSTRING, PICL_READ + PICL_VOLATILE,
309503831d35Sstevel 		    MAX_OPERATIONAL_STATUS_LEN, PICL_PROP_OPERATIONAL_STATUS,
309603831d35Sstevel 		    get_op_status, NULL);
309703831d35Sstevel 		if (err != PICL_SUCCESS) {
309803831d35Sstevel 			syslog(LOG_ERR, PROPINFO_FAIL,
309903831d35Sstevel 			    PICL_PROP_OPERATIONAL_STATUS, err);
310003831d35Sstevel 			return (err);
310103831d35Sstevel 		}
310203831d35Sstevel 		err = ptree_create_and_add_prop(nodeh, &propinfo, NULL, NULL);
310303831d35Sstevel 		if (err != PICL_SUCCESS) {
310403831d35Sstevel 			syslog(LOG_ERR, ADD_PROP_FAIL,
310503831d35Sstevel 			    PICL_PROP_OPERATIONAL_STATUS, err);
310603831d35Sstevel 			return (err);
310703831d35Sstevel 		}
310803831d35Sstevel 	}
310903831d35Sstevel 	return (PICL_SUCCESS);
311003831d35Sstevel }
311103831d35Sstevel 
311203831d35Sstevel /*
311303831d35Sstevel  * environmental information handling - uses sgenv driver kstats
311403831d35Sstevel  */
311503831d35Sstevel 
311603831d35Sstevel static int
add_env_nodes(picl_nodehdl_t nodeh,char * nodename,picl_prophdl_t tblhdl)311703831d35Sstevel add_env_nodes(picl_nodehdl_t nodeh, char *nodename, picl_prophdl_t tblhdl)
311803831d35Sstevel {
311903831d35Sstevel 	int err = PICL_SUCCESS;
312003831d35Sstevel 	env_sensor_t	*env;
312103831d35Sstevel 	int	i;
312203831d35Sstevel 	picl_prophdl_t	tblhdl2;
312303831d35Sstevel 	picl_prophdl_t	frutype;
312403831d35Sstevel 	char fruname[PICL_PROPNAMELEN_MAX];
312503831d35Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
312603831d35Sstevel 	char id[PICL_PROPNAMELEN_MAX];
312703831d35Sstevel 	float scale;
312803831d35Sstevel 	picl_nodehdl_t childh;
312903831d35Sstevel 	picl_nodehdl_t sensorhdl;
313003831d35Sstevel 	kstat_ctl_t *kc;
313103831d35Sstevel 	kstat_t *env_info_ksp;
313203831d35Sstevel 
313303831d35Sstevel 	err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
313403831d35Sstevel 	if (err != PICL_SUCCESS) {
313503831d35Sstevel 		return (err);
313603831d35Sstevel 	}
313703831d35Sstevel 
313803831d35Sstevel 	env = env_info_ksp->ks_data;
313903831d35Sstevel 	for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
314003831d35Sstevel 		/*
314103831d35Sstevel 		 * check values from kstat entry are within valid range
314203831d35Sstevel 		 */
314303831d35Sstevel 		if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT)
314403831d35Sstevel 			continue;
314503831d35Sstevel 		if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB)
314603831d35Sstevel 			continue;
314703831d35Sstevel 		if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC)
314803831d35Sstevel 			continue;
314903831d35Sstevel 		if ((env->sd_id.id.hpu_type >> 8) >=
315003831d35Sstevel 		    (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8))
315103831d35Sstevel 			continue;
315203831d35Sstevel 		if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT)
315303831d35Sstevel 			continue;
315403831d35Sstevel 
315503831d35Sstevel 		/*
315603831d35Sstevel 		 * does this kstat entry belong to this fru?
315703831d35Sstevel 		 * Note sc reports RPS as 10 and 12 via env messages
315803831d35Sstevel 		 * but by 0 and 2 via fru messages, so correct here
315903831d35Sstevel 		 */
316003831d35Sstevel 		if ((env->sd_id.id.hpu_type >> 8) ==
316103831d35Sstevel 		    (SG_HPU_TYPE_REPEATER_BOARD >> 8)) {
316203831d35Sstevel 			sprintf_buf3(fruname, "%s%d",
316303831d35Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
316403831d35Sstevel 			    env->sd_id.id.hpu_slot - 10);
316503831d35Sstevel 		} else {
316603831d35Sstevel 			sprintf_buf3(fruname, "%s%d",
316703831d35Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
316803831d35Sstevel 			    env->sd_id.id.hpu_slot);
316903831d35Sstevel 		}
317003831d35Sstevel 		if (strcmp(nodename, fruname) != 0)
317103831d35Sstevel 			continue;
317203831d35Sstevel 
317303831d35Sstevel 		/*
317403831d35Sstevel 		 * set up FRUType. Note we only want to do this once per fru
317503831d35Sstevel 		 */
317603831d35Sstevel 		err = ptree_get_prop_by_name(nodeh, PICL_PROP_FRU_TYPE,
317703831d35Sstevel 		    &frutype);
317803831d35Sstevel 		if (err != PICL_SUCCESS) {
317903831d35Sstevel 			err = add_prop_charstring(nodeh,
318003831d35Sstevel 			    hpu_fru_type_table[env->sd_id.id.hpu_type >> 8],
318103831d35Sstevel 			    PICL_PROP_FRU_TYPE);
318203831d35Sstevel 			if (err != PICL_SUCCESS)
318303831d35Sstevel 				goto done;
318403831d35Sstevel 		}
318503831d35Sstevel 
318603831d35Sstevel 		/*
318703831d35Sstevel 		 * create the sensor node with a sensible name
318803831d35Sstevel 		 */
318903831d35Sstevel 		switch (env->sd_id.id.sensor_type) {
319003831d35Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
319103831d35Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
319203831d35Sstevel 				sprintf_buf2(id, "t_ambient%d",
319303831d35Sstevel 				    env->sd_id.id.sensor_typenum);
319403831d35Sstevel 			} else {
319503831d35Sstevel 				sprintf_buf3(id, "t_%s%d",
319603831d35Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
319703831d35Sstevel 				    env->sd_id.id.sensor_partnum);
319803831d35Sstevel 			}
319903831d35Sstevel 			break;
320003831d35Sstevel 		case SG_SENSOR_TYPE_CURRENT:
320103831d35Sstevel 			sprintf_buf3(id, "i_%s%d",
320203831d35Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
320303831d35Sstevel 			    env->sd_id.id.sensor_partnum);
320403831d35Sstevel 			break;
320503831d35Sstevel 		case SG_SENSOR_TYPE_COOLING:
320603831d35Sstevel 			sprintf_buf3(id, "ft_%s%d",
320703831d35Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
320803831d35Sstevel 			    env->sd_id.id.sensor_partnum);
320903831d35Sstevel 			break;
321003831d35Sstevel 		default: /* voltage */
321103831d35Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
321203831d35Sstevel 				sprintf_buf3(id, "v_%s%d",
321303831d35Sstevel 				    hpu_sensor_table[env->sd_id.id.sensor_type],
321403831d35Sstevel 				    env->sd_id.id.sensor_typenum);
321503831d35Sstevel 			} else {
321603831d35Sstevel 				sprintf_buf3(id, "v_%s%d",
321703831d35Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
321803831d35Sstevel 				    env->sd_id.id.sensor_partnum);
321903831d35Sstevel 			}
322003831d35Sstevel 			break;
322103831d35Sstevel 		}
322203831d35Sstevel 
322303831d35Sstevel 		/*
322403831d35Sstevel 		 * check if sensor node has already been created
322503831d35Sstevel 		 */
322603831d35Sstevel 		sprintf_buf3(buf, "%s_%s", nodename, id);
3227*ada2da53SToomas Soome 		if (find_child_by_name(sch, buf) != 0)
322803831d35Sstevel 			continue;
322903831d35Sstevel 
323003831d35Sstevel 		if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_COOLING) {
323103831d35Sstevel 			/*
323203831d35Sstevel 			 * create individual fan_unit nodes
323303831d35Sstevel 			 */
323403831d35Sstevel 			childh = nodeh;
323503831d35Sstevel 			sprintf_buf2(fruname, "FAN%d",
323603831d35Sstevel 			    env->sd_id.id.sensor_partnum);
323703831d35Sstevel 			err = add_intermediate_nodes(&childh, fruname,
323803831d35Sstevel 			    &tblhdl2, "fan-unit", "FAN");
323903831d35Sstevel 			if (err != PICL_SUCCESS)
324003831d35Sstevel 				goto done;
324103831d35Sstevel 			err = add_board_status(childh, fruname);
324203831d35Sstevel 			if (err != PICL_SUCCESS)
324303831d35Sstevel 				goto done;
324403831d35Sstevel 		} else if (env->sd_id.id.sensor_part ==
324503831d35Sstevel 		    SG_SENSOR_PART_CHEETAH ||
324603831d35Sstevel 		    ((env->sd_id.id.hpu_type >> 8) ==
324703831d35Sstevel 		    (SG_HPU_TYPE_CPU_BOARD >> 8) &&
324803831d35Sstevel 		    (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_TEMPERATURE) &&
324903831d35Sstevel 		    (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD))) {
325003831d35Sstevel 			/*
325103831d35Sstevel 			 * put sensors under individual processor nodes
325203831d35Sstevel 			 */
325303831d35Sstevel 			childh = nodeh;
325403831d35Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD)
325503831d35Sstevel 				sprintf_buf2(fruname, "P%d",
325603831d35Sstevel 				    env->sd_id.id.sensor_typenum);
325703831d35Sstevel 			else
325803831d35Sstevel 				sprintf_buf2(fruname, "P%d",
325903831d35Sstevel 				    env->sd_id.id.sensor_partnum);
326003831d35Sstevel 			err = add_intermediate_nodes(&childh, fruname,
326103831d35Sstevel 			    &tblhdl2, "cpu", "PROC");
326203831d35Sstevel 			if (err != PICL_SUCCESS)
326303831d35Sstevel 				goto done;
326403831d35Sstevel 		} else {
326503831d35Sstevel 			childh = nodeh;
326603831d35Sstevel 			tblhdl2 = tblhdl;
326703831d35Sstevel 		}
3268*ada2da53SToomas Soome 		err = add_sensor_node(childh, 0, buf,
326903831d35Sstevel 		    hpu_sensor_class_table[env->sd_id.id.sensor_type],
327003831d35Sstevel 		    hpu_sensor_prop_table[env->sd_id.id.sensor_type],
327103831d35Sstevel 		    tblhdl2, &sensorhdl);
327203831d35Sstevel 		if (err != PICL_SUCCESS)
327303831d35Sstevel 			goto done;
327403831d35Sstevel 
327503831d35Sstevel 		/*
327603831d35Sstevel 		 * add additional properties
327703831d35Sstevel 		 */
327803831d35Sstevel 		switch (env->sd_id.id.sensor_type) {
327903831d35Sstevel 		case SG_SENSOR_TYPE_COOLING:
328003831d35Sstevel 			err = add_prop_charstring(sensorhdl, id,
328103831d35Sstevel 			    PICL_PROP_LABEL);
328203831d35Sstevel 			if (err != PICL_SUCCESS)
328303831d35Sstevel 				goto done;
328403831d35Sstevel 			/*
328503831d35Sstevel 			 * add threshold at 75% of full speed
328603831d35Sstevel 			 */
328703831d35Sstevel 			err = add_prop_int(sensorhdl, 75,
328803831d35Sstevel 			    PICL_PROP_LOW_WARNING_THRESHOLD);
328903831d35Sstevel 			if (err != PICL_SUCCESS)
329003831d35Sstevel 				goto done;
329103831d35Sstevel 			err = add_sensor_prop(sensorhdl,
329203831d35Sstevel 			    PICL_PROP_FAN_SPEED_UNIT);
329303831d35Sstevel 			if (err != PICL_SUCCESS)
329403831d35Sstevel 				goto done;
329503831d35Sstevel 			continue;
329603831d35Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
329703831d35Sstevel 			if ((env->sd_id.id.hpu_type >> 8 ==
329803831d35Sstevel 			    (SG_HPU_TYPE_CPU_BOARD >> 8)) &&
329903831d35Sstevel 			    (env->sd_id.id.sensor_part ==
330003831d35Sstevel 			    SG_SENSOR_PART_BOARD)) {
330103831d35Sstevel 				err = add_prop_charstring(sensorhdl,
330203831d35Sstevel 				    PICL_PROPVAL_AMBIENT, PICL_PROP_LABEL);
330303831d35Sstevel 				if (err != PICL_SUCCESS)
330403831d35Sstevel 					goto done;
330503831d35Sstevel 			} else if (env->sd_id.id.sensor_part ==
330603831d35Sstevel 			    SG_SENSOR_PART_CHEETAH) {
330703831d35Sstevel 				err = add_prop_charstring(sensorhdl,
330803831d35Sstevel 				    PICL_PROPVAL_DIE, PICL_PROP_LABEL);
330903831d35Sstevel 				if (err != PICL_SUCCESS)
331003831d35Sstevel 					goto done;
331103831d35Sstevel 			} else {
331203831d35Sstevel 				err = add_prop_charstring(sensorhdl, id,
331303831d35Sstevel 				    PICL_PROP_LABEL);
331403831d35Sstevel 				if (err != PICL_SUCCESS)
331503831d35Sstevel 					goto done;
331603831d35Sstevel 			}
331703831d35Sstevel 			err = add_prop_int(sensorhdl, env->sd_lo_warn /
331803831d35Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_LOW_WARNING);
331903831d35Sstevel 			if (err != PICL_SUCCESS)
332003831d35Sstevel 				goto done;
332103831d35Sstevel 			err = add_prop_int(sensorhdl, env->sd_lo /
332203831d35Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_LOW_SHUTDOWN);
332303831d35Sstevel 			if (err != PICL_SUCCESS)
332403831d35Sstevel 				goto done;
332503831d35Sstevel 			err = add_prop_int(sensorhdl, env->sd_hi_warn /
332603831d35Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_WARNING);
332703831d35Sstevel 			if (err != PICL_SUCCESS)
332803831d35Sstevel 				goto done;
332903831d35Sstevel 			err = add_prop_int(sensorhdl, env->sd_hi /
333003831d35Sstevel 			    SG_TEMPERATURE_SCALE, PICL_PROP_HIGH_SHUTDOWN);
333103831d35Sstevel 			if (err != PICL_SUCCESS)
333203831d35Sstevel 				goto done;
333303831d35Sstevel 			continue;
333403831d35Sstevel 		case SG_SENSOR_TYPE_1_5_VDC:
333503831d35Sstevel 			scale = SG_1_5_VDC_SCALE;
333603831d35Sstevel 			break;
333703831d35Sstevel 		case SG_SENSOR_TYPE_1_8_VDC:
333803831d35Sstevel 			scale = SG_1_8_VDC_SCALE;
333903831d35Sstevel 			break;
334003831d35Sstevel 		case SG_SENSOR_TYPE_2_5_VDC:
334103831d35Sstevel 			scale = SG_2_5_VDC_SCALE;
334203831d35Sstevel 			break;
334303831d35Sstevel 		case SG_SENSOR_TYPE_3_3_VDC:
334403831d35Sstevel 			scale = SG_3_3_VDC_SCALE;
334503831d35Sstevel 			break;
334603831d35Sstevel 		case SG_SENSOR_TYPE_5_VDC:
334703831d35Sstevel 			scale = SG_5_VDC_SCALE;
334803831d35Sstevel 			break;
334903831d35Sstevel 		case SG_SENSOR_TYPE_12_VDC:
335003831d35Sstevel 			scale = SG_12_VDC_SCALE;
335103831d35Sstevel 			break;
335203831d35Sstevel 		case SG_SENSOR_TYPE_48_VDC:
335303831d35Sstevel 			/*
335403831d35Sstevel 			 * The 48VDC sensor is just an indicator - doesn't
335503831d35Sstevel 			 * give reading or thresholds
335603831d35Sstevel 			 */
335703831d35Sstevel 			err = add_prop_charstring(sensorhdl, id,
335803831d35Sstevel 			    PICL_PROP_LABEL);
335903831d35Sstevel 			if (err != PICL_SUCCESS)
336003831d35Sstevel 				goto done;
336103831d35Sstevel 			continue;
336203831d35Sstevel 		case SG_SENSOR_TYPE_CURRENT:
336303831d35Sstevel 			scale = SG_CURRENT_SCALE;
336403831d35Sstevel 			break;
336503831d35Sstevel 		}
336603831d35Sstevel 		err = add_prop_charstring(sensorhdl, id, PICL_PROP_LABEL);
336703831d35Sstevel 		if (err != PICL_SUCCESS)
336803831d35Sstevel 			goto done;
336903831d35Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_lo_warn / scale,
337003831d35Sstevel 		    PICL_PROP_LOW_WARNING);
337103831d35Sstevel 		if (err != PICL_SUCCESS)
337203831d35Sstevel 			goto done;
337303831d35Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_lo / scale,
337403831d35Sstevel 		    PICL_PROP_LOW_SHUTDOWN);
337503831d35Sstevel 		if (err != PICL_SUCCESS)
337603831d35Sstevel 			goto done;
337703831d35Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_hi_warn / scale,
337803831d35Sstevel 		    PICL_PROP_HIGH_WARNING);
337903831d35Sstevel 		if (err != PICL_SUCCESS)
338003831d35Sstevel 			goto done;
338103831d35Sstevel 		err = add_prop_float(sensorhdl, (float)env->sd_hi / scale,
338203831d35Sstevel 		    PICL_PROP_HIGH_SHUTDOWN);
338303831d35Sstevel 		if (err != PICL_SUCCESS)
338403831d35Sstevel 			goto done;
338503831d35Sstevel 	}
338603831d35Sstevel done:
338703831d35Sstevel 	kstat_close(kc);
338803831d35Sstevel 	return (err);
338903831d35Sstevel }
339003831d35Sstevel 
339103831d35Sstevel static int
get_sensor_data(ptree_rarg_t * arg,void * result)339203831d35Sstevel get_sensor_data(ptree_rarg_t *arg, void *result)
339303831d35Sstevel {
339403831d35Sstevel 	int err;				/* return code */
339503831d35Sstevel 	kstat_ctl_t		*kc;
339603831d35Sstevel 	char	name[PICL_PROPNAMELEN_MAX];
339703831d35Sstevel 	ptree_propinfo_t propinfo;
339803831d35Sstevel 	int	i;
339903831d35Sstevel 	env_sensor_t	*env;
340003831d35Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
340103831d35Sstevel 	char buf1[PICL_PROPNAMELEN_MAX];
340203831d35Sstevel 	kstat_t *env_info_ksp;
340303831d35Sstevel 
340403831d35Sstevel 	err = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
340503831d35Sstevel 	    sizeof (name));
340603831d35Sstevel 	if (err != PICL_SUCCESS)
340703831d35Sstevel 		return (err);
340803831d35Sstevel 	err = ptree_get_propinfo(arg->proph, &propinfo);
340903831d35Sstevel 	if (err != PICL_SUCCESS)
341003831d35Sstevel 		return (err);
341103831d35Sstevel 
341203831d35Sstevel 	err = open_kstat(SG_ENV_INFO_KSTAT_NAME, (void **)&env_info_ksp, &kc);
341303831d35Sstevel 	if (err != PICL_SUCCESS) {
341403831d35Sstevel 		return (err);
341503831d35Sstevel 	}
341603831d35Sstevel 
341703831d35Sstevel 	env = env_info_ksp->ks_data;
341803831d35Sstevel 	for (i = 0; i < SGENV_NUM_ENV_READINGS(env_info_ksp); i++, env++) {
341903831d35Sstevel 		/*
342003831d35Sstevel 		 * check kstat values are within range
342103831d35Sstevel 		 */
342203831d35Sstevel 		if (SG_INFO_VALUESTATUS(env->sd_infostamp) != SG_INFO_VALUE_OK)
342303831d35Sstevel 			continue;
342403831d35Sstevel 		if (env->sd_id.id.sensor_type < SG_SENSOR_TYPE_CURRENT)
342503831d35Sstevel 			continue;
342603831d35Sstevel 		if (env->sd_id.id.sensor_type == SG_SENSOR_TYPE_ENVDB)
342703831d35Sstevel 			continue;
342803831d35Sstevel 		if (env->sd_id.id.sensor_type > SG_SENSOR_TYPE_2_5_VDC)
342903831d35Sstevel 			continue;
343003831d35Sstevel 		if ((env->sd_id.id.hpu_type >> 8) >=
343103831d35Sstevel 		    (SG_HPU_TYPE_SUN_FIRE_3800_CENTERPLANE >> 8))
343203831d35Sstevel 			continue;
343303831d35Sstevel 		if (env->sd_id.id.sensor_part > SG_SENSOR_PART_INPUT)
343403831d35Sstevel 			continue;
343503831d35Sstevel 
343603831d35Sstevel 		/*
343703831d35Sstevel 		 * check this kstat matches the name of the node
343803831d35Sstevel 		 * note sc reports RPS as 10 and 12 via env messages
343903831d35Sstevel 		 * but by 0 and 2 via fru messages, so correct here
344003831d35Sstevel 		 */
344103831d35Sstevel 		if ((env->sd_id.id.hpu_type >> 8) ==
344203831d35Sstevel 		    (SG_HPU_TYPE_REPEATER_BOARD >> 8))
344303831d35Sstevel 			sprintf_buf3(buf, "%s%d",
344403831d35Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
344503831d35Sstevel 			    env->sd_id.id.hpu_slot - 10);
344603831d35Sstevel 		else
344703831d35Sstevel 			sprintf_buf3(buf, "%s%d",
344803831d35Sstevel 			    hpu_type_table[env->sd_id.id.hpu_type >> 8],
344903831d35Sstevel 			    env->sd_id.id.hpu_slot);
345003831d35Sstevel 		switch (env->sd_id.id.sensor_type) {
345103831d35Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
345203831d35Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
345303831d35Sstevel 				sprintf_buf3(buf1, "%s_t_ambient%d",
345403831d35Sstevel 				    buf, env->sd_id.id.sensor_typenum);
345503831d35Sstevel 			} else {
345603831d35Sstevel 				sprintf_buf4(buf1, "%s_t_%s%d", buf,
345703831d35Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
345803831d35Sstevel 				    env->sd_id.id.sensor_partnum);
345903831d35Sstevel 			}
346003831d35Sstevel 			break;
346103831d35Sstevel 		case SG_SENSOR_TYPE_CURRENT:
346203831d35Sstevel 			sprintf_buf4(buf1, "%s_i_%s%d", buf,
346303831d35Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
346403831d35Sstevel 			    env->sd_id.id.sensor_partnum);
346503831d35Sstevel 			break;
346603831d35Sstevel 		case SG_SENSOR_TYPE_COOLING:
346703831d35Sstevel 			sprintf_buf4(buf1, "%s_ft_%s%d", buf,
346803831d35Sstevel 			    hpu_part_table[env->sd_id.id.sensor_part],
346903831d35Sstevel 			    env->sd_id.id.sensor_partnum);
347003831d35Sstevel 			break;
347103831d35Sstevel 		default: /* voltage */
347203831d35Sstevel 			if (env->sd_id.id.sensor_part == SG_SENSOR_PART_BOARD) {
347303831d35Sstevel 				sprintf_buf4(buf1, "%s_v_%s%d", buf,
347403831d35Sstevel 				    hpu_sensor_table[env->sd_id.id.sensor_type],
347503831d35Sstevel 				    env->sd_id.id.sensor_typenum);
347603831d35Sstevel 			} else {
347703831d35Sstevel 				sprintf_buf4(buf1, "%s_v_%s%d", buf,
347803831d35Sstevel 				    hpu_part_table[env->sd_id.id.sensor_part],
347903831d35Sstevel 				    env->sd_id.id.sensor_partnum);
348003831d35Sstevel 			}
348103831d35Sstevel 			break;
348203831d35Sstevel 		}
348303831d35Sstevel 		if (strcmp(buf1, name) != 0)
348403831d35Sstevel 			continue;
348503831d35Sstevel 
348603831d35Sstevel 		/*
348703831d35Sstevel 		 * ok - this is the kstat we want - update
348803831d35Sstevel 		 * Condition, or sensor reading as requested
348903831d35Sstevel 		 */
349003831d35Sstevel 		if (strcmp(propinfo.piclinfo.name, PICL_PROP_CONDITION) == 0) {
349103831d35Sstevel 			switch (SG_GET_SENSOR_STATUS(env->sd_status)) {
349203831d35Sstevel 			case SG_SENSOR_STATUS_OK:
349303831d35Sstevel 				(void) strlcpy(result, PICL_PROPVAL_OKAY,
349403831d35Sstevel 				    MAX_CONDITION_LEN);
349503831d35Sstevel 				break;
349603831d35Sstevel 			case SG_SENSOR_STATUS_LO_WARN:
349703831d35Sstevel 			case SG_SENSOR_STATUS_HI_WARN:
349803831d35Sstevel 				(void) strlcpy(result, PICL_PROPVAL_WARNING,
349903831d35Sstevel 				    MAX_CONDITION_LEN);
350003831d35Sstevel 				break;
350103831d35Sstevel 			case SG_SENSOR_STATUS_LO_DANGER:
350203831d35Sstevel 			case SG_SENSOR_STATUS_HI_DANGER:
350303831d35Sstevel 				(void) strlcpy(result, PICL_PROPVAL_FAILED,
350403831d35Sstevel 				    MAX_CONDITION_LEN);
350503831d35Sstevel 				break;
350603831d35Sstevel 			default:
350703831d35Sstevel 				kstat_close(kc);
350803831d35Sstevel 				return (PICL_PROPVALUNAVAILABLE);
350903831d35Sstevel 			}
351003831d35Sstevel 			kstat_close(kc);
351103831d35Sstevel 			return (PICL_SUCCESS);
351203831d35Sstevel 		}
351303831d35Sstevel 		switch (env->sd_id.id.sensor_type) {
351403831d35Sstevel 		case SG_SENSOR_TYPE_TEMPERATURE:
351503831d35Sstevel 			*(int *)result = env->sd_value / SG_TEMPERATURE_SCALE;
351603831d35Sstevel 			break;
351703831d35Sstevel 		case SG_SENSOR_TYPE_1_5_VDC:
351803831d35Sstevel 			*(float *)result =
351903831d35Sstevel 			    (float)env->sd_value / (float)SG_1_5_VDC_SCALE;
352003831d35Sstevel 			break;
352103831d35Sstevel 		case SG_SENSOR_TYPE_1_8_VDC:
352203831d35Sstevel 			*(float *)result =
352303831d35Sstevel 			    (float)env->sd_value / (float)SG_1_8_VDC_SCALE;
352403831d35Sstevel 			break;
352503831d35Sstevel 		case SG_SENSOR_TYPE_2_5_VDC:
352603831d35Sstevel 			*(float *)result =
352703831d35Sstevel 			    (float)env->sd_value / (float)SG_2_5_VDC_SCALE;
352803831d35Sstevel 			break;
352903831d35Sstevel 		case SG_SENSOR_TYPE_3_3_VDC:
353003831d35Sstevel 			*(float *)result =
353103831d35Sstevel 			    (float)env->sd_value / (float)SG_3_3_VDC_SCALE;
353203831d35Sstevel 			break;
353303831d35Sstevel 		case SG_SENSOR_TYPE_5_VDC:
353403831d35Sstevel 			*(float *)result =
353503831d35Sstevel 			    (float)env->sd_value / (float)SG_5_VDC_SCALE;
353603831d35Sstevel 			break;
353703831d35Sstevel 		case SG_SENSOR_TYPE_12_VDC:
353803831d35Sstevel 			*(float *)result =
353903831d35Sstevel 			    (float)env->sd_value / (float)SG_12_VDC_SCALE;
354003831d35Sstevel 			break;
354103831d35Sstevel 		case SG_SENSOR_TYPE_CURRENT:
354203831d35Sstevel 			*(float *)result =
354303831d35Sstevel 			    (float)env->sd_value / (float)SG_CURRENT_SCALE;
354403831d35Sstevel 			break;
354503831d35Sstevel 		case SG_SENSOR_TYPE_COOLING:
354603831d35Sstevel 			if (strcmp(propinfo.piclinfo.name,
354703831d35Sstevel 			    PICL_PROP_FAN_SPEED_UNIT) == 0) {
354803831d35Sstevel 				if (SG_GET_SENSOR_STATUS(env->sd_status) ==
354903831d35Sstevel 				    SG_SENSOR_STATUS_FAN_LOW) {
355003831d35Sstevel 					(void) strlcpy(result,
355103831d35Sstevel 					    PICL_PROPVAL_SELF_REGULATING,
355203831d35Sstevel 					    MAX_SPEED_UNIT_LEN);
355303831d35Sstevel 				} else {
355403831d35Sstevel 					(void) strlcpy(result,
355503831d35Sstevel 					    PICL_PROPVAL_PER_CENT,
355603831d35Sstevel 					    MAX_SPEED_UNIT_LEN);
355703831d35Sstevel 				}
355803831d35Sstevel 			} else {
355903831d35Sstevel 				switch (SG_GET_SENSOR_STATUS(env->sd_status)) {
356003831d35Sstevel 				case SG_SENSOR_STATUS_FAN_HIGH:
356103831d35Sstevel 					*(int *)result = 100;
356203831d35Sstevel 					break;
356303831d35Sstevel 				case SG_SENSOR_STATUS_FAN_FAIL:
356403831d35Sstevel 				case SG_SENSOR_STATUS_FAN_OFF:
356503831d35Sstevel 					*(int *)result = 0;
356603831d35Sstevel 					break;
356703831d35Sstevel 				default:
356803831d35Sstevel 				case SG_SENSOR_STATUS_FAN_LOW:
356903831d35Sstevel 					kstat_close(kc);
357003831d35Sstevel 					return (PICL_PROPVALUNAVAILABLE);
357103831d35Sstevel 				}
357203831d35Sstevel 			}
357303831d35Sstevel 			break;
357403831d35Sstevel 		default:
357503831d35Sstevel 			kstat_close(kc);
357603831d35Sstevel 			return (PICL_PROPVALUNAVAILABLE);
357703831d35Sstevel 		}
357803831d35Sstevel 		kstat_close(kc);
357903831d35Sstevel 		return (PICL_SUCCESS);
358003831d35Sstevel 	}
358103831d35Sstevel 	kstat_close(kc);
358203831d35Sstevel 	return (PICL_PROPVALUNAVAILABLE);
358303831d35Sstevel }
358403831d35Sstevel 
358503831d35Sstevel /*
358603831d35Sstevel  * led information handling - uses lw8 driver
358703831d35Sstevel  */
358803831d35Sstevel 
358903831d35Sstevel static int
add_led_nodes(picl_nodehdl_t nodeh,char * name,int position,picl_prophdl_t tblhdl)359003831d35Sstevel add_led_nodes(picl_nodehdl_t nodeh, char *name, int position,
359103831d35Sstevel     picl_prophdl_t tblhdl)
359203831d35Sstevel {
359303831d35Sstevel 	int err;
359403831d35Sstevel 	int  ledfd;
359503831d35Sstevel 	lom_get_led_t lom_get_led;
359603831d35Sstevel 	picl_nodehdl_t sensorhdl;
359703831d35Sstevel 	char buf[PICL_PROPNAMELEN_MAX];
359803831d35Sstevel 
359903831d35Sstevel 	/*
360003831d35Sstevel 	 * Open the lw8 pseudo dev to get the led information
360103831d35Sstevel 	 */
360203831d35Sstevel 	if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
360303831d35Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
360403831d35Sstevel 		return (PICL_SUCCESS);
360503831d35Sstevel 	}
360603831d35Sstevel 	bzero(&lom_get_led, sizeof (lom_get_led));
360703831d35Sstevel 	(void) strlcpy(lom_get_led.location, name,
360803831d35Sstevel 	    sizeof (lom_get_led.location));
360903831d35Sstevel 	if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
361003831d35Sstevel 		(void) close(ledfd);
361103831d35Sstevel 		syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
361203831d35Sstevel 		return (PICL_FAILURE);
361303831d35Sstevel 	}
361403831d35Sstevel 	while (lom_get_led.next_id[0] != '\0') {
361503831d35Sstevel 		(void) strlcpy(lom_get_led.id, lom_get_led.next_id,
361603831d35Sstevel 		    sizeof (lom_get_led.id));
361703831d35Sstevel 		lom_get_led.next_id[0] = '\0';
361803831d35Sstevel 		lom_get_led.position = LOM_LED_POSITION_FRU;
361903831d35Sstevel 		if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
362003831d35Sstevel 			(void) close(ledfd);
362103831d35Sstevel 			syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
362203831d35Sstevel 			return (PICL_FAILURE);
362303831d35Sstevel 		}
362403831d35Sstevel 		sprintf_buf3(buf, "%s_%s", name, lom_get_led.id);
362503831d35Sstevel 		if (position != lom_get_led.position)
362603831d35Sstevel 			continue;
362703831d35Sstevel 		if (position == LOM_LED_POSITION_LOCATION) {
3628*ada2da53SToomas Soome 			err = add_sensor_node(0, nodeh, buf, PICL_CLASS_LED,
362903831d35Sstevel 			    PICL_PROP_STATE, tblhdl, &sensorhdl);
363003831d35Sstevel 		} else {
3631*ada2da53SToomas Soome 			err = add_sensor_node(nodeh, 0, buf, PICL_CLASS_LED,
363203831d35Sstevel 			    PICL_PROP_STATE, tblhdl, &sensorhdl);
363303831d35Sstevel 		}
363403831d35Sstevel 		if (err != PICL_SUCCESS) {
363503831d35Sstevel 			(void) close(ledfd);
363603831d35Sstevel 			return (err);
363703831d35Sstevel 		}
363803831d35Sstevel 		if (strcmp(name, "chassis") == 0 && strcmp(lom_get_led.id,
363903831d35Sstevel 		    "locator") == 0) {
364003831d35Sstevel 			err = add_prop_charstring(sensorhdl, PICL_PROPVAL_TRUE,
364103831d35Sstevel 			    PICL_PROP_IS_LOCATOR);
364203831d35Sstevel 			if (err != PICL_SUCCESS) {
364303831d35Sstevel 				(void) close(ledfd);
364403831d35Sstevel 				return (err);
364503831d35Sstevel 			}
364603831d35Sstevel 			err = add_prop_charstring(sensorhdl,
364703831d35Sstevel 			    PICL_PROPVAL_SYSTEM, PICL_PROP_LOCATOR_NAME);
364803831d35Sstevel 			if (err != PICL_SUCCESS) {
364903831d35Sstevel 				(void) close(ledfd);
365003831d35Sstevel 				return (err);
365103831d35Sstevel 			}
365203831d35Sstevel 		}
365303831d35Sstevel 		err = add_prop_charstring(sensorhdl, lom_get_led.id,
365403831d35Sstevel 		    PICL_PROP_LABEL);
365503831d35Sstevel 		if (err != PICL_SUCCESS) {
365603831d35Sstevel 			(void) close(ledfd);
365703831d35Sstevel 			return (err);
365803831d35Sstevel 		}
365903831d35Sstevel 		err = add_prop_charstring(sensorhdl, lom_get_led.color,
366003831d35Sstevel 		    PICL_PROP_COLOR);
366103831d35Sstevel 		if (err != PICL_SUCCESS) {
366203831d35Sstevel 			(void) close(ledfd);
366303831d35Sstevel 			return (err);
366403831d35Sstevel 		}
366503831d35Sstevel 	}
366603831d35Sstevel 	(void) close(ledfd);
366703831d35Sstevel 	return (PICL_SUCCESS);
366803831d35Sstevel }
366903831d35Sstevel 
367003831d35Sstevel static int
get_led(char * name,char * ptr,char * result)367103831d35Sstevel get_led(char *name, char *ptr, char *result)
367203831d35Sstevel {
367303831d35Sstevel 	int ledfd;
367403831d35Sstevel 	lom_get_led_t lom_get_led;
367503831d35Sstevel 
367603831d35Sstevel 	/*
367703831d35Sstevel 	 * Open the lw8 pseudo dev to get the led information
367803831d35Sstevel 	 */
367903831d35Sstevel 	if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
368003831d35Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
368103831d35Sstevel 		return (PICL_FAILURE);
368203831d35Sstevel 	}
368303831d35Sstevel 	bzero(&lom_get_led, sizeof (lom_get_led));
368403831d35Sstevel 	(void) strlcpy(lom_get_led.location, name,
368503831d35Sstevel 	    sizeof (lom_get_led.location));
368603831d35Sstevel 	(void) strlcpy(lom_get_led.id, ptr, sizeof (lom_get_led.id));
368703831d35Sstevel 	if (ioctl(ledfd, LOMIOCGETLED, &lom_get_led) == -1) {
368803831d35Sstevel 		(void) close(ledfd);
368903831d35Sstevel 		syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
369003831d35Sstevel 		return (PICL_PROPVALUNAVAILABLE);
369103831d35Sstevel 	}
369203831d35Sstevel 	if (lom_get_led.status == LOM_LED_STATUS_ON)
369303831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_ON, MAX_STATE_LEN);
369403831d35Sstevel 	else if (lom_get_led.status == LOM_LED_STATUS_FLASHING)
369503831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_FLASHING, MAX_STATE_LEN);
369603831d35Sstevel 	else if (lom_get_led.status == LOM_LED_STATUS_BLINKING)
369703831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_BLINKING, MAX_STATE_LEN);
369803831d35Sstevel 	else
369903831d35Sstevel 		(void) strlcpy(result, PICL_PROPVAL_OFF, MAX_STATE_LEN);
370003831d35Sstevel 	(void) close(ledfd);
370103831d35Sstevel 	return (PICL_SUCCESS);
370203831d35Sstevel }
370303831d35Sstevel 
370403831d35Sstevel static int
get_led_data(ptree_rarg_t * arg,void * result)370503831d35Sstevel get_led_data(ptree_rarg_t *arg, void *result)
370603831d35Sstevel {
370703831d35Sstevel 	int rc;				/* return code */
370803831d35Sstevel 	char	name[PICL_PROPNAMELEN_MAX];
370903831d35Sstevel 	char *ptr;
371003831d35Sstevel 
371103831d35Sstevel 	rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
371203831d35Sstevel 	    sizeof (name));
371303831d35Sstevel 	if (rc != PICL_SUCCESS)
371403831d35Sstevel 		return (rc);
371503831d35Sstevel 
371603831d35Sstevel 	ptr = strchr(name, '_');
371703831d35Sstevel 	*ptr++ = '\0'; /* now name is fru name, ptr is led name */
371803831d35Sstevel 	return (get_led(name, ptr, (char *)result));
371903831d35Sstevel }
372003831d35Sstevel 
372103831d35Sstevel static int
set_led(char * name,char * ptr,char * value)372203831d35Sstevel set_led(char *name, char *ptr, char *value)
372303831d35Sstevel {
372403831d35Sstevel 	int ledfd;
372503831d35Sstevel 	lom_set_led_t lom_set_led;
372603831d35Sstevel 
372703831d35Sstevel 	/*
372803831d35Sstevel 	 * Open the lw8 pseudo dev to set the led information
372903831d35Sstevel 	 */
373003831d35Sstevel 	if ((ledfd = open(LED_PSEUDO_DEV, O_RDWR, 0)) == -1) {
373103831d35Sstevel 		syslog(LOG_ERR, DEV_OPEN_FAIL, LED_PSEUDO_DEV, strerror(errno));
373203831d35Sstevel 		return (PICL_FAILURE);
373303831d35Sstevel 	}
373403831d35Sstevel 	bzero(&lom_set_led, sizeof (lom_set_led));
373503831d35Sstevel 	(void) strlcpy(lom_set_led.location, name,
373603831d35Sstevel 	    sizeof (lom_set_led.location));
373703831d35Sstevel 	(void) strlcpy(lom_set_led.id, ptr, sizeof (lom_set_led.id));
373803831d35Sstevel 	if (strcmp(value, PICL_PROPVAL_ON) == 0) {
373903831d35Sstevel 		lom_set_led.status = LOM_LED_STATUS_ON;
374003831d35Sstevel 	} else if (strcmp(value, PICL_PROPVAL_FLASHING) == 0) {
374103831d35Sstevel 		lom_set_led.status = LOM_LED_STATUS_FLASHING;
374203831d35Sstevel 	} else if (strcmp(value, PICL_PROPVAL_BLINKING) == 0) {
374303831d35Sstevel 		lom_set_led.status = LOM_LED_STATUS_BLINKING;
374403831d35Sstevel 	} else {
374503831d35Sstevel 		lom_set_led.status = LOM_LED_STATUS_OFF;
374603831d35Sstevel 	}
374703831d35Sstevel 	if (ioctl(ledfd, LOMIOCSETLED, &lom_set_led) == -1) {
374803831d35Sstevel 		(void) close(ledfd);
374903831d35Sstevel 		syslog(LOG_ERR, LED_IOCTL_FAIL, strerror(errno));
375003831d35Sstevel 		return (PICL_PROPVALUNAVAILABLE);
375103831d35Sstevel 	}
375203831d35Sstevel 	(void) close(ledfd);
375303831d35Sstevel 	return (PICL_SUCCESS);
375403831d35Sstevel }
375503831d35Sstevel 
375603831d35Sstevel static int
set_led_data(ptree_warg_t * arg,const void * value)375703831d35Sstevel set_led_data(ptree_warg_t *arg, const void *value)
375803831d35Sstevel {
375903831d35Sstevel 	int rc;				/* return code */
376003831d35Sstevel 	char	name[PICL_PROPNAMELEN_MAX];
376103831d35Sstevel 	char *ptr;
376203831d35Sstevel 
376303831d35Sstevel 	rc = ptree_get_propval_by_name(arg->nodeh, PICL_PROP_NAME, name,
376403831d35Sstevel 	    sizeof (name));
376503831d35Sstevel 	if (rc != PICL_SUCCESS)
376603831d35Sstevel 		return (rc);
376703831d35Sstevel 
376803831d35Sstevel 	ptr = strchr(name, '_');
376903831d35Sstevel 	*ptr++ = '\0'; /* now name is fru name, ptr is led name */
377003831d35Sstevel 	return (set_led(name, ptr, (char *)value));
377103831d35Sstevel }
377203831d35Sstevel 
377303831d35Sstevel static void
disk_leds_init(void)377403831d35Sstevel disk_leds_init(void)
377503831d35Sstevel {
377603831d35Sstevel 	int err = 0, i;
377703831d35Sstevel 
377803831d35Sstevel 	if (!g_mutex_init) {
377903831d35Sstevel 		if ((pthread_cond_init(&g_cv, NULL) == 0) &&
378003831d35Sstevel 		    (pthread_cond_init(&g_cv_ack, NULL) == 0) &&
378103831d35Sstevel 		    (pthread_mutex_init(&g_mutex, NULL) == 0)) {
378203831d35Sstevel 			g_mutex_init = B_TRUE;
378303831d35Sstevel 		} else {
378403831d35Sstevel 			return;
378503831d35Sstevel 		}
378603831d35Sstevel 	}
378703831d35Sstevel 
378803831d35Sstevel 	if (ledsthr_created) {
378903831d35Sstevel 		/*
379003831d35Sstevel 		 * this is a restart, wake up sleeping threads
379103831d35Sstevel 		 */
379203831d35Sstevel 		err = pthread_mutex_lock(&g_mutex);
379303831d35Sstevel 		if (err != 0) {
379403831d35Sstevel 			syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
379503831d35Sstevel 			return;
379603831d35Sstevel 		}
379703831d35Sstevel 		g_wait_now = B_FALSE;
379803831d35Sstevel 		(void) pthread_cond_broadcast(&g_cv);
379903831d35Sstevel 		(void) pthread_mutex_unlock(&g_mutex);
380003831d35Sstevel 	} else {
380103831d35Sstevel 		if ((pthread_attr_init(&ledsthr_attr) != 0) ||
380203831d35Sstevel 		    (pthread_attr_setscope(&ledsthr_attr,
380303831d35Sstevel 		    PTHREAD_SCOPE_SYSTEM) != 0))
380403831d35Sstevel 			return;
380503831d35Sstevel 		if ((err = pthread_create(&ledsthr_tid, &ledsthr_attr,
380603831d35Sstevel 		    disk_leds_thread, NULL)) != 0) {
380703831d35Sstevel 			syslog(LOG_ERR, EM_THREAD_CREATE_FAILED, strerror(err));
380803831d35Sstevel 			return;
380903831d35Sstevel 		}
381003831d35Sstevel 		ledsthr_created = B_TRUE;
381103831d35Sstevel 	}
381203831d35Sstevel 	for (i = 0; i < N_DISKS; i++) {
381303831d35Sstevel 		(void) set_led(lw8_disks[i].d_fruname, FAULT_LED,
381403831d35Sstevel 		    PICL_PROPVAL_OFF);
381503831d35Sstevel 	}
381603831d35Sstevel }
381703831d35Sstevel 
381803831d35Sstevel static void
disk_leds_fini(void)381903831d35Sstevel disk_leds_fini(void)
382003831d35Sstevel {
382103831d35Sstevel 	int	err;
382203831d35Sstevel 
382303831d35Sstevel 	/*
382403831d35Sstevel 	 * tell led thread to pause
382503831d35Sstevel 	 */
382603831d35Sstevel 	if (!ledsthr_created)
382703831d35Sstevel 		return;
382803831d35Sstevel 	err = pthread_mutex_lock(&g_mutex);
382903831d35Sstevel 	if (err != 0) {
383003831d35Sstevel 		syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
383103831d35Sstevel 		return;
383203831d35Sstevel 	}
383303831d35Sstevel 	g_wait_now = B_TRUE;
383403831d35Sstevel 	disk_leds_thread_ack = B_FALSE;
383503831d35Sstevel 	(void) pthread_cond_broadcast(&g_cv);
383603831d35Sstevel 
383703831d35Sstevel 	/*
383803831d35Sstevel 	 * and wait for the led thread to acknowledge
383903831d35Sstevel 	 */
384003831d35Sstevel 	while (!disk_leds_thread_ack) {
384103831d35Sstevel 		(void) pthread_cond_wait(&g_cv_ack, &g_mutex);
384203831d35Sstevel 	}
384303831d35Sstevel 	(void) pthread_mutex_unlock(&g_mutex);
384403831d35Sstevel }
384503831d35Sstevel 
384603831d35Sstevel static void
update_disk_node(struct lw8_disk * diskp)384703831d35Sstevel update_disk_node(struct lw8_disk *diskp)
384803831d35Sstevel {
384903831d35Sstevel 	picl_nodehdl_t slotndh;
385003831d35Sstevel 	picl_nodehdl_t diskndh;
385103831d35Sstevel 	picl_nodehdl_t devhdl;
385203831d35Sstevel 	picl_prophdl_t	tblhdl;
385303831d35Sstevel 	int err;
385403831d35Sstevel 	char path[MAXPATHLEN];
385503831d35Sstevel 	char *fruname = diskp->d_fruname;
385603831d35Sstevel 
385703831d35Sstevel 	sprintf_buf2(path, CHASSIS_LOC_PATH, fruname);
385803831d35Sstevel 	if (ptree_get_node_by_path(path, &slotndh) != PICL_SUCCESS) {
385903831d35Sstevel 		return;
386003831d35Sstevel 	}
386103831d35Sstevel 	diskndh = find_child_by_name(slotndh, fruname);
386203831d35Sstevel 	err = ptree_get_node_by_path(diskp->d_plat_path, &devhdl);
386303831d35Sstevel 	if (err == PICL_SUCCESS) {
3864*ada2da53SToomas Soome 		if (diskndh != 0)
386503831d35Sstevel 			return;
386603831d35Sstevel 		err = ptree_create_and_add_node(slotndh, fruname,
386703831d35Sstevel 		    PICL_CLASS_FRU, &diskndh);
386803831d35Sstevel 		if (err != PICL_SUCCESS) {
386903831d35Sstevel 			syslog(LOG_ERR, ADD_NODE_FAIL, fruname, err);
387003831d35Sstevel 			return;
387103831d35Sstevel 		}
387203831d35Sstevel 		err = create_table(diskndh, &tblhdl, PICL_PROP_DEVICES);
387303831d35Sstevel 		if (err != PICL_SUCCESS)
387403831d35Sstevel 			return;
387503831d35Sstevel 		err = create_table_entry(tblhdl, devhdl, PICL_CLASS_BLOCK);
387603831d35Sstevel 		if (err != PICL_SUCCESS)
387703831d35Sstevel 			return;
387803831d35Sstevel 		err = add_prop_ref(devhdl, diskndh, PICL_REFPROP_FRU_PARENT);
387903831d35Sstevel 		if (err != PICL_SUCCESS)
388003831d35Sstevel 			return;
388103831d35Sstevel 	} else {
3882*ada2da53SToomas Soome 		if (diskndh == 0)
388303831d35Sstevel 			return;
388403831d35Sstevel 		err = ptree_delete_node(diskndh);
388503831d35Sstevel 		if (err != PICL_SUCCESS)
388603831d35Sstevel 			return;
388703831d35Sstevel 		(void) ptree_destroy_node(diskndh);
388803831d35Sstevel 	}
388903831d35Sstevel }
389003831d35Sstevel 
389103831d35Sstevel /*
389203831d35Sstevel  * Implement a state machine in order to:
389303831d35Sstevel  *
389403831d35Sstevel  *  o enable/disable disk LEDs
389503831d35Sstevel  *  o add/delete the disk's node in the FRU tree
389603831d35Sstevel  *
389703831d35Sstevel  * The machine changes state based on the current, in-memory
389803831d35Sstevel  * state of the disk (eg, the d_state field of 'struct lw8_disk')
389903831d35Sstevel  * and libdevice's current view of whether the disk is
390003831d35Sstevel  * Configured or Unconfigured.
390103831d35Sstevel  *
390203831d35Sstevel  * If the new state is the same as the previous state, then
390303831d35Sstevel  * no side effects occur.  Otherwise, the LEDs for the
390403831d35Sstevel  * disk are set and the disk's associated node in the
390503831d35Sstevel  * FRU Tree is added or deleted.
390603831d35Sstevel  */
390703831d35Sstevel static void
set_disk_leds(struct lw8_disk * disk)390803831d35Sstevel set_disk_leds(struct lw8_disk *disk)
390903831d35Sstevel {
391003831d35Sstevel 	devctl_hdl_t	dhdl;
391103831d35Sstevel 	uint_t		cur_state = 0;
391203831d35Sstevel 
391303831d35Sstevel 	dhdl = devctl_device_acquire(disk->d_devices_path, 0);
391403831d35Sstevel 	if (dhdl == NULL) {
391503831d35Sstevel 		int err = errno;
391603831d35Sstevel 		syslog(LOG_ERR, DEVCTL_DEVICE_ACQUIRE_FAILED,
391703831d35Sstevel 		    strerror(err));
391803831d35Sstevel 		return;
391903831d35Sstevel 	}
392003831d35Sstevel 	devctl_device_getstate(dhdl, &cur_state);
392103831d35Sstevel 	devctl_release(dhdl);
392203831d35Sstevel 
392303831d35Sstevel 	if ((cur_state & DEVICE_OFFLINE) != 0) {
392403831d35Sstevel 		switch (disk->d_state) {
392503831d35Sstevel 		default:
392603831d35Sstevel 			/*
392703831d35Sstevel 			 * State machine should never get here.
392803831d35Sstevel 			 * When NDEBUG is defined, control will
392903831d35Sstevel 			 * fall through and force d_state to
393003831d35Sstevel 			 * match the semantics of "DEVICE_OFFLINE".
393103831d35Sstevel 			 * During development, NDEBUG can be undefined,
393203831d35Sstevel 			 * and this will fire an assertion.
393303831d35Sstevel 			 */
393403831d35Sstevel 			assert(0);
393503831d35Sstevel 			/*FALLTHROUGH*/
393603831d35Sstevel 
393703831d35Sstevel 		case DISK_STATE_NOT_INIT:
393803831d35Sstevel 		case DISK_STATE_READY:
393903831d35Sstevel 			disk->d_state = DISK_STATE_NOT_READY;
394003831d35Sstevel 
394103831d35Sstevel 			(void) set_led(disk->d_fruname, POWER_LED,
394203831d35Sstevel 			    PICL_PROPVAL_OFF);
394303831d35Sstevel 			(void) set_led(disk->d_fruname, REMOK_LED,
394403831d35Sstevel 			    PICL_PROPVAL_ON);
394503831d35Sstevel 
394603831d35Sstevel 			update_disk_node(disk);
394703831d35Sstevel 			break;
394803831d35Sstevel 
394903831d35Sstevel 		case DISK_STATE_NOT_READY:
395003831d35Sstevel 			break;
395103831d35Sstevel 		}
395203831d35Sstevel 	} else if ((cur_state & DEVICE_ONLINE) != 0) {
395303831d35Sstevel 		switch (disk->d_state) {
395403831d35Sstevel 		default:
395503831d35Sstevel 			/*
395603831d35Sstevel 			 * State machine should never get here.
395703831d35Sstevel 			 * When NDEBUG is defined, control will
395803831d35Sstevel 			 * fall through and force d_state to
395903831d35Sstevel 			 * match the semantics of "DEVICE_ONLINE".
396003831d35Sstevel 			 * During development, NDEBUG can be undefined,
396103831d35Sstevel 			 * and this will fire an assertion.
396203831d35Sstevel 			 */
396303831d35Sstevel 			assert(0);
396403831d35Sstevel 			/*FALLTHROUGH*/
396503831d35Sstevel 
396603831d35Sstevel 		case DISK_STATE_NOT_INIT:
396703831d35Sstevel 		case DISK_STATE_NOT_READY:
396803831d35Sstevel 			disk->d_state = DISK_STATE_READY;
396903831d35Sstevel 
397003831d35Sstevel 			(void) set_led(disk->d_fruname, REMOK_LED,
397103831d35Sstevel 			    PICL_PROPVAL_OFF);
397203831d35Sstevel 			(void) set_led(disk->d_fruname, POWER_LED,
397303831d35Sstevel 			    PICL_PROPVAL_ON);
397403831d35Sstevel 
397503831d35Sstevel 			update_disk_node(disk);
397603831d35Sstevel 			break;
397703831d35Sstevel 
397803831d35Sstevel 		case DISK_STATE_READY:
397903831d35Sstevel 			break;
398003831d35Sstevel 		}
398103831d35Sstevel 	}
398203831d35Sstevel }
398303831d35Sstevel 
398403831d35Sstevel /*
398503831d35Sstevel  * NOTE: this implementation of disk_leds_thread is based on the version in
398603831d35Sstevel  * plugins/sun4u/mpxu/frudr/piclfrudr.c (with V440 raid support removed). Some
398703831d35Sstevel  * day the source code layout and build environment should support common code
398803831d35Sstevel  * used by platform specific plugins, in which case LW8 support could be added
398903831d35Sstevel  * to the mpxu version (which would be moved to a common directory).
399003831d35Sstevel  */
399103831d35Sstevel /*ARGSUSED*/
399203831d35Sstevel static void *
disk_leds_thread(void * args)399303831d35Sstevel disk_leds_thread(void *args)
399403831d35Sstevel {
399503831d35Sstevel 	int	i;
399603831d35Sstevel 	int	err = 0;
399703831d35Sstevel 	int	n_disks = N_DISKS;
399803831d35Sstevel 
399903831d35Sstevel 	static char *lw8_pci_devs[] = {
400003831d35Sstevel 		DISK0_BASE_PATH,
400103831d35Sstevel 		DISK1_BASE_PATH
400203831d35Sstevel 	};
400303831d35Sstevel 
400403831d35Sstevel 	static char *lw8_pcix_devs[] = {
400503831d35Sstevel 		DISK0_BASE_PATH_PCIX,
400603831d35Sstevel 		DISK1_BASE_PATH_PCIX
400703831d35Sstevel 	};
400803831d35Sstevel 
400903831d35Sstevel 	static char **lw8_devs;
401003831d35Sstevel 
401103831d35Sstevel 	if (pcix_io) {
401203831d35Sstevel 		lw8_devs = lw8_pcix_devs;
401303831d35Sstevel 	} else {
401403831d35Sstevel 		lw8_devs = lw8_pci_devs;
401503831d35Sstevel 	}
401603831d35Sstevel 
401703831d35Sstevel 	/*
401803831d35Sstevel 	 * create aliases for disk names
401903831d35Sstevel 	 */
402003831d35Sstevel 	for (i = 0; i < n_disks; i++) {
402103831d35Sstevel 		char buffer[MAXPATHLEN];
402203831d35Sstevel 
402303831d35Sstevel 		(void) snprintf(buffer, sizeof (buffer), "/devices%s",
402403831d35Sstevel 		    lw8_devs[i]);
402503831d35Sstevel 		lw8_disks[i].d_devices_path = strdup(buffer);
402603831d35Sstevel 
402703831d35Sstevel 		(void) snprintf(buffer, sizeof (buffer), "/platform%s",
402803831d35Sstevel 		    lw8_devs[i]);
402903831d35Sstevel 		lw8_disks[i].d_plat_path = strdup(buffer);
403003831d35Sstevel 	}
403103831d35Sstevel 
403203831d35Sstevel 	for (;;) {
403303831d35Sstevel 		for (i = 0; i < n_disks; i++) {
403403831d35Sstevel 			set_disk_leds(&lw8_disks[i]);
403503831d35Sstevel 		}
403603831d35Sstevel 
403703831d35Sstevel 		/*
403803831d35Sstevel 		 * wait a bit until we check again
403903831d35Sstevel 		 */
404003831d35Sstevel 		err = poll(NULL, 0, ledsthr_poll_period);
404103831d35Sstevel 		if (err == -1) {
404203831d35Sstevel 			err = errno;
404303831d35Sstevel 			syslog(LOG_ERR, EM_POLL_FAIL, strerror(err));
404403831d35Sstevel 			break;
404503831d35Sstevel 		}
404603831d35Sstevel 		err = pthread_mutex_lock(&g_mutex);
404703831d35Sstevel 		if (err != 0) {
404803831d35Sstevel 			syslog(LOG_ERR, EM_MUTEX_FAIL, strerror(err));
404903831d35Sstevel 			break;
405003831d35Sstevel 		}
405103831d35Sstevel 		if (g_wait_now != B_FALSE) {
405203831d35Sstevel 			/* notify _fini routine that we've paused */
405303831d35Sstevel 			disk_leds_thread_ack = B_TRUE;
405403831d35Sstevel 			(void) pthread_cond_signal(&g_cv_ack);
405503831d35Sstevel 			/* and go to sleep in case we get restarted */
405603831d35Sstevel 			while (g_wait_now != B_FALSE)
405703831d35Sstevel 				(void) pthread_cond_wait(&g_cv, &g_mutex);
405803831d35Sstevel 		}
405903831d35Sstevel 		(void) pthread_mutex_unlock(&g_mutex);
406003831d35Sstevel 	}
406103831d35Sstevel 	return ((void *)err);
406203831d35Sstevel }
4063