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"
127*ada2da53SToomas Soome #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) {
1663*ada2da53SToomas Soome err = add_prop_ref(cpuhdl1, nodeh,
1664*ada2da53SToomas Soome 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
2082768a4bffSjfrank /*
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
214503831d35Sstevel /*
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,
2575*ada2da53SToomas Soome char *class, char *prop_class, picl_prophdl_t tblhdl,
2576*ada2da53SToomas Soome 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