#include <syslog.h>
#include <unistd.h>
#include <stdio.h>
#include <libintl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/time_impl.h>
#include <sys/signal.h>
#include <sys/devctl.h>
#include <libdevinfo.h>
#include <libdevice.h>
#include <picl.h>
#include <picltree.h>
#include <sys/i2c/clients/i2c_client.h>
#include <hbaapi.h>
#include <limits.h>
#include <sys/systeminfo.h>
#include <psvc_objects.h>
#define SEG5_ADDR 0x30
#define EBUS_DEV_NAME "/devices/pci@9,700000/ebus@1/"
#define SEG5_DEV_NAME EBUS_DEV_NAME "i2c@1,30/"
#define SEG5_ADDR_DEV_FMT EBUS_DEV_NAME "i2c@1,%x:devctl"
#define QLC_NODE "/pci@9,600000/SUNW,qlc@2"
#define DISK_DRV "ssd"
#define MAX_DISKS 2
#define WWN_SIZE 8
#define ONBOARD_CONTR "../../devices/pci@9,600000/SUNW,qlc@2/fp@0,0:fc"
#define PCF8574_BIT_WRITE_VALUE(byte, bit, value)\
((value << bit) | (byte & (~(0x01 << bit))))
#define PDB_MUST_BE_1 0xBF
#define PSU_MUST_BE_1 0x7F
#define DISKBP_MUST_BE_1 0x0F
#define PSVC_MAX_STR_LEN 32
#define PS_MAX_FAULT_SENSORS 3
static char *ps_prev_id[2][3] =
{{NULL, NULL, NULL}, {NULL, NULL, NULL}};
static int ps_prev_failed[2][3] = {{0, 0, 0}, {0, 0, 0}};
static boolean_t ps_prev_present[2];
static boolean_t ps_present[2];
static int ac_unplugged(psvc_opaque_t, char *);
static int ac_power_check(psvc_opaque_t, char *, char *);
static int n_retry_fan = PSVC_NUM_OF_RETRIES;
static int retry_sleep_fan = 1;
static int n_retry_ps_status = PSVC_NUM_OF_RETRIES;
static int retry_sleep_ps_status = 1;
static int n_retry_pshp = PSVC_NUM_OF_RETRIES;
static int retry_sleep_pshp = 1;
static int n_retry_diskhp = PSVC_NUM_OF_RETRIES;
static int retry_sleep_diskhp = 1;
static int n_retry_temp_shutdown = PSVC_NUM_OF_RETRIES;
static int retry_sleep_temp_shutdown = 1;
static int n_retry_fsp_fault = PSVC_NUM_OF_RETRIES;
static int retry_sleep_fsp_fault = 1;
typedef struct {
int *pvar;
char *texttag;
} i2c_noise_param_t;
static i2c_noise_param_t i2cparams[] = {
&n_retry_fan, "n_retry_fan",
&retry_sleep_fan, "retry_sleep_fan",
&n_retry_ps_status, "n_retry_ps_status",
&retry_sleep_ps_status, "retry_sleep_ps_status",
&n_retry_pshp, "n_retry_pshp",
&retry_sleep_pshp, "retry_sleep_pshp",
&n_retry_diskhp, "n_retry_diskhp",
&retry_sleep_diskhp, "retry_sleep_diskhp",
&n_retry_temp_shutdown, "n_retry_temp_shutdown",
&retry_sleep_temp_shutdown, "retry_sleep_temp_shutdown",
&n_retry_fsp_fault, "n_retry_fsp_fault",
&retry_sleep_fsp_fault, "retry_sleep_fsp_fault",
NULL, NULL
};
#pragma init(i2cparams_load)
static void
i2cparams_debug(i2c_noise_param_t *pi2cparams, char *platform,
int usingDefaults)
{
char s[128];
i2c_noise_param_t *p;
if (!usingDefaults) {
(void) snprintf(s, sizeof (s),
"# Values from /usr/platform/%s/lib/i2cparam.conf\n",
platform);
syslog(LOG_WARNING, "%s", s);
} else {
(void) snprintf(s, sizeof (s),
"# No /usr/platform/%s/lib/i2cparam.conf file, using defaults\n",
platform);
}
(void) fputs(s, stdout);
p = pi2cparams;
while (p->pvar != NULL) {
(void) snprintf(s, sizeof (s), "%s %d\n", p->texttag,
*(p->pvar));
if (!usingDefaults)
syslog(LOG_WARNING, "%s", s);
(void) fputs(s, stdout);
p++;
}
}
static void
i2cparams_load(void)
{
FILE *fp;
char filename[PATH_MAX];
char platform[64];
char s[128];
char var[128];
int val;
i2c_noise_param_t *p;
if (sysinfo(SI_PLATFORM, platform, sizeof (platform)) == -1) {
syslog(LOG_ERR, "sysinfo error %s\n", strerror(errno));
return;
}
(void) snprintf(filename, sizeof (filename),
"/usr/platform/%s/lib/i2cparam.conf", platform);
if ((fp = fopen(filename, "r")) != NULL) {
while (fgets(s, sizeof (s), fp) != NULL) {
if (s[0] == '#')
continue;
if (sscanf(s, "%127s %d", var, &val) != 2)
continue;
if (val < 1)
val = 1;
p = &(i2cparams[0]);
while (p->pvar != NULL) {
if (strncmp(p->texttag, var, sizeof (var)) ==
0) {
*(p->pvar) = val;
break;
}
p++;
}
}
(void) fclose(fp);
}
i2cparams_debug(&(i2cparams[0]), platform, ((fp == NULL)? 1 : 0));
}
static int
create_i2c_node(char *nd_name, char *nd_compat, int nd_nexi, int *nd_reg)
{
devctl_ddef_t ddef_hdl = NULL;
devctl_hdl_t bus_hdl = NULL;
devctl_hdl_t dev_hdl = NULL;
char buf[MAXPATHLEN];
char dev_path[MAXPATHLEN];
int rv = PSVC_FAILURE;
(void) snprintf(buf, sizeof (buf), SEG5_ADDR_DEV_FMT, nd_nexi);
bus_hdl = devctl_bus_acquire(buf, 0);
if (bus_hdl == NULL)
goto bad;
ddef_hdl = devctl_ddef_alloc(nd_name, 0);
(void) devctl_ddef_string(ddef_hdl, "compatible", nd_compat);
(void) devctl_ddef_int_array(ddef_hdl, "reg", 2, nd_reg);
if (devctl_bus_dev_create(bus_hdl, ddef_hdl, 0, &dev_hdl))
goto bad;
if (devctl_get_pathname(dev_hdl, dev_path, MAXPATHLEN) == NULL)
goto bad;
#ifdef DEBUG
syslog(LOG_ERR, "PSVC: create_i2c_node: Device node created: (%s)",
dev_path);
#endif
rv = PSVC_SUCCESS;
bad:
if (dev_hdl) devctl_release(dev_hdl);
if (ddef_hdl) devctl_ddef_free(ddef_hdl);
if (bus_hdl) devctl_release(bus_hdl);
return (rv);
}
static void
delete_i2c_node(char *nd)
{
int rv;
devctl_hdl_t dev_hdl;
dev_hdl = devctl_device_acquire(nd, 0);
if (dev_hdl == NULL) {
return;
}
rv = devctl_device_remove(dev_hdl);
if (rv != DDI_SUCCESS)
perror(nd);
#ifdef DEBUG
else
syslog(LOG_ERR, "Device node deleted: (%s)", nd);
#endif
devctl_release(dev_hdl);
}
static int
send_pcf8574_reset(psvc_opaque_t hdlp, char *reset_dev)
{
int err;
uint8_t reset_bits[2] = {0x7F, 0xFF};
int i;
for (i = 0; i < 2; i++) {
err = psvc_set_attr(hdlp, reset_dev, PSVC_GPIO_VALUE_ATTR,
&reset_bits[i]);
if (err != PSVC_SUCCESS) {
#ifdef DEBUG
syslog(LOG_ERR,
gettext("Reset to %s with 0x%x failed"),
reset_dev, reset_bits[i]);
#endif
return (err);
}
}
sleep(3);
return (err);
}
static int
pcf8574_write_bit(psvc_opaque_t hdlp, char *id, uint8_t bit_num,
uint8_t bit_val, uint8_t write_must_be_1)
{
int rv = PSVC_FAILURE;
uint8_t byte;
rv = psvc_get_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
if (rv != PSVC_SUCCESS)
return (rv);
byte = PCF8574_BIT_WRITE_VALUE(byte, bit_num, bit_val);
byte |= write_must_be_1;
rv = psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR, &byte);
return (rv);
}
static int
pdb_enable_i2c(psvc_opaque_t hdlp)
{
int rv = PSVC_SUCCESS, i;
int bit_vals[3] = {1, 0, 1};
int bit_num = 6;
for (i = 0; i < 3; i++) {
rv = pcf8574_write_bit(hdlp, "PDB_PORT", bit_num, bit_vals[i],
PDB_MUST_BE_1);
if (rv != PSVC_SUCCESS) {
goto bad;
}
}
return (rv);
bad:
#ifdef DEBUG
syslog(LOG_ERR, gettext("PDB I2C Bus Enabling Failed"));
#endif
return (rv);
}
int32_t
psvc_init_disk_bp_policy_0(psvc_opaque_t hdlp, char *id)
{
uint8_t reset = 0xFF;
return (psvc_set_attr(hdlp, id, PSVC_GPIO_VALUE_ATTR,
&reset));
}
int32_t
pcf8574_init_policy_0(psvc_opaque_t hdlp, char *id)
{
return (send_pcf8574_reset(hdlp, id));
}
static int32_t
check_fan(psvc_opaque_t hdlp, char *tray_id, char *fan_id, boolean_t *fault_on)
{
int status;
int speed;
int low_thresh;
boolean_t have_fault = 0;
char *tach_id;
char state[PSVC_MAX_STR_LEN];
char prev_state[PSVC_MAX_STR_LEN];
char fault_state[PSVC_MAX_STR_LEN];
int retry;
status = psvc_get_attr(hdlp, fan_id, PSVC_ASSOC_ID_ATTR,
&tach_id, PSVC_FAN_SPEED_TACHOMETER, 0);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, tach_id, PSVC_LO_WARN_ATTR, &low_thresh);
if (status != PSVC_SUCCESS)
return (status);
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_fan);
status = psvc_get_attr(hdlp, tach_id, PSVC_SENSOR_VALUE_ATTR,
&speed);
if (status != PSVC_SUCCESS)
return (status);
if (speed <= low_thresh) {
strlcpy(fault_state, "DEVICE_FAIL",
sizeof (fault_state));
strlcpy(state, PSVC_ERROR, sizeof (state));
have_fault = 1;
} else {
strlcpy(fault_state, PSVC_NO_FAULT,
sizeof (fault_state));
strlcpy(state, PSVC_OK, sizeof (state));
have_fault = 0;
}
retry++;
} while ((retry < n_retry_fan) && (speed <= low_thresh));
status = psvc_set_attr(hdlp, fan_id, PSVC_FAULTID_ATTR, fault_state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, fan_id, PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, fan_id, PSVC_PREV_STATE_ATTR, prev_state);
if (status != PSVC_SUCCESS)
return (status);
if (strcmp(state, PSVC_OK) != 0) {
syslog(LOG_ERR, gettext("WARNING: %s (%s) failure detected"),
tray_id, fan_id);
} else {
if (strcmp(state, prev_state) != 0) {
syslog(LOG_ERR, gettext("NOTICE: Device %s (%s) OK"),
tray_id, fan_id);
}
}
*fault_on |= have_fault;
return (PSVC_SUCCESS);
}
int32_t
psvc_fan_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
{
int fan_count;
int led_count;
int err, i;
char *led_id;
char *fan_id;
char led_state[PSVC_MAX_STR_LEN];
char state[PSVC_MAX_STR_LEN];
char prev_state[PSVC_MAX_STR_LEN];
boolean_t fault_on = 0;
err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &fan_count,
PSVC_FAN_TRAY_FANS);
if (err != PSVC_SUCCESS)
return (err);
for (i = 0; i < fan_count; i++) {
err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&fan_id, PSVC_FAN_TRAY_FANS, i);
if (err != PSVC_SUCCESS)
return (err);
err = check_fan(hdlp, id, fan_id, &fault_on);
if (err != PSVC_SUCCESS)
return (err);
}
if (fault_on) {
strlcpy(led_state, PSVC_LED_ON, sizeof (led_state));
err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_ERROR);
if (err != PSVC_SUCCESS)
return (err);
} else {
strlcpy(led_state, PSVC_LED_OFF, sizeof (led_state));
err = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, PSVC_OK);
if (err != PSVC_SUCCESS)
return (err);
}
err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
if (err != PSVC_SUCCESS)
return (err);
err = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, prev_state);
if (err != PSVC_SUCCESS)
return (err);
if (strcmp(state, prev_state) != 0) {
err = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
&led_count, PSVC_DEV_FAULT_LED);
if (err != PSVC_SUCCESS)
return (err);
for (i = 0; i < led_count; i++) {
err = psvc_get_attr(hdlp, id,
PSVC_ASSOC_ID_ATTR, &led_id,
PSVC_DEV_FAULT_LED, i);
if (err != PSVC_SUCCESS)
return (err);
err = psvc_set_attr(hdlp, led_id,
PSVC_LED_STATE_ATTR, led_state);
if (err != PSVC_SUCCESS)
return (err);
err = psvc_get_attr(hdlp, led_id,
PSVC_LED_STATE_ATTR, led_state);
if (err != PSVC_SUCCESS)
return (err);
}
}
return (err);
}
static int32_t
check_cpu_temp_fault(psvc_opaque_t hdlp, char *cpu, int32_t cpu_count)
{
char *sensorid;
int32_t sensor_count;
int32_t status = PSVC_SUCCESS;
int32_t i;
char fault[PSVC_MAX_STR_LEN];
int retry;
psvc_get_attr(hdlp, cpu, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
PSVC_DEV_TEMP_SENSOR);
for (i = 0; i < sensor_count; ++i) {
status = psvc_get_attr(hdlp, cpu, PSVC_ASSOC_ID_ATTR,
&sensorid, PSVC_DEV_TEMP_SENSOR, i);
if (status == PSVC_FAILURE)
return (status);
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_temp_shutdown);
status = psvc_get_attr(hdlp, sensorid,
PSVC_FAULTID_ATTR, fault);
if (status == PSVC_FAILURE)
return (status);
retry++;
} while (((strcmp(fault, PSVC_TEMP_LO_SHUT) == 0) ||
(strcmp(fault, PSVC_TEMP_HI_SHUT) == 0)) &&
(retry < n_retry_temp_shutdown));
if ((strcmp(fault, PSVC_TEMP_HI_SHUT) == 0) ||
(strcmp(fault, PSVC_TEMP_LO_SHUT) == 0)) {
system("shutdown -y -g 60 -i 5 \"OVERTEMP condition\"");
}
}
return (status);
}
int32_t
psvc_shutdown_policy_0(psvc_opaque_t hdlp, char *id)
{
int32_t cpu_count;
char *cpuid;
int32_t i;
boolean_t present;
int32_t status = PSVC_SUCCESS;
psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &cpu_count,
PSVC_CPU);
for (i = 0; i < cpu_count; ++i) {
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &cpuid,
PSVC_CPU, i);
if (status == PSVC_FAILURE)
return (status);
status = psvc_get_attr(hdlp, cpuid,
PSVC_PRESENCE_ATTR, &present);
if (status == PSVC_FAILURE && present == PSVC_PRESENT)
return (status);
if (present == PSVC_PRESENT) {
status = check_cpu_temp_fault(hdlp, cpuid, cpu_count);
if (status == PSVC_FAILURE && errno != ENODEV)
return (status);
}
}
return (PSVC_SUCCESS);
}
int32_t
psvc_fsp_device_fault_check_policy_0(psvc_opaque_t hdlp, char *id)
{
int32_t status;
int32_t i;
int32_t device_count = 0;
char device_state[PSVC_MAX_STR_LEN];
char *device_id;
int32_t failed_count = 0;
static int32_t led_on = 0;
int retry;
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR,
&device_count, PSVC_DEV_FAULT_SENSOR);
if (status != PSVC_SUCCESS)
return (status);
for (i = 0; i < device_count; i++) {
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&device_id, PSVC_DEV_FAULT_SENSOR, i);
if (status != PSVC_SUCCESS)
return (status);
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_fsp_fault);
status = psvc_get_attr(hdlp, device_id, PSVC_STATE_ATTR,
device_state);
if (status != PSVC_SUCCESS)
return (status);
if (strcmp(device_state, PSVC_OK) != 0 &&
strcmp(device_state, PSVC_HOTPLUGGED) != 0 &&
strcmp(device_state, "NO AC POWER") != 0 &&
strlen(device_state) != 0) {
failed_count++;
}
retry++;
} while ((retry < n_retry_fsp_fault) && (failed_count));
}
if (failed_count == 0 && led_on) {
syslog(LOG_ERR, gettext("%s has turned OFF"), id);
status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
PSVC_LED_OFF);
led_on = 0;
}
if (failed_count > 0 && ! led_on) {
syslog(LOG_ERR,
gettext("%s has turned ON"), id);
status = psvc_set_attr(hdlp, id, PSVC_LED_STATE_ATTR,
PSVC_LED_ON);
led_on = 1;
}
return (PSVC_SUCCESS);
}
static void
ps_reset_prev_failed(int index)
{
int i;
for (i = 0; i < 3; i++) {
ps_prev_id[index][i] = NULL;
ps_prev_failed[index][i] = 0;
}
}
static int
check_i2c_access(psvc_opaque_t hdlp, char *id)
{
int rv;
char state[PSVC_MAX_STR_LEN];
char ps_fault_sensor[PSVC_MAX_STR_LEN];
snprintf(ps_fault_sensor, sizeof (ps_fault_sensor),
"%s_FAULT_SENSOR", id);
rv = psvc_get_attr(hdlp, ps_fault_sensor, PSVC_SWITCH_STATE_ATTR,
&state);
return (rv);
}
static int
handle_ps_hotplug_children_presence(psvc_opaque_t hdlp, char *id)
{
char *child_add_on[4] = {"_RESET", "_LOGICAL_STATE", "_AC_IN_SENSOR",
"_FAULT_SENSOR"};
int add_ons = 4;
char addon_id[PICL_PROPNAMELEN_MAX];
char *sensor_id;
int32_t status = PSVC_SUCCESS;
boolean_t presence;
int j;
for (j = 0; j < add_ons; j++) {
snprintf(addon_id, sizeof (addon_id), "%s%s", id,
child_add_on[j]);
status = psvc_get_attr(hdlp, addon_id, PSVC_PRESENCE_ATTR,
&presence);
if (status != PSVC_SUCCESS)
return (status);
}
for (j = 0; j < PS_MAX_FAULT_SENSORS; j++) {
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&(sensor_id), PSVC_DEV_FAULT_SENSOR, j);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
&presence);
if (status != PSVC_SUCCESS)
return (status);
}
for (j = 0; j < 2; j++) {
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&(sensor_id), PSVC_PHYSICAL_DEVICE, j);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, sensor_id, PSVC_PRESENCE_ATTR,
&presence);
if (status != PSVC_SUCCESS)
return (status);
}
return (status);
}
static int
handle_ps_hotplug(psvc_opaque_t hdlp, char *id, boolean_t present)
{
int32_t status = PSVC_SUCCESS;
int32_t instance;
picl_nodehdl_t parent_node;
picl_nodehdl_t child_node;
char info[PSVC_MAX_STR_LEN];
char ps_logical_state[PICL_PROPNAMELEN_MAX];
char parent_path[PICL_PROPNAMELEN_MAX];
char ps_path[PICL_PROPNAMELEN_MAX];
static int fruprom_addr[2][2] = { {0, 0xa2}, {0, 0xa0} };
static int pcf8574_addr[2][2] = { {0, 0x72}, {0, 0x70} };
char dev_path[MAXPATHLEN];
psvcplugin_lookup(id, parent_path, &child_node);
status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
if (status != PSVC_SUCCESS)
return (status);
if (present == PSVC_PRESENT && !ps_prev_present[instance]) {
syslog(LOG_ERR, gettext("Device %s inserted"), id);
ptree_get_node_by_path(parent_path, &parent_node);
ptree_add_node(parent_node, child_node);
snprintf(ps_path, sizeof (ps_path), "%s/%s", parent_path, id);
psvcplugin_add_children(ps_path);
status = handle_ps_hotplug_children_presence(hdlp, id);
status |= create_i2c_node("ioexp", "i2c-pcf8574", SEG5_ADDR,
pcf8574_addr[instance]);
status |= create_i2c_node("fru", "i2c-at24c64", SEG5_ADDR,
fruprom_addr[instance]);
} else {
syslog(LOG_ERR, gettext("Device %s removed"), id);
ps_reset_prev_failed(instance);
if (ptree_delete_node(child_node) != PICL_SUCCESS)
syslog(LOG_ERR, "ptree_delete_node failed!");
snprintf(dev_path, sizeof (dev_path),
SEG5_DEV_NAME"ioexp@0,%x:pcf8574",
pcf8574_addr[instance][1]);
delete_i2c_node(dev_path);
snprintf(dev_path, sizeof (dev_path),
SEG5_DEV_NAME"fru@0,%x:fru", fruprom_addr[instance][1]);
delete_i2c_node(dev_path);
}
snprintf(ps_logical_state, sizeof (ps_logical_state),
"%s_LOGICAL_STATE", id);
strlcpy(info, PSVC_OK, sizeof (info));
status |= psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, info);
status |= psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR, info);
strlcpy(info, PSVC_NO_FAULT, sizeof (info));
status |= psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, info);
status |= pdb_enable_i2c(hdlp);
return (status);
}
static int32_t
check_ps_state(psvc_opaque_t hdlp, char *id)
{
int32_t sensor_count;
int32_t status = PSVC_SUCCESS;
int32_t i;
int32_t fault_on = 0;
char *sensor_id;
char ps_ok_sensor[PICL_PROPNAMELEN_MAX];
char ps_logical_state[PICL_PROPNAMELEN_MAX];
char ps_reset[PICL_PROPNAMELEN_MAX];
char previous_state[PSVC_MAX_STR_LEN];
char state[PSVC_MAX_STR_LEN];
char fault[PSVC_MAX_STR_LEN];
int ps_okay = 1;
int instance;
int retry;
snprintf(ps_logical_state, sizeof (ps_logical_state),
"%s_LOGICAL_STATE", id);
status = ac_power_check(hdlp, id, ps_logical_state);
if (status == PSVC_FAILURE)
return (status);
status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
if (strcmp(state, "NO AC POWER") == 0)
return (status);
status = psvc_get_attr(hdlp, id, PSVC_PREV_STATE_ATTR, previous_state);
if (status != PSVC_SUCCESS)
return (status);
snprintf(ps_ok_sensor, sizeof (ps_ok_sensor), "%s_OK_SENSOR", id);
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_ps_status);
status = psvc_get_attr(hdlp, ps_ok_sensor,
PSVC_SWITCH_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
retry++;
} while ((retry < n_retry_ps_status) &&
(strcmp(previous_state, state)));
if (strcmp(previous_state, state) != 0) {
if (strcmp(state, PSVC_SWITCH_OFF) == 0) {
strlcpy(state, PSVC_ERROR, sizeof (state));
strlcpy(fault, "DEVICE_FAIL", sizeof (fault));
fault_on = 1;
syslog(LOG_ERR, gettext(
"Device %s: Failure Detected -- %s "
"shutdown!"), id, id);
ps_okay = 0;
} else {
strlcpy(state, PSVC_OK, sizeof (state));
strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
}
status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
if (status != PSVC_SUCCESS)
return (status);
}
status = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
PSVC_DEV_FAULT_SENSOR);
if (status != PSVC_SUCCESS) {
return (status);
}
for (i = 0; i < sensor_count; i++) {
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&sensor_id, PSVC_DEV_FAULT_SENSOR, i);
if (status != PSVC_SUCCESS)
return (status);
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_ps_status);
status = psvc_get_attr(hdlp, sensor_id,
PSVC_SWITCH_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
retry++;
} while ((retry < n_retry_ps_status) &&
(strcmp(state, PSVC_SWITCH_ON) == 0));
if (strcmp(state, PSVC_SWITCH_ON) == 0) {
if (ps_prev_id[instance][i] == NULL)
ps_prev_id[instance][i] = sensor_id;
if (ps_prev_failed[instance][i] != 1)
ps_prev_failed[instance][i] = 1;
fault_on = 1;
if (i == 0) {
if (ps_okay)
syslog(LOG_ERR, gettext(
"Device %s: Fault Detected"),
id);
} else {
syslog(LOG_ERR, gettext("Warning %s: %s is ON"),
id, sensor_id);
}
}
}
status = psvc_get_attr(hdlp, ps_logical_state,
PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, ps_logical_state,
PSVC_PREV_STATE_ATTR, previous_state);
if (status != PSVC_SUCCESS)
return (status);
if (fault_on) {
if (ps_okay) {
status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
PSVC_GEN_FAULT);
if (status != PSVC_SUCCESS)
return (status);
}
status = psvc_set_attr(hdlp, ps_logical_state,
PSVC_STATE_ATTR, PSVC_ERROR);
if (status != PSVC_SUCCESS)
return (status);
snprintf(ps_reset, sizeof (ps_reset), "%s_RESET", id);
status = send_pcf8574_reset(hdlp, ps_reset);
return (status);
}
if (strcmp(state, PSVC_OK) != 0) {
for (i = 0; i < 3; i++) {
char *sensor = ps_prev_id[instance][i];
int *prev_failed = &ps_prev_failed[instance][i];
if (sensor == NULL)
continue;
if (*prev_failed == 0)
continue;
*prev_failed = 0;
if (i == 0) {
if (ps_okay)
syslog(LOG_ERR, gettext(
"Notice %s: Fault Cleared"),
id);
} else {
syslog(LOG_ERR, gettext("Notice %s: %s is OFF"),
id, sensor);
}
}
status = psvc_set_attr(hdlp, ps_logical_state,
PSVC_STATE_ATTR, PSVC_OK);
if (status != PSVC_SUCCESS)
return (status);
syslog(LOG_ERR, gettext("Device %s Okay"), id);
}
return (PSVC_SUCCESS);
}
static int
ac_unplugged(psvc_opaque_t hdlp, char *id)
{
int32_t status = PSVC_SUCCESS;
char ac_sensor_id[PICL_PROPNAMELEN_MAX];
char ac_switch_state[PSVC_MAX_STR_LEN];
snprintf(ac_sensor_id, sizeof (ac_sensor_id), "%s_AC_IN_SENSOR", id);
status = psvc_get_attr(hdlp, ac_sensor_id, PSVC_SWITCH_STATE_ATTR,
ac_switch_state);
if (status == PSVC_FAILURE) {
return (status);
}
if (strcmp(ac_switch_state, PSVC_SWITCH_OFF) == 0) {
return (1);
} else {
return (0);
}
}
static int
ac_power_check(psvc_opaque_t hdlp, char *id, char *ps_logical_state)
{
int32_t status = PSVC_SUCCESS;
int32_t sensor_count;
char *sensor_id;
char state[PSVC_MAX_STR_LEN];
int unplugged, i;
status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
unplugged = ac_unplugged(hdlp, id);
if (status == PSVC_FAILURE) {
return (status);
}
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_MATCHES_ATTR, &sensor_count,
PSVC_DEV_FAULT_SENSOR);
if (status != PSVC_SUCCESS) {
return (status);
}
if ((unplugged) && (strcmp(state, "NO AC POWER") != 0)) {
status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
"NO AC POWER");
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
PSVC_ERROR);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
"NO AC POWER");
if (status != PSVC_SUCCESS)
return (status);
syslog(LOG_ERR, gettext("Device %s AC UNAVAILABLE"), id);
for (i = 0; i < sensor_count; ++i) {
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&sensor_id, PSVC_DEV_FAULT_SENSOR, i);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, sensor_id,
PSVC_FAULTID_ATTR, "");
if (status != PSVC_SUCCESS)
return (status);
}
}
if ((!unplugged) && (strcmp(state, "NO AC POWER") == 0)) {
status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
PSVC_OK);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, ps_logical_state, PSVC_STATE_ATTR,
PSVC_OK);
if (status != PSVC_SUCCESS)
return (status);
syslog(LOG_ERR, gettext("Device %s AC AVAILABLE"), id);
}
return (status);
}
int32_t
psvc_init_ps_presence(psvc_opaque_t hdlp, char *id)
{
int err;
int instance;
boolean_t presence;
err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
err |= psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR, &presence);
ps_prev_present[instance] = ps_present[instance] = presence;
return (err);
}
int32_t
psvc_ps_monitor_policy_0(psvc_opaque_t hdlp, char *id)
{
int err;
int instance;
static int failed_last_time[2] = {0, 0};
int retry;
err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
if (err != PSVC_SUCCESS)
return (err);
ps_prev_present[instance] = ps_present[instance];
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_pshp);
err = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
&ps_present[instance]);
if (err != PSVC_SUCCESS)
goto out;
retry++;
} while ((retry < n_retry_pshp) &&
(ps_present[instance] != ps_prev_present[instance]));
if (ps_present[instance] != ps_prev_present[instance]) {
err = handle_ps_hotplug(hdlp, id, ps_present[instance]);
return (err);
}
if (!ps_present[instance])
return (PSVC_SUCCESS);
err = check_i2c_access(hdlp, id);
if (err != PSVC_SUCCESS) {
if (ps_present[instance] == PSVC_PRESENT &&
ps_prev_present[instance] == PSVC_PRESENT) {
syslog(LOG_ERR, "Device %s removed", id);
ps_reset_prev_failed(instance);
ps_prev_present[instance] = 0;
handle_ps_hotplug(hdlp, id, ps_present[instance]);
return (PSVC_SUCCESS);
}
goto out;
}
err = check_ps_state(hdlp, id);
if (err != PSVC_SUCCESS)
goto out;
failed_last_time[instance] = 0;
return (err);
out:
if (! failed_last_time[instance]) {
failed_last_time[instance] = 1;
return (PSVC_SUCCESS);
}
return (err);
}
static int
light_disk_fault_leds(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
{
int err;
int bit_nums[MAX_DISKS] = {6, 7};
uint8_t led_masks[MAX_DISKS] = {0x40, 0x80};
int instance;
int bit_value;
char state[PSVC_MAX_STR_LEN];
uint8_t byte;
if (disk_presence != PSVC_PRESENT)
return (PSVC_SUCCESS);
err = psvc_get_attr(hdlp, id, PSVC_INSTANCE_ATTR, &instance);
if (err != PSVC_SUCCESS)
return (err);
err = psvc_get_attr(hdlp, "DISK_PORT", PSVC_GPIO_VALUE_ATTR,
&byte);
if (err != PSVC_SUCCESS)
return (err);
err = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, state);
if (err != PSVC_SUCCESS)
return (err);
if (strcmp(state, PSVC_OK) == 0 || strcmp(state, "") == 0) {
if (byte & led_masks[instance]) {
return (err);
} else {
bit_value = 1;
err = pcf8574_write_bit(hdlp, "DISK_PORT",
bit_nums[instance], bit_value,
DISKBP_MUST_BE_1);
if (err != PSVC_SUCCESS)
return (err);
}
} else {
if (byte & led_masks[instance]) {
bit_value = 0;
err = pcf8574_write_bit(hdlp, "DISK_PORT",
bit_nums[instance], bit_value,
DISKBP_MUST_BE_1);
if (err != PSVC_SUCCESS)
return (err);
} else {
return (err);
}
}
return (err);
}
int
verify_disk_wwn(char *wwn)
{
HBA_PORTATTRIBUTES hbaPortAttrs, discPortAttrs;
HBA_HANDLE handle;
HBA_STATUS status;
HBA_ADAPTERATTRIBUTES hbaAttrs;
HBA_UINT32 numberOfAdapters, hbaCount, hbaPort, discPort;
char adaptername[256];
char vwwn[WWN_SIZE * 2];
char OSDeviceName[PATH_MAX + 1];
int count, linksize;
status = HBA_LoadLibrary();
if (status != HBA_STATUS_OK) {
(void) HBA_FreeLibrary();
return (HBA_STATUS_ERROR);
}
numberOfAdapters = HBA_GetNumberOfAdapters();
for (hbaCount = 0; hbaCount < numberOfAdapters; hbaCount++) {
if ((status = HBA_GetAdapterName(hbaCount, adaptername)) !=
HBA_STATUS_OK)
continue;
handle = HBA_OpenAdapter(adaptername);
if (handle == 0)
continue;
if ((status = HBA_GetAdapterAttributes(handle,
&hbaAttrs)) != HBA_STATUS_OK) {
HBA_CloseAdapter(handle);
continue;
}
for (hbaPort = 0;
hbaPort < hbaAttrs.NumberOfPorts; hbaPort++) {
if ((status = HBA_GetAdapterPortAttributes(handle,
hbaPort, &hbaPortAttrs)) != HBA_STATUS_OK)
continue;
linksize = readlink(hbaPortAttrs.OSDeviceName,
OSDeviceName, PATH_MAX);
if ((linksize + 1) != sizeof (ONBOARD_CONTR))
continue;
OSDeviceName[linksize] = '\0';
if (strcmp(OSDeviceName, ONBOARD_CONTR) != 0)
continue;
for (discPort = 0;
discPort < hbaPortAttrs.NumberofDiscoveredPorts;
discPort++) {
status = HBA_GetDiscoveredPortAttributes(
handle, hbaPort, discPort,
&discPortAttrs);
if (status != HBA_STATUS_OK)
continue;
for (count = 0; count < WWN_SIZE; count++)
(void) sprintf(&vwwn[count * 2],
"%2.2x",
discPortAttrs.NodeWWN.wwn[count]);
if (strcmp(wwn, vwwn) == 0) {
HBA_CloseAdapter(handle);
(void) HBA_FreeLibrary();
return (HBA_STATUS_OK);
}
}
}
HBA_CloseAdapter(handle);
}
(void) HBA_FreeLibrary();
return (HBA_STATUS_ERROR_ILLEGAL_WWN);
}
static int
light_disk_ok2remove_leds(psvc_opaque_t hdlp, boolean_t *disk_present)
{
di_node_t node;
di_node_t root_node;
di_minor_t min_node;
int *prop;
int n;
int target;
int rv;
int disk_online = 0;
static int prev_online[MAX_DISKS] = {-1, -1};
int bit_nums[MAX_DISKS] = {4, 5};
int bit_val;
int count;
char *dev_path;
char wwn[WWN_SIZE * 2];
uchar_t *prop_wwn;
root_node = di_init("/", DINFOCPYALL);
if (root_node == DI_NODE_NIL)
return (PSVC_FAILURE);
for (node = di_drv_first_node(DISK_DRV, root_node);
node != DI_NODE_NIL;
node = di_drv_next_node(node)) {
n = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &prop);
if (n == -1)
continue;
target = *prop;
if (target < 0 || target > 1)
continue;
if (! disk_present[target])
continue;
dev_path = di_devfs_path(node);
if (memcmp(dev_path, QLC_NODE, (sizeof (QLC_NODE) - 1)) != 0) {
di_devfs_path_free(dev_path);
continue;
}
di_devfs_path_free(dev_path);
n = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
"node-wwn", &prop_wwn);
if (n == -1)
continue;
for (count = 0; count < WWN_SIZE; count++)
(void) sprintf(&wwn[count * 2], "%2.2x",
prop_wwn[count]);
n = verify_disk_wwn(wwn);
if (n == HBA_STATUS_ERROR_ILLEGAL_WWN)
continue;
min_node = di_minor_next(node, DI_MINOR_NIL);
disk_online = (min_node != DI_MINOR_NIL);
if ((disk_online == 0) && (prev_online[target] == 1)) {
bit_val = 0;
rv = pcf8574_write_bit(hdlp, "DISK_PORT",
bit_nums[target], bit_val, DISKBP_MUST_BE_1);
if (rv != PSVC_SUCCESS)
goto done;
} else if ((prev_online[target] == 0) && (disk_online == 1)) {
bit_val = 1;
rv = pcf8574_write_bit(hdlp, "DISK_PORT",
bit_nums[target], bit_val, DISKBP_MUST_BE_1);
if (rv != PSVC_SUCCESS)
goto done;
}
if (disk_online != prev_online[target])
prev_online[target] = disk_online;
}
done:
di_fini(root_node);
return (rv);
}
static int
check_disk_fault(psvc_opaque_t hdlp, char *id, boolean_t disk_presence)
{
int32_t status = PSVC_SUCCESS;
int32_t fault_on = 0;
char *sensor_id;
char disk_state[PSVC_MAX_STR_LEN];
char state[PSVC_MAX_STR_LEN];
char fault[PSVC_MAX_STR_LEN];
boolean_t change_of_state = 0;
if (disk_presence != PSVC_PRESENT)
return (PSVC_SUCCESS);
status = psvc_get_attr(hdlp, id, PSVC_STATE_ATTR, disk_state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR,
&sensor_id, PSVC_DEV_FAULT_SENSOR, 0);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_get_attr(hdlp, sensor_id, PSVC_SWITCH_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
if (strcmp(state, PSVC_SWITCH_ON) == 0) {
strlcpy(state, PSVC_ERROR, sizeof (state));
strlcpy(fault, PSVC_GEN_FAULT, sizeof (fault));
fault_on = 1;
} else {
if (strcmp(disk_state, PSVC_OK) != 0)
change_of_state = 1;
strlcpy(state, PSVC_OK, sizeof (state));
strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
}
status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR, state);
if (status != PSVC_SUCCESS)
return (status);
status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR, fault);
if (status != PSVC_SUCCESS)
return (status);
if (fault_on) {
syslog(LOG_ERR, gettext("Fault detected: %s"), id);
} else {
if (change_of_state)
syslog(LOG_ERR, gettext("Notice: %s okay"), id);
}
return (PSVC_SUCCESS);
}
static int
check_disk_hotplug(psvc_opaque_t hdlp, char *id, boolean_t *disk_presence,
int disk_instance)
{
boolean_t presence;
boolean_t previous_presence;
int32_t status = PSVC_SUCCESS;
char label[PSVC_MAX_STR_LEN];
uint8_t disk_leds[MAX_DISKS][2] = {{4, 6}, {5, 7}};
int retry;
status = psvc_get_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR,
&previous_presence);
if (status != PSVC_SUCCESS)
return (status);
retry = 0;
do {
if (retry)
(void) sleep(retry_sleep_diskhp);
status = psvc_get_attr(hdlp, id, PSVC_PRESENCE_ATTR,
&presence);
if (status != PSVC_SUCCESS)
return (status);
retry++;
} while ((retry < n_retry_diskhp) &&
(presence != previous_presence));
*disk_presence = presence;
if (presence != previous_presence) {
char parent_path[PICL_PROPNAMELEN_MAX];
picl_nodehdl_t child_node;
status = psvc_get_attr(hdlp, id, PSVC_LABEL_ATTR, label);
if (status != PSVC_SUCCESS)
return (status);
psvcplugin_lookup(id, parent_path, &child_node);
if (presence == PSVC_PRESENT) {
picl_nodehdl_t parent_node;
char state[PSVC_MAX_STR_LEN];
char fault[PSVC_MAX_STR_LEN];
syslog(LOG_ERR, gettext("Device %s inserted"), label);
strlcpy(state, PSVC_OK, sizeof (state));
status = psvc_set_attr(hdlp, id, PSVC_STATE_ATTR,
state);
if (status != PSVC_SUCCESS)
return (status);
strlcpy(fault, PSVC_NO_FAULT, sizeof (fault));
status = psvc_set_attr(hdlp, id, PSVC_FAULTID_ATTR,
fault);
if (status != PSVC_SUCCESS) {
return (status);
}
status = ptree_get_node_by_path(parent_path,
&parent_node);
if (status != PICL_SUCCESS)
return (PSVC_FAILURE);
status = ptree_add_node(parent_node, child_node);
if (status != PICL_SUCCESS)
return (PSVC_FAILURE);
} else {
int i;
int bit_val = 1;
for (i = 0; i < 2; i++) {
status = pcf8574_write_bit(hdlp, "DISK_PORT",
disk_leds[disk_instance][i], bit_val,
DISKBP_MUST_BE_1);
if (status != PSVC_SUCCESS)
syslog(LOG_ERR, "Failed in turning off"
" %d's LEDs", id);
}
syslog(LOG_ERR, gettext("Device %s removed"), label);
ptree_delete_node(child_node);
}
}
status = psvc_set_attr(hdlp, id, PSVC_PREV_PRESENCE_ATTR, &presence);
if (status != PSVC_SUCCESS)
return (status);
return (status);
}
int32_t
psvc_disk_monitor_policy_0(psvc_opaque_t hdlp, char *id)
{
int rv, err, i;
char *disks[MAX_DISKS] = {"DISK0", "DISK1"};
int saved_errno = 0;
boolean_t disk_present[MAX_DISKS] = {0, 0};
for (i = 0; i < MAX_DISKS; i++) {
err = check_disk_hotplug(hdlp, disks[i], &disk_present[i], i);
if (err) saved_errno = errno;
rv = err;
err = check_disk_fault(hdlp, disks[i], disk_present[i]);
if (err) saved_errno = errno;
rv |= err;
err |= light_disk_fault_leds(hdlp, disks[i], disk_present[i]);
if (err) saved_errno = errno;
rv |= err;
}
err = light_disk_ok2remove_leds(hdlp, disk_present);
if (err) saved_errno = errno;
rv |= err;
errno = saved_errno;
return (rv);
}
#define START_OFFSET 0x1800
#define NUM_SEG_OFFSET 0x1805
#define SEG_TABLE_OFFSET 0x1806
static int32_t
read_sc_segment(psvc_opaque_t hdlp, char *id, char *fru_id, int offset)
{
static int thresh_names[] = {
PSVC_HW_LO_SHUT_ATTR,
PSVC_LO_SHUT_ATTR,
PSVC_LO_WARN_ATTR,
PSVC_NOT_USED,
PSVC_OPTIMAL_TEMP_ATTR,
PSVC_HI_WARN_ATTR,
PSVC_HI_SHUT_ATTR,
PSVC_HW_HI_SHUT_ATTR
};
int8_t amb_temp_array[8];
int i;
fru_info_t fru_info;
int err;
fru_info.buf_start = offset + 8;
fru_info.buf = amb_temp_array;
fru_info.read_size = 8;
err = psvc_get_attr(hdlp, fru_id, PSVC_FRU_INFO_ATTR, &fru_info);
if (err != PSVC_SUCCESS)
return (err);
for (i = 0; i < 8; i++) {
int32_t temp = amb_temp_array[i];
if (thresh_names[i] == PSVC_NOT_USED)
continue;
err = psvc_set_attr(hdlp, id, thresh_names[i], &temp);
if (err != PSVC_SUCCESS)
return (err);
}
return (PSVC_SUCCESS);
}
int32_t
update_disk_bp_temp_thresholds(psvc_opaque_t hdlp, char *id)
{
char *fru;
fru_info_t fru_info;
int16_t seg_offset;
int8_t byte;
int8_t seg_count;
char seg_name[2];
int current_offset, i, err;
err = psvc_get_attr(hdlp, id, PSVC_ASSOC_ID_ATTR, &fru, PSVC_FRU, 0);
if (err != PSVC_SUCCESS)
return (err);
fru_info.buf_start = START_OFFSET;
fru_info.buf = &byte;
fru_info.read_size = 1;
err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
if (err != PSVC_SUCCESS)
return (err);
if (*fru_info.buf != 8) {
syslog(LOG_ERR, "Notice: FRU Prom %s not programmed", fru);
}
fru_info.buf_start = NUM_SEG_OFFSET;
fru_info.buf = &seg_count;
fru_info.read_size = 1;
err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
if (err != PSVC_SUCCESS)
return (err);
current_offset = SEG_TABLE_OFFSET;
for (i = 0; i < seg_count; i++) {
fru_info.buf_start = current_offset;
fru_info.buf = seg_name;
fru_info.read_size = 2;
err = psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR, &fru_info);
if (err != PSVC_SUCCESS)
return (err);
if (memcmp(seg_name, "SC", 2) == 0) {
current_offset += 6;
fru_info.buf_start = current_offset;
fru_info.buf = (char *)&seg_offset;
fru_info.read_size = 2;
psvc_get_attr(hdlp, fru, PSVC_FRU_INFO_ATTR,
&fru_info);
return (read_sc_segment(hdlp, id, fru, seg_offset));
}
current_offset += 10;
}
return (PSVC_SUCCESS);
}