#include <sys/time.h>
#include <sys/errno.h>
#include <sys/kmem.h>
#include <sys/stat.h>
#include <sys/cmn_err.h>
#include <sys/disp.h>
#include <sys/conf.h>
#include <sys/modctl.h>
#include <sys/devops.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/sgevents.h>
#include <sys/sysevent.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/domain.h>
#include <sys/sysevent/env.h>
#include <sys/serengeti.h>
#include <sys/sgfrutypes.h>
#include <sys/sgsbbc.h>
#include <sys/sgsbbc_iosram.h>
#include <sys/sgsbbc_mailbox.h>
#include <sys/sbd_ioctl.h>
#include <sys/sbdp_priv.h>
#include <sys/sbd.h>
#include <sys/sgenv_impl.h>
int sgenv_max_mbox_wait_time = 0;
#ifdef DEBUG
uint_t sgenv_debug = SGENV_DEBUG_NONE;
#endif
static struct cb_ops sgenv_cb_ops = {
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
ddi_segmap,
nochpoll,
ddi_prop_op,
NULL,
D_NEW | D_MP
};
static struct dev_ops sgenv_ops = {
DEVO_REV,
0,
ddi_getinfo_1to1,
nulldev,
nulldev,
sgenv_attach,
sgenv_detach,
nodev,
&sgenv_cb_ops,
(struct bus_ops *)NULL,
nulldev,
ddi_quiesce_not_needed,
};
extern struct mod_ops mod_driverops;
static struct modldrv modldrv = {
&mod_driverops,
"Environmental Driver",
&sgenv_ops
};
static struct modlinkage modlinkage = {
MODREV_1,
&modldrv,
NULL
};
static void *sgenv_statep;
static env_sensor_t *env_cache[SGENV_MAX_HPU_KEYS] = {NULL};
static void *env_cache_snapshot = NULL;
static size_t env_cache_snapshot_size = 0;
static int env_cache_updated = FALSE;
static kmutex_t env_kstat_lock;
static kmutex_t env_cache_lock;
static hrtime_t last_env_read_time = 0;
static volatile int env_thread_run = 0;
static kthread_t *env_thread = NULL;
static kt_did_t env_thread_tid;
static kcondvar_t env_flag_cond;
static kmutex_t env_flag_lock;
static boolean_t env_cache_updating = B_FALSE;
static boolean_t env_cache_update_needed = B_TRUE;
static sg_board_info_t board_cache[SG_MAX_BDS] = { 0 };
static sg_board_info_t board_cache_snapshot[SG_MAX_BDS] = { 0 };
static int board_cache_updated = FALSE;
static kmutex_t board_cache_lock;
static kmutex_t board_kstat_lock;
static int board_count = 0;
static int board_count_snapshot = 0;
static hrtime_t last_board_read_time = 0;
static volatile int board_thread_run = 0;
static kthread_t *board_thread = NULL;
static kt_did_t board_thread_tid;
static kcondvar_t board_flag_cond;
static kmutex_t board_flag_lock;
static boolean_t board_cache_updating = B_FALSE;
static boolean_t board_cache_update_needed = B_TRUE;
static int vol_sensor_count[SGENV_MAX_HPU_KEYS] = {0};
static int sgenv_mbox_error_count = 0;
static kmutex_t keysw_hdlr_lock;
static kmutex_t env_hdlr_lock;
static kmutex_t dr_hdlr_lock;
static sg_event_key_position_t keysw_payload;
static sbbc_msg_t keysw_payload_msg;
static sg_event_env_changed_t env_payload;
static sbbc_msg_t env_payload_msg;
static sg_event_fan_status_t fan_payload;
static sbbc_msg_t fan_payload_msg;
static sg_system_fru_descriptor_t dr_payload;
static sbbc_msg_t dr_payload_msg;
static const hpu_value_t hpus[] = {
HPU_ENTRY(SG_HPU_TYPE_UNKNOWN),
HPU_ENTRY(SG_HPU_TYPE_CPU_BOARD),
HPU_ENTRY(SG_HPU_TYPE_PCI_IO_BOARD),
HPU_ENTRY(SG_HPU_TYPE_CPCI_IO_BOARD),
HPU_ENTRY(SG_HPU_TYPE_SP_CPCI_IO_BOARD),
HPU_ENTRY(SG_HPU_TYPE_REPEATER_BOARD),
HPU_ENTRY(SG_HPU_TYPE_L2_REPEATER_BOARD),
HPU_ENTRY(SG_HPU_TYPE_SYSTEM_CONTROLLER_BOARD),
HPU_ENTRY(SG_HPU_TYPE_SP_SYSTEM_CONTROLLER_BOARD),
HPU_ENTRY(SG_HPU_TYPE_A123_POWER_SUPPLY),
HPU_ENTRY(SG_HPU_TYPE_A138_POWER_SUPPLY),
HPU_ENTRY(SG_HPU_TYPE_A145_POWER_SUPPLY),
HPU_ENTRY(SG_HPU_TYPE_A152_POWER_SUPPLY),
HPU_ENTRY(SG_HPU_TYPE_A153_POWER_SUPPLY),
HPU_ENTRY(SG_HPU_TYPE_RACK_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_SP_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_MD_TOP_IO_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_MD_BOTTOM_IO_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_R12_THREE_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_K12_IO_ONE_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_K12_CPU_THREE_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_R24_IO_FOUR_FAN_TRAY),
HPU_ENTRY(SG_HPU_TYPE_R24_CPU_SIX_FAN_TRAY),
0, (char *)NULL
};
static const struct part_value parts[] = {
PART_VALUE(SG_SENSOR_PART_SBBC),
PART_VALUE(SG_SENSOR_PART_SDC),
PART_VALUE(SG_SENSOR_PART_AR),
PART_VALUE(SG_SENSOR_PART_CBH),
PART_VALUE(SG_SENSOR_PART_DX),
PART_VALUE(SG_SENSOR_PART_CHEETAH),
PART_VALUE(SG_SENSOR_PART_1_5_VDC),
PART_VALUE(SG_SENSOR_PART_3_3_VDC),
PART_VALUE(SG_SENSOR_PART_5_VDC),
PART_VALUE(SG_SENSOR_PART_12_VDC),
PART_VALUE(SG_SENSOR_PART_48_VDC),
PART_VALUE(SG_SENSOR_PART_CURRENT),
PART_VALUE(SG_SENSOR_PART_BOARD),
PART_VALUE(SG_SENSOR_PART_SCAPP),
PART_VALUE(SG_SENSOR_PART_SCHIZO),
PART_VALUE(SG_SENSOR_PART_FAN),
0, (char *)NULL
};
static const struct type_value types[] = {
TYPE_VALUE(SG_SENSOR_TYPE_CURRENT, SG_CURRENT_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_TEMPERATURE, SG_TEMPERATURE_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_1_5_VDC, SG_1_5_VDC_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_1_8_VDC, SG_1_8_VDC_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_3_3_VDC, SG_3_3_VDC_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_5_VDC, SG_5_VDC_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_12_VDC, SG_12_VDC_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_48_VDC, SG_48_VDC_SCALE),
TYPE_VALUE(SG_SENSOR_TYPE_ENVDB, 1),
TYPE_VALUE(SG_SENSOR_TYPE_COOLING, 1),
0, (char *)NULL
};
int
_init(void)
{
int error = 0;
error = ddi_soft_state_init(&sgenv_statep,
sizeof (sgenv_soft_state_t), 1);
if (error)
return (error);
error = mod_install(&modlinkage);
if (error) {
ddi_soft_state_fini(&sgenv_statep);
return (error);
}
mutex_init(&env_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&env_cache_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&env_flag_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&env_flag_cond, NULL, CV_DEFAULT, NULL);
mutex_init(&board_cache_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&board_kstat_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&board_flag_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&board_flag_cond, NULL, CV_DEFAULT, NULL);
mutex_init(&keysw_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&env_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&dr_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
return (error);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
int
_fini(void)
{
int error = 0;
error = mod_remove(&modlinkage);
if (error)
return (error);
mutex_destroy(&env_kstat_lock);
mutex_destroy(&env_cache_lock);
mutex_destroy(&board_cache_lock);
mutex_destroy(&board_kstat_lock);
mutex_destroy(&keysw_hdlr_lock);
mutex_destroy(&env_hdlr_lock);
mutex_destroy(&dr_hdlr_lock);
ddi_soft_state_fini(&sgenv_statep);
return (error);
}
static int
sgenv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
sgenv_soft_state_t *softsp;
int instance;
int err;
switch (cmd) {
case DDI_ATTACH:
instance = ddi_get_instance(dip);
err = ddi_soft_state_zalloc(sgenv_statep, instance);
if (err != DDI_SUCCESS) {
cmn_err(CE_WARN, "attach: could not allocate state "
"structure for inst %d.", instance);
return (DDI_FAILURE);
}
softsp = ddi_get_soft_state(sgenv_statep, instance);
if (softsp == NULL) {
ddi_soft_state_free(sgenv_statep, instance);
cmn_err(CE_WARN, "attach: could not get state "
"structure for inst %d.", instance);
return (DDI_FAILURE);
}
softsp->dip = dip;
softsp->instance = instance;
err = sgenv_add_kstats(softsp);
if (err != 0) {
sgenv_remove_kstats(softsp);
ddi_soft_state_free(sgenv_statep, instance);
return (DDI_FAILURE);
}
sgenv_init_board_cache();
sgenv_init_env_cache();
err = sgenv_create_cache_update_threads();
if (err != DDI_SUCCESS) {
sgenv_remove_kstats(softsp);
ddi_soft_state_free(sgenv_statep, instance);
return (DDI_FAILURE);
}
err = ddi_create_minor_node(dip, SGENV_DRV_NAME, S_IFCHR,
instance, DDI_PSEUDO, 0);
if (err != DDI_SUCCESS) {
sgenv_remove_kstats(softsp);
(void) sgenv_remove_cache_update_threads();
ddi_soft_state_free(sgenv_statep, instance);
return (DDI_FAILURE);
}
err = sgenv_add_intr_handlers();
if (err != DDI_SUCCESS) {
cmn_err(CE_WARN, "Failed to add event handlers");
(void) sgenv_remove_intr_handlers();
sgenv_remove_kstats(softsp);
(void) sgenv_remove_cache_update_threads();
ddi_soft_state_free(sgenv_statep, instance);
return (DDI_FAILURE);
}
ddi_report_dev(dip);
return (DDI_SUCCESS);
case DDI_RESUME:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
static int
sgenv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
sgenv_soft_state_t *softsp;
int instance;
int err;
switch (cmd) {
case DDI_DETACH:
instance = ddi_get_instance(dip);
softsp = ddi_get_soft_state(sgenv_statep, instance);
if (softsp == NULL) {
cmn_err(CE_WARN, "detach: could not get state "
"structure for inst %d.", instance);
return (DDI_FAILURE);
}
err = sgenv_remove_cache_update_threads();
if (err != DDI_SUCCESS) {
cmn_err(CE_WARN, "Failed to remove update threads");
}
err = sgenv_remove_intr_handlers();
if (err != DDI_SUCCESS) {
cmn_err(CE_WARN, "Failed to remove event handlers");
}
sgenv_remove_kstats(softsp);
ddi_soft_state_free(sgenv_statep, instance);
ddi_remove_minor_node(dip, NULL);
return (DDI_SUCCESS);
case DDI_SUSPEND:
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
static int
sgenv_add_kstats(sgenv_soft_state_t *softsp)
{
kstat_t *ksp;
kstat_named_t *keyswitch_named_data;
int inst = softsp->instance;
ksp = kstat_create(SGENV_DRV_NAME, inst, SG_KEYSWITCH_KSTAT_NAME,
"misc", KSTAT_TYPE_NAMED, 1, 0);
if (ksp != NULL) {
keyswitch_named_data = (struct kstat_named *)(ksp->ks_data);
kstat_named_init(&keyswitch_named_data[0],
POSITION_KSTAT_NAME,
KSTAT_DATA_INT32);
ksp->ks_update = sgenv_keyswitch_kstat_update;
kstat_install(ksp);
softsp->keyswitch_ksp = ksp;
} else {
cmn_err(CE_WARN, "Keyswitch: kstat_create failed");
return (-1);
}
ksp = kstat_create(SGENV_DRV_NAME, inst, SG_ENV_INFO_KSTAT_NAME,
"misc", KSTAT_TYPE_RAW, 0,
KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
if (ksp != NULL) {
ksp->ks_data = NULL;
ksp->ks_data_size = 0;
ksp->ks_snaptime = 0;
ksp->ks_update = sgenv_env_info_kstat_update;
ksp->ks_snapshot = sgenv_env_info_kstat_snapshot;
ksp->ks_lock = &env_kstat_lock;
kstat_install(ksp);
softsp->env_info_ksp = ksp;
} else {
cmn_err(CE_WARN, "Environmental Info: kstat_create failed");
return (-1);
}
ksp = kstat_create(SGENV_DRV_NAME, inst, SG_BOARD_STATUS_KSTAT_NAME,
"misc", KSTAT_TYPE_RAW, 0,
KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_VAR_SIZE);
if (ksp != NULL) {
ksp->ks_data = NULL;
ksp->ks_data_size = 0;
ksp->ks_snaptime = 0;
ksp->ks_update = sgenv_board_info_kstat_update;
ksp->ks_snapshot = sgenv_board_info_kstat_snapshot;
ksp->ks_lock = &board_kstat_lock;
kstat_install(ksp);
softsp->board_info_ksp = ksp;
} else {
cmn_err(CE_WARN, "Board Status Info: kstat_create failed");
return (-1);
}
return (0);
}
static void
sgenv_remove_kstats(sgenv_soft_state_t *softsp)
{
kstat_t *ksp;
ksp = softsp->keyswitch_ksp;
if (ksp != NULL) {
softsp->keyswitch_ksp = NULL;
kstat_delete(ksp);
}
ksp = softsp->env_info_ksp;
if (ksp != NULL) {
sgenv_destroy_env_cache();
softsp->env_info_ksp = NULL;
ksp->ks_lock = NULL;
kstat_delete(ksp);
}
ksp = softsp->board_info_ksp;
if (ksp != NULL) {
softsp->board_info_ksp = NULL;
ksp->ks_lock = NULL;
kstat_delete(ksp);
}
}
static int
sgenv_add_intr_handlers(void)
{
int err;
keysw_payload_msg.msg_buf = (caddr_t)&keysw_payload;
keysw_payload_msg.msg_len = sizeof (keysw_payload);
err = sbbc_mbox_reg_intr(MBOX_EVENT_KEY_SWITCH, sgenv_keyswitch_handler,
&keysw_payload_msg, NULL, &keysw_hdlr_lock);
if (err != 0) {
cmn_err(CE_WARN, "Failed to register MBOX_EVENT_KEY_SWITCH "
"handler. Err=%d", err);
return (DDI_FAILURE);
}
env_payload_msg.msg_buf = (caddr_t)&env_payload;
env_payload_msg.msg_len = sizeof (env_payload);
err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, sgenv_env_data_handler,
&env_payload_msg, NULL, &env_hdlr_lock);
if (err != 0) {
cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV "
"(env) handler. Err=%d", err);
return (DDI_FAILURE);
}
fan_payload_msg.msg_buf = (caddr_t)&fan_payload;
fan_payload_msg.msg_len = sizeof (fan_payload);
err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, sgenv_fan_status_handler,
&fan_payload_msg, NULL, &env_hdlr_lock);
if (err != 0) {
cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV (fan)"
"handler. Err=%d", err);
return (DDI_FAILURE);
}
dr_payload_msg.msg_buf = (caddr_t)&dr_payload;
dr_payload_msg.msg_len = sizeof (dr_payload);
err = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC, sgenv_dr_event_handler,
&dr_payload_msg, NULL, &dr_hdlr_lock);
if (err != 0) {
cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC (DR)"
"handler. Err=%d", err);
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
sgenv_remove_intr_handlers(void)
{
int rv = DDI_SUCCESS;
int err;
err = sbbc_mbox_unreg_intr(MBOX_EVENT_KEY_SWITCH,
sgenv_keyswitch_handler);
if (err != 0) {
cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_KEY_SWITCH "
"handler. Err=%d", err);
rv = DDI_FAILURE;
}
err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, sgenv_env_data_handler);
if (err != 0) {
cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV (env)"
"handler. Err=%d", err);
rv = DDI_FAILURE;
}
err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, sgenv_fan_status_handler);
if (err != 0) {
cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV (fan)"
"handler. Err=%d", err);
rv = DDI_FAILURE;
}
err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, sgenv_dr_event_handler);
if (err != 0) {
cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC (DR) "
"handler. Err=%d", err);
rv = DDI_FAILURE;
}
return (rv);
}
static int
sgenv_create_cache_update_threads(void)
{
DCMN_ERR_S(f, "sgenv_create_cache_update_threads()");
DCMN_ERR_THREAD(CE_NOTE, "Entering %s", f);
env_thread_run = 1;
env_thread = thread_create(NULL, 0, sgenv_update_env_cache,
NULL, 0, &p0, TS_RUN, minclsyspri);
env_thread_tid = env_thread->t_did;
board_thread_run = 1;
board_thread = thread_create(NULL, 0, sgenv_update_board_cache,
NULL, 0, &p0, TS_RUN, minclsyspri);
board_thread_tid = board_thread->t_did;
DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
return (DDI_SUCCESS);
}
static int
sgenv_remove_cache_update_threads(void)
{
DCMN_ERR_S(f, "sgenv_remove_cache_update_threads()");
DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for cache update threads", f);
mutex_enter(&env_flag_lock);
env_thread_run = 0;
cv_signal(&env_flag_cond);
mutex_exit(&env_flag_lock);
thread_join(env_thread_tid);
mutex_enter(&board_flag_lock);
board_thread_run = 0;
cv_signal(&board_flag_cond);
mutex_exit(&board_flag_lock);
thread_join(board_thread_tid);
DCMN_ERR_THREAD(CE_NOTE, "%s: cache update threads finished", f);
return (DDI_SUCCESS);
}
static int
sgenv_keyswitch_kstat_update(kstat_t *ksp, int rw)
{
sg_keyswitch_kstat_t *keysw_data;
int8_t posn;
int size;
int rv = 0;
keysw_data = (sg_keyswitch_kstat_t *)ksp->ks_data;
switch (rw) {
case KSTAT_WRITE:
return (EACCES);
case KSTAT_READ:
size = iosram_size(SBBC_KEYSWITCH_KEY);
if (size != 1) {
posn = SG_KEYSWITCH_POSN_UNKNOWN;
rv = -1;
} else if ((rv = iosram_read(SBBC_KEYSWITCH_KEY, 0,
(char *)&posn, size)) != 0) {
posn = SG_KEYSWITCH_POSN_UNKNOWN;
} else {
switch (posn) {
case SG_KEYSWITCH_POSN_ON:
case SG_KEYSWITCH_POSN_DIAG:
case SG_KEYSWITCH_POSN_SECURE:
break;
default:
posn = SG_KEYSWITCH_POSN_UNKNOWN;
break;
}
}
keysw_data->keyswitch_position.value.i32 = posn;
return (rv);
default:
return (EINVAL);
}
}
static void
sgenv_init_env_cache(void)
{
ASSERT(env_thread_run == 0);
ASSERT(env_thread == NULL);
}
static void
sgenv_update_env_cache(void)
{
DCMN_ERR_S(f, "sgenv_update_env_cache()");
mutex_enter(&env_flag_lock);
while (env_thread_run == 1) {
if (env_cache_update_needed) {
DCMN_ERR_THREAD(CE_NOTE, "%s: update needed", f);
env_cache_update_needed = B_FALSE;
} else {
DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for signal", f);
cv_wait(&env_flag_cond, &env_flag_lock);
if (env_thread_run == 0) {
break;
}
env_cache_updating = B_TRUE;
}
mutex_exit(&env_flag_lock);
(void) sgenv_get_env_info_data();
(void) sgenv_check_sensor_thresholds();
mutex_enter(&env_flag_lock);
if (env_cache_update_needed == B_FALSE)
env_cache_updating = B_FALSE;
}
mutex_exit(&env_flag_lock);
DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
env_thread_run = -1;
thread_exit();
}
static int
sgenv_env_info_kstat_update(kstat_t *ksp, int rw)
{
DCMN_ERR_S(f, "sgenv_env_info_kstat_update()");
int err = 0;
int key_posn;
env_sensor_t *ptr;
switch (rw) {
case KSTAT_WRITE:
return (EACCES);
case KSTAT_READ:
mutex_enter(&env_cache_lock);
sgenv_update_env_kstat_size(ksp);
if ((env_cache_snapshot != NULL) &&
(env_cache_snapshot_size > 0)) {
DCMN_ERR_CACHE(CE_NOTE, "%s freeing "
"env_cache_snapshot buf", f);
kmem_free(env_cache_snapshot, env_cache_snapshot_size);
}
env_cache_snapshot_size = ksp->ks_data_size;
env_cache_snapshot = kmem_zalloc(
env_cache_snapshot_size, KM_SLEEP);
ptr = env_cache_snapshot;
for (key_posn = 0; key_posn < SGENV_MAX_HPU_KEYS; key_posn++) {
if (vol_sensor_count[key_posn] <= 0)
continue;
ASSERT(vol_sensor_count[key_posn] <=
SGENV_MAX_SENSORS_PER_KEY);
if (env_cache[key_posn] == NULL) {
DCMN_ERR(CE_NOTE, "!Cache entry %d has "
"disappeared", key_posn);
vol_sensor_count[key_posn] = 0;
continue;
}
bcopy(&env_cache[key_posn][0], ptr,
sizeof (env_sensor_t) *
vol_sensor_count[key_posn]);
ptr += vol_sensor_count[key_posn];
}
mutex_exit(&env_cache_lock);
return (err);
default:
return (EINVAL);
}
}
static int
sgenv_env_info_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
{
DCMN_ERR_S(f, "sgenv_env_info_kstat_snapshot()");
switch (rw) {
case KSTAT_WRITE:
return (EACCES);
case KSTAT_READ:
if (env_cache_snapshot_size > 0)
bcopy(env_cache_snapshot, buf, env_cache_snapshot_size);
ksp->ks_snaptime = last_env_read_time;
DCMN_ERR_CACHE(CE_NOTE, "%s freeing env_cache_snapshot buf", f);
kmem_free(env_cache_snapshot, env_cache_snapshot_size);
env_cache_snapshot = NULL;
env_cache_snapshot_size = 0;
return (0);
default:
return (EINVAL);
}
}
static void
sgenv_init_board_cache(void)
{
int i;
ASSERT(board_thread_run == 0);
ASSERT(board_thread == NULL);
mutex_enter(&board_cache_lock);
for (i = 0; i < SG_MAX_BDS; i++)
board_cache[i].node_id = (-1);
mutex_exit(&board_cache_lock);
}
static void
sgenv_update_board_cache(void)
{
DCMN_ERR_S(f, "sgenv_update_board_cache()");
mutex_enter(&board_flag_lock);
while (board_thread_run == 1) {
if (board_cache_update_needed) {
DCMN_ERR_THREAD(CE_NOTE, "%s: update needed", f);
board_cache_update_needed = B_FALSE;
} else {
DCMN_ERR_THREAD(CE_NOTE, "%s: Waiting for signal", f);
cv_wait(&board_flag_cond, &board_flag_lock);
if (board_thread_run == 0) {
break;
}
board_cache_updating = B_TRUE;
}
mutex_exit(&board_flag_lock);
(void) sgenv_get_board_info_data();
mutex_enter(&board_flag_lock);
if (board_cache_update_needed == B_FALSE)
board_cache_updating = B_FALSE;
}
mutex_exit(&board_flag_lock);
DCMN_ERR_THREAD(CE_NOTE, "Exiting %s", f);
board_thread_run = -1;
thread_exit();
}
static int
sgenv_board_info_kstat_update(kstat_t *ksp, int rw)
{
int i;
switch (rw) {
case KSTAT_WRITE:
return (EACCES);
case KSTAT_READ:
if (board_cache_updated == FALSE)
return (ENXIO);
mutex_enter(&board_cache_lock);
ksp->ks_data_size = board_count * sizeof (sg_board_info_t);
board_count_snapshot = board_count;
for (i = 0; i < SG_MAX_BDS; i++) {
board_cache_snapshot[i] = board_cache[i];
}
mutex_exit(&board_cache_lock);
return (0);
default:
return (EINVAL);
}
}
static int
sgenv_board_info_kstat_snapshot(kstat_t *ksp, void *buf, int rw)
{
DCMN_ERR_S(f, "sgenv_board_info_kstat_snapshot()");
sg_board_info_t *bdp;
int i, num_bds = 0;
switch (rw) {
case KSTAT_WRITE:
return (EACCES);
case KSTAT_READ:
if (board_cache_updated == FALSE) {
ksp->ks_data_size = 0;
ksp->ks_data = NULL;
return (ENOMEM);
}
ksp->ks_snaptime = last_board_read_time;
ASSERT(board_count_snapshot <= SG_MAX_BDS);
for (i = 0; i < SG_MAX_BDS; i++) {
bdp = &board_cache_snapshot[i];
DCMN_ERR_CACHE(CE_NOTE, "%s: looking at "
"cache_snapshot entry[%d], node=%d",
f, i, bdp->node_id);
if (bdp->node_id >= 0) {
num_bds++;
if (num_bds > board_count_snapshot) {
ksp->ks_data_size = 0;
ksp->ks_data = NULL;
DCMN_ERR(CE_WARN, "%s: buf overflow."
" %d >= %d.",
f, num_bds, board_count_snapshot);
return (EIO);
}
DCMN_ERR_CACHE(CE_NOTE, "%s: about to bcopy"
" cache_snapshot entry[%d], node=%d,"
" board=%d", f, i, bdp->node_id,
bdp->board_num);
bcopy(bdp, buf, sizeof (sg_board_info_t));
buf = ((sg_board_info_t *)buf) + 1;
}
}
return (0);
default:
return (EINVAL);
}
}
static int
sgenv_get_env_info_data(void)
{
DCMN_ERR_S(f, "sgenv_get_env_info_data()");
envresp_key_t new_keys[SGENV_MAX_HPU_KEYS] = {0};
envresp_key_t old_key;
envresp_key_t key;
int i;
int err = 0;
int status = 0;
DCMN_ERR_EVENT(CE_NOTE, "%s: entered.", f);
err = sgenv_get_hpu_keys(new_keys, &status);
if (err != 0) {
if (env_cache_updated == FALSE) {
sgenv_mbox_error_msg("HPU Keys", err, status);
return (err);
} else {
sgenv_mbox_error_msg("HPU Keys", err, status);
return (0);
}
}
for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
if (vol_sensor_count[i] == 0) {
old_key = 0;
} else {
ASSERT(env_cache[i] != NULL);
ASSERT(env_cache[i][0].sd_id.id.sensor_part ==
SG_SENSOR_PART_SCAPP);
ASSERT(env_cache[i][0].sd_id.id.sensor_type ==
SG_SENSOR_TYPE_ENVDB);
ASSERT(SG_INFO_VALUESTATUS(env_cache[i][0].sd_infostamp)
== SG_INFO_VALUE_OK);
old_key = env_cache[i][0].sd_value;
}
key = new_keys[i];
if ((key == 0) && (old_key == 0)) {
ASSERT(env_cache[i] == NULL);
continue;
}
mutex_enter(&env_cache_lock);
if (key == 0) {
ASSERT(old_key != 0);
(void) sgenv_clear_env_cache_entry(i);
mutex_exit(&env_cache_lock);
continue;
}
if (key != old_key) {
if (env_cache[i] == NULL) {
err = sgenv_create_env_cache_entry(i);
if (err == DDI_FAILURE) {
mutex_exit(&env_cache_lock);
continue;
}
}
err = sgenv_get_env_data(new_keys[i], i,
SG_GET_ENV_CONSTANTS, &status);
if (err) {
err = sgenv_handle_env_data_error(err, status,
i, old_key, "Constant Data");
mutex_exit(&env_cache_lock);
if (err != DDI_FAILURE) {
continue;
} else if (env_cache_updated == TRUE) {
return (0);
} else {
return (DDI_FAILURE);
}
}
err = sgenv_get_env_data(new_keys[i], i,
SG_GET_ENV_THRESHOLDS, &status);
if (err) {
err = sgenv_handle_env_data_error(err, status,
i, old_key, "Threshold Data");
mutex_exit(&env_cache_lock);
if (err != DDI_FAILURE) {
continue;
} else if (env_cache_updated == TRUE) {
return (0);
} else {
return (DDI_FAILURE);
}
}
err = sgenv_get_env_data(new_keys[i], i,
SG_GET_ENV_VOLATILES, &status);
if (err) {
err = sgenv_handle_env_data_error(err, status,
i, old_key, "Volatile Data (fresh)");
mutex_exit(&env_cache_lock);
if (err != DDI_FAILURE) {
continue;
} else if (env_cache_updated == TRUE) {
return (0);
} else {
return (DDI_FAILURE);
}
}
env_cache_updated = TRUE;
last_env_read_time = gethrtime();
} else {
ASSERT(env_cache[i] != NULL);
err = sgenv_get_env_data(new_keys[i], i,
SG_GET_ENV_VOLATILES, &status);
if (err) {
err = sgenv_handle_env_data_error(err, status,
i, old_key, "Volatile Data (update)");
mutex_exit(&env_cache_lock);
if (err == DDI_FAILURE) {
return (0);
} else {
continue;
}
}
}
mutex_exit(&env_cache_lock);
}
return (0);
}
static int
sgenv_get_board_info_data(void)
{
static uint_t node_present[SSM_MAX_INSTANCES] = {SGENV_NO_NODE_EXISTS};
static fn_t f = "sgenv_get_board_info_data()";
static int first_time = TRUE;
sbbc_msg_t req;
sbbc_msg_t resp;
int node;
int board;
show_board_t show_bd, *shbp = &show_bd;
info_t inform;
int status;
int rv = 0;
sg_board_info_t *ptr;
DCMN_ERR_EVENT(CE_NOTE, "%s: entered.", f);
if (first_time) {
sgenv_set_valid_node_positions(node_present);
first_time = FALSE;
}
for (node = 0; node < SSM_MAX_INSTANCES; node++) {
if (node_present[node] == SGENV_NO_NODE_EXISTS)
continue;
for (board = 0; board < SG_MAX_BDS; board++) {
if ((node_present[node] & (1 << board)) == 0)
continue;
inform.board = board;
inform.node = node;
inform.revision = 0xdead;
req.msg_type.type = DR_MBOX;
req.msg_type.sub_type = DR_MBOX_SHOW_BOARD;
req.msg_status = SG_MBOX_STATUS_SUCCESS;
req.msg_len = sizeof (info_t);
req.msg_bytes = sizeof (info_t);
req.msg_buf = (caddr_t)&inform;
bzero(shbp, sizeof (show_board_t));
shbp->s_cond = -1;
shbp->s_power = -1;
shbp->s_assigned = -1;
shbp->s_claimed = -1;
shbp->s_present = -1;
resp.msg_type.type = DR_MBOX;
resp.msg_type.sub_type = DR_MBOX_SHOW_BOARD;
resp.msg_bytes = sizeof (show_board_t);
resp.msg_status = SG_MBOX_STATUS_SUCCESS;
resp.msg_len = sizeof (show_board_t);
resp.msg_buf = (caddr_t)shbp;
if (sgenv_max_mbox_wait_time <=
max(sbbc_mbox_min_timeout, 0))
sgenv_max_mbox_wait_time =
sbbc_mbox_default_timeout;
rv = sbbc_mbox_request_response(&req, &resp,
sgenv_max_mbox_wait_time);
status = resp.msg_status;
if ((rv) || (status != SG_MBOX_STATUS_SUCCESS)) {
if (status > SG_MBOX_STATUS_SUCCESS) {
sgenv_mbox_error_msg("Board Info", rv,
resp.msg_status);
return (rv);
}
if (status == SG_MBOX_STATUS_ILLEGAL_NODE) {
sgenv_mbox_error_msg("Board Info", rv,
resp.msg_status);
node_present[node] =
SGENV_NO_NODE_EXISTS;
break;
} else if (status ==
SG_MBOX_STATUS_ILLEGAL_SLOT) {
node_present[node] &= (~(1 << board) &
SGENV_NODE_TYPE_DS);
continue;
} else if (status ==
SG_MBOX_STATUS_BOARD_ACCESS_DENIED) {
rv = rv;
} else {
char err_msg[40];
(void) sprintf(err_msg,
"Board data for "
"Node%d/Slot%d", node, board);
sgenv_mbox_error_msg(err_msg, rv,
resp.msg_status);
if (rv == 0)
rv = status;
continue;
}
}
mutex_enter(&board_cache_lock);
ptr = &board_cache[board];
if (shbp->s_assigned == -1) {
if (ptr->node_id != -1) {
board_count--;
ptr->node_id = -1;
DCMN_ERR_CACHE(CE_NOTE, "%s: "
"Clearing cache line %d [%p]",
f, board, (void *)ptr);
}
} else {
if (ptr->node_id == -1)
board_count++;
DCMN_ERR_CACHE(CE_NOTE, "%s: "
"Writing data for bd=%d into "
" the board_cache at [%p]",
f, board, (void *)ptr);
ptr->node_id = node;
ptr->board_num = board;
ptr->condition = shbp->s_cond;
ptr->assigned = shbp->s_assigned;
ptr->claimed = shbp->s_claimed;
ptr->present = shbp->s_present;
ptr->led.led_status =
shbp->s_ledstatus;
last_board_read_time = gethrtime();
}
mutex_exit(&board_cache_lock);
}
}
if (board_count > 0)
board_cache_updated = TRUE;
return (rv);
}
static int
sgenv_get_hpu_keys(envresp_key_t *new, int *status)
{
sbbc_msg_t req;
sbbc_msg_t resp;
int rv;
req.msg_type.type = SG_ENV;
req.msg_type.sub_type = SG_GET_ENV_HPU_KEYS;
req.msg_status = SG_MBOX_STATUS_SUCCESS;
req.msg_len = 0;
req.msg_bytes = 0;
resp.msg_type.type = SG_ENV;
resp.msg_type.sub_type = SG_GET_ENV_HPU_KEYS;
resp.msg_status = SG_MBOX_STATUS_SUCCESS;
resp.msg_len = sizeof (envresp_key_t) * SGENV_MAX_HPU_KEYS;
resp.msg_bytes = 0;
resp.msg_buf = (caddr_t)new;
if (sgenv_max_mbox_wait_time <= max(sbbc_mbox_min_timeout, 0))
sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
rv = sbbc_mbox_request_response(&req, &resp, sgenv_max_mbox_wait_time);
*status = resp.msg_status;
return (rv);
}
static int
sgenv_get_env_data(envresp_key_t key, int key_posn, uint16_t flag, int *status)
{
union {
envresp_constants_t con[SGENV_MAX_SENSORS_PER_KEY];
envresp_volatiles_t vol[SGENV_MAX_SENSORS_PER_KEY];
envresp_thresholds_t thr[SGENV_MAX_SENSORS_PER_KEY];
} buf;
sbbc_msg_t req;
sbbc_msg_t resp;
int i;
int rv;
ASSERT(MUTEX_HELD(&env_cache_lock));
ASSERT(env_cache[key_posn] != NULL);
if (flag == SG_GET_ENV_CONSTANTS) {
resp.msg_len = sizeof (buf.con);
resp.msg_buf = (caddr_t)buf.con;
} else if (flag == SG_GET_ENV_VOLATILES) {
resp.msg_len = sizeof (buf.vol);
resp.msg_buf = (caddr_t)buf.vol;
} else if (flag == SG_GET_ENV_THRESHOLDS) {
resp.msg_len = sizeof (buf.thr);
resp.msg_buf = (caddr_t)buf.thr;
} else {
*status = EINVAL;
return (-1);
}
req.msg_type.type = SG_ENV;
req.msg_type.sub_type = flag;
req.msg_status = SG_MBOX_STATUS_SUCCESS;
req.msg_len = 0;
req.msg_bytes = 0;
req.msg_data[0] = key;
resp.msg_type.type = SG_ENV;
resp.msg_type.sub_type = flag;
resp.msg_status = SG_MBOX_STATUS_SUCCESS;
resp.msg_bytes = 0;
if (sgenv_max_mbox_wait_time <= max(sbbc_mbox_min_timeout, 0))
sgenv_max_mbox_wait_time = sbbc_mbox_default_timeout;
rv = sbbc_mbox_request_response(&req, &resp, sgenv_max_mbox_wait_time);
*status = resp.msg_status;
if (rv != 0) {
return (rv);
} else {
switch (*status) {
case SG_MBOX_STATUS_SUCCESS:
break;
case ETIMEDOUT:
return (ETIMEDOUT);
case ENXIO:
return (ENXIO);
default:
SGENV_PRINT_MBOX_MSG((&resp), "Env info problem");
return (EINVAL);
}
}
for (i = 0; i < resp.msg_data[0]; i++) {
if (flag == SG_GET_ENV_CONSTANTS) {
env_cache[key_posn][i].sd_id.tag_id =
buf.con[i].id.tag_id;
env_cache[key_posn][i].sd_lo =
buf.con[i].lo;
env_cache[key_posn][i].sd_hi =
buf.con[i].hi;
} else if (flag == SG_GET_ENV_VOLATILES) {
env_cache[key_posn][i].sd_value =
buf.vol[i].value;
env_cache[key_posn][i].sd_infostamp =
buf.vol[i].info;
sgenv_set_sensor_status(&env_cache[key_posn][i]);
} else if (flag == SG_GET_ENV_THRESHOLDS) {
env_cache[key_posn][i].sd_lo_warn =
buf.thr[i].lo_warn;
env_cache[key_posn][i].sd_hi_warn =
buf.thr[i].hi_warn;
}
}
if (flag == SG_GET_ENV_VOLATILES)
vol_sensor_count[key_posn] = resp.msg_data[0];
return (rv);
}
static int
sgenv_handle_env_data_error(int err, int status, int key_posn,
envresp_key_t key, char *str)
{
int rv = DDI_SUCCESS;
ASSERT(str != (char *)NULL);
switch (err) {
case ENXIO:
DCMN_ERR_CACHE(CE_NOTE, "key @ posn %d has changed from %d"
" while %s", key_posn, key, str);
rv = ENXIO;
break;
default:
sgenv_mbox_error_msg(str, err, status);
rv = DDI_FAILURE;
break;
}
if (key == 0)
sgenv_clear_env_cache_entry(key_posn);
return (rv);
}
static void
sgenv_clear_env_cache_entry(int key_posn)
{
ASSERT(MUTEX_HELD(&env_cache_lock));
if (env_cache[key_posn] != NULL) {
kmem_free(env_cache[key_posn], sizeof (env_sensor_t) *
SGENV_MAX_SENSORS_PER_KEY);
env_cache[key_posn] = NULL;
vol_sensor_count[key_posn] = 0;
}
}
static void
sgenv_mbox_error_msg(char *str, int err, int status)
{
if (sgenv_mbox_error_count < INT_MAX)
sgenv_mbox_error_count++;
#ifdef DEBUG
if ((sgenv_debug & SGENV_DEBUG_MSG) == 0)
return;
ASSERT(str != NULL);
switch (err) {
case ENOTSUP:
DCMN_ERR(CE_WARN, "!This system configuration does not "
"support SGENV");
break;
case ETIMEDOUT:
DCMN_ERR(CE_WARN, "!Mailbox timed out while servicing "
"SGENV request for %s", str);
break;
default:
DCMN_ERR(CE_WARN, "!Error occurred reading %s, Errno=%d,"
" Status=%d", str, err, status);
break;
}
#endif
}
static int
sgenv_create_env_cache_entry(int key_posn)
{
int i;
ASSERT(key_posn < SGENV_MAX_HPU_KEYS);
ASSERT(key_posn >= 0);
env_cache[key_posn] = (env_sensor_t *)kmem_zalloc(
sizeof (env_sensor_t) * SGENV_MAX_SENSORS_PER_KEY, KM_NOSLEEP);
if (env_cache[key_posn] == NULL) {
cmn_err(CE_WARN, "Failed to allocate memory for env_cache[%d]",
key_posn);
return (DDI_FAILURE);
}
for (i = 0; i < SGENV_MAX_SENSORS_PER_KEY; i++)
env_cache[key_posn][i].sd_status = SG_SENSOR_STATUS_OK;
return (DDI_SUCCESS);
}
static void
sgenv_destroy_env_cache(void)
{
int i;
ASSERT(MUTEX_HELD(&env_cache_lock) == FALSE);
mutex_enter(&env_cache_lock);
for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
if (env_cache[i] != NULL) {
kmem_free(env_cache[i], sizeof (env_sensor_t) *
SGENV_MAX_SENSORS_PER_KEY);
env_cache[i] = NULL;
vol_sensor_count[i] = 0;
}
}
env_cache_updated = FALSE;
mutex_exit(&env_cache_lock);
}
static void
sgenv_update_env_kstat_size(kstat_t *ksp)
{
int i;
ASSERT(MUTEX_HELD(&env_cache_lock));
ksp->ks_data_size = 0;
for (i = 0; i < SGENV_MAX_HPU_KEYS; i++) {
if (vol_sensor_count[i] <= 0)
continue;
ASSERT(vol_sensor_count[i] <= SGENV_MAX_SENSORS_PER_KEY);
ksp->ks_data_size += vol_sensor_count[i] *
sizeof (env_sensor_t);
}
ASSERT(ksp->ks_data_size >= 0);
}
static uint_t
sgenv_check_sensor_thresholds(void)
{
DCMN_ERR_S(f, "sgenv_poll_env()");
int key;
int i;
env_sensor_t sensor;
env_sensor_status_t status;
DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
mutex_enter(&env_cache_lock);
for (key = 0; key < SGENV_MAX_HPU_KEYS; key++) {
if (vol_sensor_count[key] == 0)
continue;
for (i = 0; i < vol_sensor_count[key]; i++) {
sensor = env_cache[key][i];
status = sensor.sd_status;
if (SG_GET_SENSOR_STATUS(status) ==
SG_GET_PREV_SENSOR_STATUS(status)) {
continue;
}
switch (sensor.sd_id.id.sensor_type) {
case SG_SENSOR_TYPE_ENVDB:
case SG_SENSOR_TYPE_COOLING:
continue;
default:
(void) sgenv_process_threshold_event(sensor);
break;
}
SGENV_PRINT_POLL_INFO(sensor);
}
}
mutex_exit(&env_cache_lock);
return (DDI_SUCCESS);
}
static void
sgenv_set_valid_node_positions(uint_t *node_present)
{
dev_info_t *rdip;
dev_info_t *dip;
ASSERT(node_present != NULL);
rdip = ddi_root_node();
for (dip = ddi_get_child(rdip); dip != NULL;
dip = ddi_get_next_sibling(dip)) {
if (strncmp("ssm", ddi_node_name(dip), 3) == 0) {
int value;
value = ddi_getprop(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "nodeid", 0);
if ((value >= 0) &&
(value < SSM_MAX_INSTANCES) &&
(node_present[value] == SGENV_NO_NODE_EXISTS)) {
node_present[value] = SGENV_NODE_TYPE_DS;
}
}
}
}
static void
sgenv_set_sensor_status(env_sensor_t *sensor)
{
env_sensor_status_t *status;
ASSERT(sensor != NULL);
status = &sensor->sd_status;
SG_SET_PREV_SENSOR_STATUS(*status, *status);
switch (sensor->sd_id.id.sensor_type) {
case SG_SENSOR_TYPE_ENVDB:
SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_OK);
break;
case SG_SENSOR_TYPE_COOLING:
if (sensor->sd_value == SGENV_FAN_SPEED_HIGH) {
SG_SET_SENSOR_STATUS(*status,
SG_SENSOR_STATUS_FAN_HIGH);
} else if (sensor->sd_value == SGENV_FAN_SPEED_LOW) {
SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_FAN_LOW);
} else if (sensor->sd_value == SGENV_FAN_SPEED_OFF) {
SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_FAN_OFF);
} else {
SG_SET_SENSOR_STATUS(*status,
SG_SENSOR_STATUS_FAN_FAIL);
}
if (SG_GET_PREV_SENSOR_STATUS(*status) == SG_SENSOR_STATUS_OK) {
SG_SET_PREV_SENSOR_STATUS(*status, *status);
}
break;
default:
if (sensor->sd_value > sensor->sd_hi) {
SG_SET_SENSOR_STATUS(*status,
SG_SENSOR_STATUS_HI_DANGER);
} else if (sensor->sd_value > sensor->sd_hi_warn) {
SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_HI_WARN);
} else if (sensor->sd_value < sensor->sd_lo) {
SG_SET_SENSOR_STATUS(*status,
SG_SENSOR_STATUS_LO_DANGER);
} else if (sensor->sd_value < sensor->sd_lo_warn) {
SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_LO_WARN);
} else {
SG_SET_SENSOR_STATUS(*status, SG_SENSOR_STATUS_OK);
}
break;
}
}
static const char *
sgenv_get_hpu_id_str(uint_t hpu_type)
{
const hpu_value_t *hpu_list = hpus;
while (hpu_list->name != (char *)NULL) {
if (hpu_list->value == hpu_type)
return (hpu_list->IDstr);
else
hpu_list++;
}
return ((char *)NULL);
}
static const char *
sgenv_get_part_str(uint_t sensor_part)
{
const part_value_t *part_list = parts;
while (part_list->name != (char *)NULL) {
if (part_list->value == sensor_part)
return (part_list->name);
else
part_list++;
}
return ((char *)NULL);
}
static const char *
sgenv_get_type_str(uint_t sensor_type)
{
const type_value_t *type_list = types;
while (type_list->name != (char *)NULL) {
if (type_list->value == sensor_type)
return (type_list->name);
else
type_list++;
}
return ((char *)NULL);
}
static void
sgenv_tagid_to_string(sensor_id_t id, char *str)
{
const char *hpu_str;
const char *part_str;
const char *type_str;
ASSERT(str != NULL);
hpu_str = sgenv_get_hpu_id_str(id.id.hpu_type);
part_str = sgenv_get_part_str(id.id.sensor_part);
type_str = sgenv_get_type_str(id.id.sensor_type);
(void) sprintf(str,
"Sensor: Node=%d, Board=%s%d, Device=%s%d, Type=%s%d: reading has ",
id.id.node_id,
((hpu_str != NULL) ? hpu_str : ""),
id.id.hpu_slot,
((part_str != NULL) ? part_str : ""),
id.id.sensor_partnum,
((type_str != NULL) ? type_str : ""),
id.id.sensor_typenum);
}
static uint_t
sgenv_keyswitch_handler(char *arg)
{
DCMN_ERR_S(f, "sgenv_keyswitch_handler()");
sysevent_t *ev = NULL;
sysevent_id_t eid;
sysevent_value_t se_val;
sysevent_attr_list_t *ev_attr_list = NULL;
sg_event_key_position_t *payload = NULL;
sbbc_msg_t *msg = NULL;
int err;
DCMN_ERR_EVENT(CE_NOTE, "%s called", f);
if (arg == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
return (DDI_INTR_CLAIMED);
}
msg = (sbbc_msg_t *)arg;
if (msg->msg_buf == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
return (DDI_INTR_CLAIMED);
}
payload = (sg_event_key_position_t *)msg->msg_buf;
if (payload == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: payload == NULL", f);
return (DDI_INTR_CLAIMED);
}
DCMN_ERR_EVENT(CE_NOTE, "Key posn = %d", (int)*payload);
ev = sysevent_alloc(EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE,
EP_SGENV, SE_NOSLEEP);
if (ev == NULL) {
cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event",
f, EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
return (DDI_INTR_CLAIMED);
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = DOMAIN_KEYSWITCH;
err = sysevent_add_attr(&ev_attr_list, DOMAIN_WHAT_CHANGED,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
DOMAIN_WHAT_CHANGED, EC_DOMAIN,
ESC_DOMAIN_STATE_CHANGE);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
err = log_sysevent(ev, SE_NOSLEEP, &eid);
if (err != 0) {
cmn_err(CE_WARN, "Failed to log %s/%s event",
EC_DOMAIN, ESC_DOMAIN_STATE_CHANGE);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
static uint_t
sgenv_env_data_handler(char *arg)
{
DCMN_ERR_S(f, "sgenv_env_data_handler()");
sg_event_env_changed_t *payload = NULL;
sbbc_msg_t *msg = NULL;
DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
if (arg == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
return (DDI_INTR_CLAIMED);
}
msg = (sbbc_msg_t *)arg;
if (msg->msg_buf == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
return (DDI_INTR_CLAIMED);
}
payload = (sg_event_env_changed_t *)msg->msg_buf;
if (payload->event_type != SC_EVENT_ENV) {
return (DDI_INTR_CLAIMED);
}
sgenv_indicate_cache_update_needed(ENV_CACHE);
return (DDI_INTR_CLAIMED);
}
static uint_t
sgenv_fan_status_handler(char *arg)
{
DCMN_ERR_S(f, "sgenv_fan_status_handler()");
sysevent_t *ev = NULL;
sysevent_id_t eid;
sysevent_value_t se_val;
sysevent_attr_list_t *ev_attr_list = NULL;
sg_event_fan_status_t *payload = NULL;
sbbc_msg_t *msg = NULL;
char fan_str[MAXNAMELEN];
int err;
DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
if (arg == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
return (DDI_INTR_CLAIMED);
}
msg = (sbbc_msg_t *)arg;
if (msg->msg_buf == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
return (DDI_INTR_CLAIMED);
}
payload = (sg_event_fan_status_t *)msg->msg_buf;
if (payload->event_type != SC_EVENT_FAN) {
return (DDI_INTR_CLAIMED);
}
ev = sysevent_alloc(EC_ENV, ESC_ENV_FAN, EP_SGENV, SE_NOSLEEP);
if (ev == NULL) {
cmn_err(CE_WARN, "%s: Failed to alloc mem for %s/%s event",
f, EC_ENV, ESC_ENV_FAN);
return (DDI_INTR_CLAIMED);
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = ENV_RESERVED_ATTR;
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_ID, &se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_ID, EC_ENV, ESC_ENV_FAN);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = ENV_RESERVED_ATTR;
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_RESOURCE_ID,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = ENV_RESERVED_ATTR;
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_DEVICE,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
se_val.value_type = SE_DATA_TYPE_INT32;
switch (payload->fan_speed) {
case SGENV_FAN_SPEED_OFF:
case SGENV_FAN_SPEED_LOW:
case SGENV_FAN_SPEED_HIGH:
se_val.value.sv_int32 = ENV_OK;
break;
case SGENV_FAN_SPEED_UNKNOWN:
default:
se_val.value.sv_int32 = ENV_FAILED;
break;
}
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_STATE,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
(void) sprintf(fan_str,
"The status of the fan in Node%d/Slot%d is now ",
payload->node_id, payload->slot_number);
switch (payload->fan_speed) {
case SGENV_FAN_SPEED_OFF:
(void) strcat(fan_str, SGENV_FAN_SPEED_OFF_STR);
break;
case SGENV_FAN_SPEED_LOW:
(void) strcat(fan_str, SGENV_FAN_SPEED_LOW_STR);
break;
case SGENV_FAN_SPEED_HIGH:
(void) strcat(fan_str, SGENV_FAN_SPEED_HIGH_STR);
break;
case SGENV_FAN_SPEED_UNKNOWN:
default:
(void) strcat(fan_str, SGENV_FAN_SPEED_UNKNOWN_STR);
break;
}
DCMN_ERR_EVENT(CE_NOTE, "Fan: %s", fan_str);
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = fan_str;
err = sysevent_add_attr(&ev_attr_list, ENV_MSG, &se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_MSG, EC_ENV, ESC_ENV_FAN);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
EC_ENV, ESC_ENV_FAN);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
err = log_sysevent(ev, SE_NOSLEEP, &eid);
if (err != 0) {
cmn_err(CE_WARN, "Failed to log %s/%s event",
EC_ENV, ESC_ENV_FAN);
sysevent_free(ev);
return (DDI_INTR_CLAIMED);
}
sysevent_free(ev);
sgenv_indicate_cache_update_needed(ENV_CACHE);
return (DDI_INTR_CLAIMED);
}
static int
sgenv_process_threshold_event(env_sensor_t sensor)
{
DCMN_ERR_S(f, "sgenv_process_threshold_event()");
sysevent_t *ev = NULL;
sysevent_id_t eid;
sysevent_value_t se_val;
sysevent_attr_list_t *ev_attr_list = NULL;
int err;
char sensor_str[MAX_TAG_ID_STR_LEN];
int temp_event_type;
switch (sensor.sd_id.id.sensor_type) {
case SG_SENSOR_TYPE_TEMPERATURE:
temp_event_type = TRUE;
ev = sysevent_alloc(EC_ENV, ESC_ENV_TEMP, EP_SGENV, SE_NOSLEEP);
if (ev == NULL) {
cmn_err(CE_WARN, "Failed to allocate sysevent buffer "
"for %s/%s event", EC_ENV, ESC_ENV_TEMP);
return (DDI_FAILURE);
}
break;
default:
temp_event_type = FALSE;
ev = sysevent_alloc(EC_ENV, ESC_ENV_POWER,
EP_SGENV, SE_NOSLEEP);
if (ev == NULL) {
cmn_err(CE_WARN, "Failed to allocate sysevent buffer "
"for %s/%s event", EC_ENV, ESC_ENV_POWER);
return (DDI_FAILURE);
}
break;
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = ENV_RESERVED_ATTR;
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_ID, &se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_ID, EC_ENV,
(temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
sysevent_free(ev);
return (DDI_FAILURE);
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = ENV_RESERVED_ATTR;
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_RESOURCE_ID,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_RESOURCE_ID, EC_ENV,
(temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_FAILURE);
}
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = ENV_RESERVED_ATTR;
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_DEVICE,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_FRU_DEVICE, EC_ENV,
(temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_FAILURE);
}
se_val.value_type = SE_DATA_TYPE_INT32;
switch (SG_GET_SENSOR_STATUS(sensor.sd_status)) {
case SG_SENSOR_STATUS_OK:
se_val.value.sv_int32 = ENV_OK;
break;
case SG_SENSOR_STATUS_LO_WARN:
case SG_SENSOR_STATUS_HI_WARN:
se_val.value.sv_int32 = ENV_WARNING;
break;
case SG_SENSOR_STATUS_LO_DANGER:
case SG_SENSOR_STATUS_HI_DANGER:
default:
se_val.value.sv_int32 = ENV_FAILED;
break;
}
err = sysevent_add_attr(&ev_attr_list, ENV_FRU_STATE,
&se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr[%s] for %s/%s event "
"(Err=%d)", ENV_FRU_STATE, EC_ENV,
(temp_event_type ? ESC_ENV_TEMP: ESC_ENV_POWER),
err);
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_FAILURE);
}
sgenv_tagid_to_string(sensor.sd_id, sensor_str);
switch (SG_GET_SENSOR_STATUS(sensor.sd_status)) {
case SG_SENSOR_STATUS_OK:
(void) strcat(sensor_str, SGENV_EVENT_MSG_OK);
break;
case SG_SENSOR_STATUS_LO_WARN:
(void) strcat(sensor_str, SGENV_EVENT_MSG_LO_WARN);
break;
case SG_SENSOR_STATUS_HI_WARN:
(void) strcat(sensor_str, SGENV_EVENT_MSG_HI_WARN);
break;
case SG_SENSOR_STATUS_LO_DANGER:
(void) strcat(sensor_str, SGENV_EVENT_MSG_LO_DANGER);
break;
case SG_SENSOR_STATUS_HI_DANGER:
(void) strcat(sensor_str, SGENV_EVENT_MSG_HI_DANGER);
break;
default:
DCMN_ERR_EVENT(CE_NOTE, "%s: Unknown sensor status", f);
(void) strcat(sensor_str, SGENV_EVENT_MSG_UNKNOWN);
break;
}
DCMN_ERR_EVENT(CE_NOTE, "Temp/Power: %s", sensor_str);
se_val.value_type = SE_DATA_TYPE_STRING;
se_val.value.sv_string = sensor_str;
err = sysevent_add_attr(&ev_attr_list, ENV_MSG, &se_val, SE_NOSLEEP);
if (err != 0) {
cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event",
ENV_MSG, EC_ENV,
(temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_FAILURE);
}
if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
cmn_err(CE_WARN, "Failed to attach attr list for %s/%s event",
EC_ENV,
(temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
sysevent_free_attr(ev_attr_list);
sysevent_free(ev);
return (DDI_FAILURE);
}
err = log_sysevent(ev, SE_NOSLEEP, &eid);
if (err != 0) {
cmn_err(CE_WARN, "Failed to log %s/%s event", EC_ENV,
(temp_event_type ? ESC_ENV_TEMP : ESC_ENV_POWER));
sysevent_free(ev);
return (DDI_FAILURE);
}
sysevent_free(ev);
return (DDI_SUCCESS);
}
static uint_t
sgenv_dr_event_handler(char *arg)
{
DCMN_ERR_S(f, "sgenv_dr_event_handler()");
sg_system_fru_descriptor_t *payload = NULL;
sbbc_msg_t *msg = NULL;
DCMN_ERR_EVENT(CE_NOTE, "%s: just been triggered.", f);
DCMN_ERR_EVENT(CE_NOTE, "%s: Start: %lld", f, gethrtime());
if (arg == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: arg == NULL", f);
return (DDI_INTR_CLAIMED);
}
msg = (sbbc_msg_t *)arg;
if (msg->msg_buf == NULL) {
DCMN_ERR_EVENT(CE_NOTE, "%s: msg_buf == NULL", f);
return (DDI_INTR_CLAIMED);
}
payload = (sg_system_fru_descriptor_t *)msg->msg_buf;
switch (payload->event_details) {
case SG_EVT_BOARD_ABSENT:
case SG_EVT_BOARD_PRESENT:
case SG_EVT_UNASSIGN:
case SG_EVT_ASSIGN:
case SG_EVT_UNAVAILABLE:
case SG_EVT_AVAILABLE:
case SG_EVT_POWER_OFF:
case SG_EVT_POWER_ON:
case SG_EVT_PASSED_TEST:
case SG_EVT_FAILED_TEST:
DCMN_ERR_EVENT(CE_NOTE, "%s: about to signal to background "
"threads due to event %d.", f, payload->event_details);
sgenv_indicate_cache_update_needed(ENV_CACHE);
sgenv_indicate_cache_update_needed(BOARD_CACHE);
break;
default:
DCMN_ERR_EVENT(CE_NOTE, "%s: Unknown DR event type.", f);
break;
}
DCMN_ERR_EVENT(CE_NOTE, "%s: Finish: %lld", f, gethrtime());
return (DDI_INTR_CLAIMED);
}
static void
sgenv_indicate_cache_update_needed(int cache_type)
{
DCMN_ERR_S(f, "sgenv_indicate_cache_update_needed()");
switch (cache_type) {
case ENV_CACHE:
mutex_enter(&env_flag_lock);
if (env_cache_updating) {
DCMN_ERR_THREAD(CE_NOTE, "%s: Thread already "
"updating env cache", f);
env_cache_update_needed = B_TRUE;
} else {
DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal "
"to env thread", f);
cv_signal(&env_flag_cond);
}
mutex_exit(&env_flag_lock);
break;
case BOARD_CACHE:
mutex_enter(&board_flag_lock);
if (board_cache_updating) {
DCMN_ERR_THREAD(CE_NOTE, "%s: Thread already "
"updating board cache", f);
board_cache_update_needed = B_TRUE;
} else {
DCMN_ERR_THREAD(CE_NOTE, "%s: Sending signal "
"to board thread", f);
cv_signal(&board_flag_cond);
}
mutex_exit(&board_flag_lock);
break;
default:
DCMN_ERR(CE_NOTE, "%s: Unknown cache type:0x%x", f, cache_type);
break;
}
}