meta-facebook/meta-fby3/recipes-fby3/plat-libs/files/pal/pal_power.c (1,346 lines of code) (raw):
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <fcntl.h>
#include <errno.h>
#include <syslog.h>
#include <sys/mman.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
#include <openbmc/kv.h>
#include <openbmc/libgpio.h>
#include <openbmc/obmc-i2c.h>
#include "pal.h"
#define CPLD_PWR_CTRL_BUS 12
#define CPLD_PWR_CTRL_ADDR 0x1F
#define REG_CWC_CPLD_CWC_HSC 0x01
#define REG_CWC_CPLD_GPV3_HSC 0x02
#define REG_CWC_CPLD_CARD_PWROK 0x0C
#define DELAY_POWER_CYCLE 5 //sec
#define MAX_POWER_CYCLE_DWELL 20 //sec
#define DELAY_EXP_POWER 2 //sec
#define MAX_EXP_POWER_DELAY 6 //sec
#define MAX_PWR_RETRY 3
enum {
POWER_STATUS_ALREADY_OK = 1,
POWER_STATUS_OK = 0,
POWER_STATUS_ERR = -1,
POWER_STATUS_FRU_ERR = -2,
};
static uint8_t m_slot_pwr_ctrl[MAX_NODES+1] = {0};
bool
is_server_off(void) {
return POWER_STATUS_OK;
}
// Power Off the server
static int
server_power_off(uint8_t fru) {
int ret = 0;
uint8_t bmc_location = 0;
ret = fby3_common_get_bmc_location(&bmc_location);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__);
return POWER_STATUS_ERR;
}
return bic_server_power_off(fru);
}
// Power On the server
static int
server_power_on(uint8_t fru) {
int ret = 0;
uint8_t bmc_location = 0;
ret = fby3_common_get_bmc_location(&bmc_location);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__);
return POWER_STATUS_ERR;
}
return bic_server_power_on(fru);
}
static void
pal_power_policy_control(uint8_t slot, char *last_ps) {
uint8_t chassis_sts[8] = {0};
uint8_t chassis_sts_len;
uint8_t power_policy = POWER_CFG_UKNOWN;
char pwr_state[MAX_VALUE_LEN] = {0};
//get power restore policy
//defined by IPMI Spec/Section 28.2.
pal_get_chassis_status(slot, NULL, chassis_sts, &chassis_sts_len);
//byte[1], bit[6:5]: power restore policy
power_policy = (*chassis_sts >> 5);
//Check power policy and last power state
if (power_policy == POWER_CFG_LPS) {
if (!last_ps) {
pal_get_last_pwr_state(slot, pwr_state);
last_ps = pwr_state;
}
if (!(strcmp(last_ps, "on"))) {
sleep(3);
pal_set_server_power(slot, SERVER_POWER_ON);
}
}
else if (power_policy == POWER_CFG_ON) {
sleep(3);
pal_set_server_power(slot, SERVER_POWER_ON);
}
}
static int
server_power_12v_on(uint8_t fru) {
int i2cfd = 0;
char cmd[64] = {0};
uint8_t tbuf[2] = {0};
uint8_t tlen = 0;
uint8_t rbuf[2] = {0};
uint8_t rlen = 0;
int ret = 0, retry= 0;
i2cfd = i2c_cdev_slave_open(CPLD_PWR_CTRL_BUS, CPLD_PWR_CTRL_ADDR >> 1, I2C_SLAVE_FORCE_CLAIM);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open %d", __func__, CPLD_PWR_CTRL_BUS);
goto error_exit;
}
tbuf[0] = 0x09 + (fru-1);
tlen = 1;
rlen = 1;
while (retry < MAX_READ_RETRY) {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, tlen, rbuf, rlen);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if (retry == MAX_READ_RETRY) {
syslog(LOG_WARNING, "%s()%d Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, __LINE__, tlen);
goto error_exit;
}
if (rbuf[0] == AC_ON) {
tbuf[1] = AC_OFF;
tlen = 2;
while (retry < MAX_READ_RETRY) {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, tlen, NULL, 0);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if (retry == MAX_READ_RETRY) {
syslog(LOG_WARNING, "%s()%d Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, __LINE__, tlen);
goto error_exit;
}
sleep(2);
}
tbuf[1] = AC_ON;
tlen = 2;
retry = 0;
while (retry < MAX_READ_RETRY) {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, tlen, NULL, 0);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if (retry == MAX_READ_RETRY) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
goto error_exit;
}
sleep(1);
ret = fby3_common_set_fru_i2c_isolated(fru, GPIO_VALUE_HIGH);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to enable the i2c of fru%d", __func__, fru);
goto error_exit;
}
sleep(1);
// vr cached info was removed when 12v_off was performed
// we generate it again to avoid accessing VR devices at the same time.
snprintf(cmd, sizeof(cmd), "/usr/bin/fw-util slot%d --version vr > /dev/null 2>&1", fru);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
ret = PAL_ENOTSUP;
goto error_exit;
}
// SiC45X setting on 1/2ou was set in runtime
// it was lost when 12v_off was performed,
// need to reconfigure it again
snprintf(cmd, sizeof(cmd), "/etc/init.d/setup-sic.sh slot%d > /dev/null 2>&1", fru);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
ret = PAL_ENOTSUP;
goto error_exit;
}
pal_power_policy_control(fru, NULL);
error_exit:
if ( i2cfd > 0 ) close(i2cfd);
return ret;
}
static int
server_power_12v_off(uint8_t fru) {
int i2cfd = 0;
char cmd[64] = {0};
uint8_t tbuf[2] = {0};
uint8_t tlen = 0;
int ret = 0, retry= 0;
snprintf(cmd, 64, "rm -f /tmp/cache_store/slot%d_vr*", fru);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
}
ret = fby3_common_set_fru_i2c_isolated(fru, GPIO_VALUE_LOW);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to disable the i2c of fru%d", __func__, fru);
goto error_exit;
}
sleep(1);
i2cfd = i2c_cdev_slave_open(CPLD_PWR_CTRL_BUS, CPLD_PWR_CTRL_ADDR >> 1, I2C_SLAVE_FORCE_CLAIM);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open %d", __func__, CPLD_PWR_CTRL_BUS);
goto error_exit;
}
tbuf[0] = 0x09 + (fru-1);
tbuf[1] = AC_OFF;
tlen = 2;
retry = 0;
while (retry < MAX_READ_RETRY) {
ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, tlen, NULL, 0);
if ( ret < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if (retry == MAX_READ_RETRY) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer fails, tlen=%d", __func__, tlen);
goto error_exit;
}
error_exit:
if ( i2cfd > 0 ) close(i2cfd);
return ret;
}
int
pal_get_server_12v_power(uint8_t slot_id, uint8_t *status) {
int ret = 0;
ret = fby3_common_server_stby_pwr_sts(slot_id, status);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s: Failed to run fby3_common_server_stby_pwr_sts on slot%d\n", __func__, slot_id);
}
if ( *status == 1 ) {
*status = SERVER_12V_ON;
} else {
*status = SERVER_12V_OFF;
}
return ret;
}
int
pal_server_set_nic_power(const uint8_t expected_pwr) {
int i = 0;
int ret = 0;
uint8_t svr_sts = 0;
uint8_t pwr_sts = 0;
for ( i = FRU_SLOT1; i <= FRU_SLOT4; i++ ) {
ret = fby3_common_is_fru_prsnt(i, &svr_sts);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s(): Failed to get the prsnt sts. fru%d", __FUNCTION__, i);
return PAL_ENOTSUP;
}
//it's prsnt
if ( svr_sts != 0 ) {
//read slot/12V pwr
switch (expected_pwr) {
case SERVER_POWER_ON:
case SERVER_POWER_OFF:
ret = pal_get_server_12v_power(i, &pwr_sts);
if ( ret == PAL_EOK && pwr_sts == SERVER_12V_ON ) {
ret = bic_get_server_power_status(i, &pwr_sts);
if ( ret == PAL_EOK && pwr_sts == SERVER_POWER_ON ) {
return PAL_ENOTREADY;
}
}
if ( ret < 0 ) {
if (expected_pwr == SERVER_POWER_ON) {
syslog(LOG_WARNING, "%s(SERVER_POWER_ON): Failed to get the pwr sts. fru%d", __FUNCTION__, i);
} else if (expected_pwr == SERVER_POWER_OFF) {
syslog(LOG_WARNING, "%s(SERVER_POWER_OFF): Failed to get the pwr sts. fru%d", __FUNCTION__, i);
return PAL_ENOTSUP;
}
}
break;
default:
return PAL_ENOTSUP;
}
}
}
//change the power mode of NIC to expected_pwr
int fd = -1;
uint8_t tbuf[2] = {0x0f, (expected_pwr&0x1)};
uint8_t tlen = 1;
uint8_t rbuf[1];
uint8_t rlen = 1;
int pid_file = 0;
if ( SERVER_POWER_ON == expected_pwr ) {
pid_file = open(SET_NIC_PWR_MODE_LOCK, O_CREAT | O_RDWR, 0666);
}
fd = i2c_cdev_slave_open(CPLD_PWR_CTRL_BUS, CPLD_PWR_CTRL_ADDR >> 1, I2C_SLAVE_FORCE_CLAIM);
if ( fd < 0 ) {
syslog(LOG_WARNING, "Failed to open bus 12");
return PAL_ENOTSUP;
}
ret = i2c_rdwr_msg_transfer(fd, CPLD_PWR_CTRL_ADDR, tbuf, tlen, rbuf, rlen);
if ( ret < 0) {
syslog(LOG_WARNING, "Failed to get NIC Power mode in CPLD");
} else {
// change the power mode of NIC when orginal mode in cpld is different
if (rbuf[0] != expected_pwr) {
tlen = 2;
ret = i2c_rdwr_msg_transfer(fd, CPLD_PWR_CTRL_ADDR, tbuf, tlen, NULL, 0);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Failed to change NIC Power mode");
} else {
//if one of them want to wake up, we need to set it and sleep 2s to wait for PERST#
//2s is enough for CPLD
if ( SERVER_POWER_ON == expected_pwr ) {
syslog(LOG_CRIT, "NIC Power is set to VMAIN");
sleep(2);
} else if ( SERVER_POWER_OFF == expected_pwr ) {
syslog(LOG_CRIT, "NIC Power is set to VAUX");
}
}
}
}
if ( pid_file > 0 ) {
close(pid_file);
remove(SET_NIC_PWR_MODE_LOCK);
}
if ( fd > 0 ) close(fd);
return (ret < 0)?PAL_ENOTSUP:PAL_EOK;
}
int
pal_get_server_power(uint8_t fru, uint8_t *status) {
int ret;
if (fru == FRU_CWC || fru == FRU_2U_TOP || fru == FRU_2U_BOT) {
if (pal_is_cwc() == PAL_EOK)
return pal_get_exp_power(fru, status);
else
return POWER_STATUS_FRU_ERR;
}
ret = fby3_common_check_slot_id(fru);
if ( ret < 0 ) {
return POWER_STATUS_FRU_ERR;
}
ret = pal_get_server_12v_power(fru, status);
if ( ret < 0 || (*status) == SERVER_12V_OFF ) {
// return earlier if power state is SERVER_12V_OFF or error happened
return ret;
}
if (bic_get_server_power_status(fru, status) < 0) {
// if bic not responsing, we reset status to SERVER_12V_ON
*status = SERVER_12V_ON;
}
return ret;
}
// Power Off, Power On, or Power Reset the server in given slot
int
pal_set_server_power(uint8_t fru, uint8_t cmd) {
uint8_t status;
int ret = 0;
uint8_t bmc_location = 0;
if (fru == FRU_CWC || fru == FRU_2U_TOP || fru == FRU_2U_BOT) {
if (pal_is_cwc() == PAL_EOK)
return pal_set_exp_power(fru, cmd);
else
return POWER_STATUS_FRU_ERR;
}
ret = fby3_common_check_slot_id(fru);
if ( ret < 0 ) {
return POWER_STATUS_FRU_ERR;
}
ret = fby3_common_get_bmc_location(&bmc_location);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__);
return POWER_STATUS_ERR;
}
switch (cmd) {
case SERVER_12V_OFF:
case SERVER_12V_ON:
case SERVER_12V_CYCLE:
//do nothing
break;
default:
if (pal_get_server_power(fru, &status) < 0) {
return POWER_STATUS_ERR;
}
if (status == SERVER_12V_OFF) {
// discard the commands if power state is 12V-off
return POWER_STATUS_FRU_ERR;
}
break;
}
switch(cmd) {
case SERVER_POWER_ON:
if ( status == SERVER_POWER_ON ) return POWER_STATUS_ALREADY_OK;
if ( bmc_location != NIC_BMC) {
ret = pal_server_set_nic_power(SERVER_POWER_ON); //only check it on class 1
if (ret == PAL_ENOTSUP) {
syslog(LOG_WARNING,"%s(SERVER_POWER_ON): fru%d pal_server_set_nic_power fail", __FUNCTION__, fru);
return POWER_STATUS_ERR;
}
} else ret = PAL_EOK;
return server_power_on(fru);
break;
case SERVER_POWER_OFF:
return (status == SERVER_POWER_OFF)?POWER_STATUS_ALREADY_OK:server_power_off(fru);
break;
case SERVER_POWER_CYCLE:
if (status == SERVER_POWER_ON) {
return bic_server_power_cycle(fru);
} else if (status == SERVER_POWER_OFF) {
if ( bmc_location != NIC_BMC) {
ret = pal_server_set_nic_power(SERVER_POWER_ON); //only check it on class 1
} else ret = PAL_EOK;
return (ret == PAL_ENOTSUP)?POWER_STATUS_ERR:server_power_on(fru);
}
break;
case SERVER_GRACEFUL_SHUTDOWN:
return (status == SERVER_POWER_OFF)?POWER_STATUS_ALREADY_OK:bic_server_graceful_power_off(fru);
break;
case SERVER_POWER_RESET:
return (status == SERVER_POWER_OFF)?POWER_STATUS_ERR:bic_server_power_reset(fru);
break;
case SERVER_12V_ON:
if ( bmc_location == NIC_BMC || pal_get_server_12v_power(fru, &status) < 0 ) {
return POWER_STATUS_ERR;
}
if (status == SERVER_12V_ON) {
pal_power_policy_control(fru, NULL);
return POWER_STATUS_ALREADY_OK;
} else {
return server_power_12v_on(fru);
}
break;
case SERVER_12V_OFF:
if ( bmc_location == NIC_BMC || pal_get_server_12v_power(fru, &status) < 0 ) {
return POWER_STATUS_ERR;
}
if ( status == SERVER_12V_OFF ) return POWER_STATUS_ALREADY_OK;
return server_power_12v_off(fru);
break;
case SERVER_12V_CYCLE:
if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) {
if ( pal_get_server_12v_power(fru, &status) < 0 ) {
return POWER_STATUS_ERR;
}
if (status == SERVER_12V_OFF) {
return server_power_12v_on(fru);
} else {
if ( server_power_12v_off(fru) < 0 ) {
return POWER_STATUS_ERR;
}
sleep(2);
if ( server_power_12v_on(fru) < 0 ) {
return POWER_STATUS_ERR;
}
}
} else {
if ((bmc_location == NIC_BMC) && (true == pal_is_fw_update_ongoing_system()) ) {
printf("Please make sure no firmware update is ongoing\n");
return POWER_STATUS_ERR;
}
if ( bic_do_12V_cycle(fru) < 0 ) {
return POWER_STATUS_ERR;
}
}
break;
default:
syslog(LOG_WARNING, "%s() wrong cmd: 0x%02X", __func__, cmd);
return POWER_STATUS_ERR;
}
return POWER_STATUS_OK;
}
int
pal_sled_cycle(void) {
int ret = PAL_EOK;
uint8_t bmc_location = 0;
uint8_t hsc_det = 0;
ret = fby3_common_get_bmc_location(&bmc_location);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__);
return POWER_STATUS_ERR;
}
if ( (bmc_location == BB_BMC) || (bmc_location == DVT_BB_BMC) ) {
if ( fby3_common_get_hsc_bb_detect(&hsc_det) ) {
return -1;
}
switch (hsc_det) {
case HSC_DET_ADM1278:
ret = system("i2cset -y 11 0x40 0xd9 c &> /dev/null");
break;
case HSC_DET_LTC4282:
ret = system("i2cset -y -f 11 0x40 0x1d 0x80 b &> /dev/null");
break;
case HSC_DET_MP5990:
ret = system("i2cset -y 11 0x40 0xf c &> /dev/null");
break;
case HSC_DET_ADM1276:
ret = system("i2cset -y 11 0x20 0xd9 c &> /dev/null");
break;
default:
syslog(LOG_WARNING, "%s Invalid HSC detection: %u\n", __func__, hsc_det);
return -1;
}
} else {
// check power lock flag
if ( bic_is_crit_act_ongoing(FRU_SLOT1) == true ) {
printf("power lock flag is asserted, please make sure no firmware update is ongoing\n");
printf("If you still want to proceed, please clean the flag manually!\n");
syslog(LOG_CRIT, "SLED_CYCLE failed because a critical activity is ongoing\n");
return PAL_ENOTSUP;
}
if ( bic_inform_sled_cycle() < 0 ) {
syslog(LOG_WARNING, "Inform another BMC for sled cycle failed.\n");
}
// Provide the time for inform another BMC
sleep(2);
int i = 0;
int retries = 3;
for (i = 0 ; i < retries; i++) {
//BMC always sends the command with slot id 1 on class 2
if ( bic_do_sled_cycle(1) < 0 ) {
printf("Try to do the sled cycle...\n");
msleep(100);
}
}
if ( i == retries ) {
printf("Failed to do the sled cycle. Please check the BIC is alive.\n");
ret = -1;
}
}
return ret;
}
int
pal_set_last_pwr_state(uint8_t fru, char *state) {
int ret;
char key[MAX_KEY_LEN] = {0};
sprintf(key, "pwr_server%d_last_state", (int) fru);
ret = pal_set_key_value(key, state);
if (ret < 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_set_last_pwr_state: pal_set_key_value failed for "
"fru %u", fru);
#endif
}
return ret;
}
int
pal_get_last_pwr_state(uint8_t fru, char *state) {
int ret;
char key[MAX_KEY_LEN] = {0};
if (pal_is_cwc() == PAL_EOK &&
(fru == FRU_CWC || fru == FRU_2U_TOP || fru == FRU_2U_BOT)) {
sprintf(key, "pwr_server%d_last_state", FRU_SLOT1);
} else {
sprintf(key, "pwr_server%d_last_state", (int) fru);
}
ret = pal_get_key_value(key, state);
if (ret < 0) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_get_last_pwr_state: pal_get_key_value failed for "
"fru %u", fru);
#endif
}
return ret;
}
static int
pal_is_valid_expansion_dev(uint8_t slot_id, uint8_t dev_id, uint8_t *rsp) {
const uint8_t st_2ou_idx = DEV_ID0_2OU;
const uint8_t end_2ou_yv3_idx = DEV_ID5_2OU;
const uint8_t end_2ou_gpv3_idx = DEV_ID13_2OU;
int ret = 0;
int config_status = 0;
uint8_t bmc_location = 0;
ret = fby3_common_get_bmc_location(&bmc_location);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__);
return POWER_STATUS_ERR;
}
config_status = bic_is_m2_exp_prsnt(slot_id);
if (config_status < 0) {
return POWER_STATUS_FRU_ERR;
}
// Is 1OU dev?
if ( (dev_id < st_2ou_idx) && ((config_status & PRESENT_1OU) == PRESENT_1OU) ) {
if ( bmc_location == NIC_BMC ) return POWER_STATUS_FRU_ERR;
rsp[0] = dev_id;
rsp[1] = FEXP_BIC_INTF;
} else if (( dev_id >= st_2ou_idx && dev_id <= end_2ou_gpv3_idx) && ((config_status & PRESENT_2OU) == PRESENT_2OU)) {
uint8_t type = 0xff;
if ( fby3_common_get_2ou_board_type(slot_id, &type) < 0 ) {
return POWER_STATUS_FRU_ERR;
} else if ( type != GPV3_MCHP_BOARD && type != GPV3_BRCM_BOARD ) {
//If dev doesn't belong to GPv3, return
if ( dev_id > end_2ou_yv3_idx ) return POWER_STATUS_FRU_ERR;
}
rsp[0] = dev_id - 4;
rsp[1] = REXP_BIC_INTF;
} else if (( dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) && ((config_status & PRESENT_2OU) == PRESENT_2OU)) {
uint8_t type = 0xff;
if ( fby3_common_get_2ou_board_type(slot_id, &type) < 0 ) {
return POWER_STATUS_FRU_ERR;
} else if ( type != GPV3_MCHP_BOARD && type != GPV3_BRCM_BOARD ) {
//If dev doesn't belong to GPv3, return
if ( dev_id > end_2ou_yv3_idx ) return POWER_STATUS_FRU_ERR;
}
rsp[0] = dev_id;
rsp[1] = REXP_BIC_INTF;
} else {
// dev not found
return POWER_STATUS_FRU_ERR;
}
return POWER_STATUS_OK;
}
int
pal_get_exp_device_power(uint8_t exp, uint8_t dev_id, uint8_t *status, uint8_t *type) {
uint8_t sta = 0;
int ret = 0;
uint8_t nvme_ready = 0;
uint8_t intf = 0;
if (pal_get_exp_power(exp, &sta)) {
return POWER_STATUS_ERR;
}
if (sta == SERVER_12V_OFF) {
*status = DEVICE_POWER_OFF;
syslog(LOG_WARNING, "pal_get_exp_device_power: pal_get_exp_power 12V-off");
return 0;
}
switch (exp) {
case FRU_2U_TOP:
if (dev_id >= DEV_ID0_2OU && dev_id <= DEV_ID13_2OU) {
dev_id -= 4;
intf = RREXP_BIC_INTF1;
} else if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
intf = RREXP_BIC_INTF1;
} else {
printf("Device not found \n");
return POWER_STATUS_FRU_ERR;
}
break;
case FRU_2U_BOT:
if (dev_id >= DEV_ID0_2OU && dev_id <= DEV_ID13_2OU) {
dev_id -= 4;
intf = RREXP_BIC_INTF2;
} else if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
intf = RREXP_BIC_INTF2;
} else {
printf("Device not found \n");
return POWER_STATUS_FRU_ERR;
}
break;
default:
return POWER_STATUS_FRU_ERR;
}
ret = bic_get_dev_power_status(FRU_SLOT1, dev_id, &nvme_ready, status, \
NULL, NULL, NULL, NULL, NULL, intf);
if (ret < 0) {
return -1;
}
if (nvme_ready) {
*type = DEV_TYPE_M2;
} else {
*type = DEV_TYPE_UNKNOWN;
}
return 0;
}
int
pal_get_dual_power(uint8_t slot_id, uint8_t dev_id, uint8_t *status, uint8_t *type) {
uint8_t dev0 = DEV_ID0_2OU + (dev_id - DUAL_DEV_ID0_2OU) * 2;
uint8_t dev1 = DEV_ID0_2OU + (dev_id - DUAL_DEV_ID0_2OU) * 2 + 1;
if (pal_get_device_power(slot_id, dev0, &status[0], type) < 0) {
return -1;
}
if (pal_get_device_power(slot_id, dev1, &status[1], type) < 0) {
return -1;
}
return 0;
}
int
pal_get_device_power(uint8_t slot_id, uint8_t dev_id, uint8_t *status, uint8_t *type) {
int ret = 0;
uint8_t nvme_ready = 0;
uint8_t intf = 0;
uint8_t rsp[2] = {0}; //idx0 = dev id, idx1 = intf
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
uint8_t dual_sta[2] = {0};
if (pal_get_dual_power(slot_id, dev_id, dual_sta, type)) {
return POWER_STATUS_ERR;
}
if (dual_sta[0] == DEVICE_POWER_ON && dual_sta[1] == DEVICE_POWER_ON) {
*status = DEVICE_POWER_ON;
} else {
*status = DEVICE_POWER_OFF;
}
return 0;
}
if (pal_is_cwc() == PAL_EOK && (slot_id == FRU_2U_TOP || slot_id == FRU_2U_BOT)) {
return pal_get_exp_device_power(slot_id, dev_id, status, type);
}
if (fby3_common_check_slot_id(slot_id) == 0) {
/* Check whether the system is 12V off or on */
if ( pal_get_server_12v_power(slot_id, status) < 0 ) {
return POWER_STATUS_ERR;
}
/* If 12V-off, return */
if ((*status) == SERVER_12V_OFF) {
*status = DEVICE_POWER_OFF;
syslog(LOG_WARNING, "pal_get_device_power: pal_is_server_12v_on 12V-off");
return 0;
}
if ( pal_is_valid_expansion_dev(slot_id, dev_id, rsp) < 0 ) {
printf("Device not found \n");
return POWER_STATUS_FRU_ERR;
}
dev_id = rsp[0];
intf = rsp[1];
ret = bic_get_dev_power_status(slot_id, dev_id, &nvme_ready, status, \
NULL, NULL, NULL, NULL, NULL, intf);
if (ret < 0) {
return -1;
}
if (nvme_ready) {
*type = DEV_TYPE_M2;
} else {
*type = DEV_TYPE_UNKNOWN;
}
return 0;
}
*type = DEV_TYPE_UNKNOWN;
return -1;
}
int
pal_set_exp_device_power(uint8_t exp, uint8_t dev_id, uint8_t cmd) {
uint8_t sta[2] = {0}, type = 0;
int ret = 0;
uint8_t intf = 0;
if (pal_get_exp_power(exp, sta)) {
return POWER_STATUS_ERR;
}
if (sta[0] == SERVER_12V_OFF) {
printf("Fru:%d is off \n", exp);
return 0;
}
if (pal_get_exp_device_power(exp, dev_id, sta, &type)) {
return POWER_STATUS_ERR;
}
switch (exp) {
case FRU_2U_TOP:
if (dev_id >= DEV_ID0_2OU && dev_id <= DEV_ID13_2OU) {
dev_id -= 4;
intf = RREXP_BIC_INTF1;
} else if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
intf = RREXP_BIC_INTF1;
} else {
printf("Device not found \n");
return POWER_STATUS_FRU_ERR;
}
break;
case FRU_2U_BOT:
if (dev_id >= DEV_ID0_2OU && dev_id <= DEV_ID13_2OU) {
dev_id -= 4;
intf = RREXP_BIC_INTF2;
} else if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
intf = RREXP_BIC_INTF2;
} else {
printf("Device not found \n");
return POWER_STATUS_FRU_ERR;
}
break;
default:
return POWER_STATUS_FRU_ERR;
}
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
if (cmd == SERVER_POWER_ON) {
if (sta[0] == DEVICE_POWER_ON && sta[1] == DEVICE_POWER_ON) {
sta[0] = DEVICE_POWER_ON;
} else {
sta[0] = DEVICE_POWER_OFF;
}
} else { //off or cycle
if (sta[0] == DEVICE_POWER_OFF && sta[1] == DEVICE_POWER_OFF) {
sta[0] = DEVICE_POWER_OFF;
} else {
sta[0] = DEVICE_POWER_ON;
}
}
}
switch(cmd) {
case SERVER_POWER_ON:
if (sta[0] == DEVICE_POWER_ON) {
return 1;
} else {
ret = bic_set_dev_power_status(FRU_SLOT1, dev_id, DEVICE_POWER_ON, intf);
return ret;
}
break;
case SERVER_POWER_OFF:
if (sta[0] == DEVICE_POWER_OFF) {
return 1;
} else {
ret = bic_set_dev_power_status(FRU_SLOT1, dev_id, DEVICE_POWER_OFF, intf);
return ret;
}
break;
case SERVER_POWER_CYCLE:
if (sta[0] == DEVICE_POWER_ON) {
ret = bic_set_dev_power_status(FRU_SLOT1, dev_id, DEVICE_POWER_OFF, intf);
if (ret < 0) {
return -1;
}
sleep(3);
ret = bic_set_dev_power_status(FRU_SLOT1, dev_id, DEVICE_POWER_ON, intf);
return ret;
} else if (sta[0] == DEVICE_POWER_OFF) {
ret = bic_set_dev_power_status(FRU_SLOT1, dev_id, DEVICE_POWER_ON, intf);
return ret;
}
break;
default:
return POWER_STATUS_ERR;
}
return 0;
}
int
pal_set_device_power(uint8_t slot_id, uint8_t dev_id, uint8_t cmd) {
int ret;
uint8_t status, type, type_1ou = 0;
uint8_t intf = 0;
uint8_t rsp[2] = {0}; //idx0 = dev id, idx1 = intf
uint8_t dual_sta[2] = {0};
if (pal_is_cwc() == PAL_EOK && (slot_id == FRU_2U_TOP || slot_id == FRU_2U_BOT)) {
return pal_set_exp_device_power(slot_id, dev_id, cmd);
}
ret = fby3_common_check_slot_id(slot_id);
if ( ret < 0 ) {
return POWER_STATUS_FRU_ERR;
}
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
if (pal_get_dual_power(slot_id, dev_id, dual_sta, &type) < 0) {
return -1;
}
} else {
if (pal_get_device_power(slot_id, dev_id, &status, &type) < 0) {
return -1;
}
}
if ( pal_is_valid_expansion_dev(slot_id, dev_id, rsp) < 0 ) {
printf("Device not found \n");
return POWER_STATUS_FRU_ERR;
}
dev_id = rsp[0];
intf = rsp[1];
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
if (cmd == SERVER_POWER_ON) {
if (dual_sta[0] == DEVICE_POWER_ON && dual_sta[1] == DEVICE_POWER_ON) {
status = DEVICE_POWER_ON;
} else {
status = DEVICE_POWER_OFF;
}
} else { //off or cycle
if (dual_sta[0] == DEVICE_POWER_OFF && dual_sta[1] == DEVICE_POWER_OFF) {
status = DEVICE_POWER_OFF;
} else {
status = DEVICE_POWER_ON;
}
}
}
switch(cmd) {
case SERVER_POWER_ON:
if (status == DEVICE_POWER_ON) {
return 1;
} else {
ret = bic_set_dev_power_status(slot_id, dev_id, DEVICE_POWER_ON, intf);
return ret;
}
break;
case SERVER_POWER_OFF:
if (status == DEVICE_POWER_OFF) {
return 1;
} else {
ret = bic_set_dev_power_status(slot_id, dev_id, DEVICE_POWER_OFF, intf);
return ret;
}
break;
case SERVER_POWER_CYCLE:
if (status == DEVICE_POWER_ON) {
ret = bic_set_dev_power_status(slot_id, dev_id, DEVICE_POWER_OFF, intf);
if (ret < 0) {
return -1;
}
if (intf == FEXP_BIC_INTF) {
bic_get_1ou_type_cache(slot_id, &type_1ou);
}
if (type_1ou == EDSFF_1U) {
sleep(6); // EDSFF timing requirement
} else {
sleep(3);
}
ret = bic_set_dev_power_status(slot_id, dev_id, DEVICE_POWER_ON, intf);
return ret;
} else if (status == DEVICE_POWER_OFF) {
ret = bic_set_dev_power_status(slot_id, dev_id, DEVICE_POWER_ON, intf);
return ret;
}
break;
default:
return -1;
}
return 0;
}
void
pal_get_chassis_status(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) {
char key[MAX_KEY_LEN];
char buff[MAX_VALUE_LEN] = {0};
int policy = 3;
int ret = 0;
uint8_t status = 0;
uint8_t uart_select = 0x00;
unsigned char *data = res_data;
if(slot == 5) { //handle the case, command sent from debug Card
ret = pal_get_uart_select_from_kv(&uart_select);
if (ret < 0) {
syslog(LOG_WARNING, "%s() Failed to get debug_card_uart_select\n", __func__);
}
// if uart_select is BMC, the following code will return default data.
slot = uart_select;
}
sprintf(key, "slot%u_por_cfg", slot);
if (pal_get_key_value(key, buff) == 0) {
if (!memcmp(buff, "off", strlen("off")))
policy = 0;
else if (!memcmp(buff, "lps", strlen("lps")))
policy = 1;
else if (!memcmp(buff, "on", strlen("on")))
policy = 2;
else
policy = 3;
}
// Current Power State
ret = pal_get_server_power(slot, &status);
if (ret >= 0) {
*data++ = status | (policy << 5);
} else {
syslog(LOG_WARNING, "pal_get_chassis_status: pal_get_server_power failed for slot%u", slot);
*data++ = 0x00 | (policy << 5);
}
*data++ = 0x00; // Last Power Event
*data++ = 0x40; // Misc. Chassis Status
*data++ = 0x00; // Front Panel Button Disable
*res_len = data - res_data;
}
uint8_t
pal_set_power_restore_policy(uint8_t slot, uint8_t *pwr_policy, uint8_t *res_data) {
uint8_t comp_code = CC_SUCCESS;
uint8_t policy = *pwr_policy & 0x07; // Power restore policy
char key[MAX_KEY_LEN];
sprintf(key, "slot%u_por_cfg", slot);
switch (policy) {
case 0:
if (pal_set_key_value(key, "off")) {
comp_code = CC_UNSPECIFIED_ERROR;
}
break;
case 1:
if (pal_set_key_value(key, "lps")) {
comp_code = CC_UNSPECIFIED_ERROR;
}
break;
case 2:
if (pal_set_key_value(key, "on")) {
comp_code = CC_UNSPECIFIED_ERROR;
}
break;
case 3:
// no change (just get present policy support)
break;
default:
comp_code = CC_PARAM_OUT_OF_RANGE;
break;
}
return comp_code;
}
// Do slot power control
static void * slot_pwr_ctrl(void *ptr) {
uint8_t slot = (int)ptr & 0xFF;
uint8_t cmd = ((int)ptr >> 8) & 0xFF;
char pwr_state[MAX_VALUE_LEN] = {0};
pthread_detach(pthread_self());
msleep(500);
if (cmd == SERVER_12V_CYCLE) {
pal_get_last_pwr_state(slot, pwr_state);
}
if (!pal_set_server_power(slot, cmd)) {
switch (cmd) {
case SERVER_POWER_OFF:
syslog(LOG_CRIT, "SERVER_POWER_OFF successful for FRU: %d", slot);
break;
case SERVER_POWER_ON:
syslog(LOG_CRIT, "SERVER_POWER_ON successful for FRU: %d", slot);
break;
case SERVER_POWER_CYCLE:
syslog(LOG_CRIT, "SERVER_POWER_CYCLE successful for FRU: %d", slot);
break;
case SERVER_POWER_RESET:
syslog(LOG_CRIT, "SERVER_POWER_RESET successful for FRU: %d", slot);
break;
case SERVER_GRACEFUL_SHUTDOWN:
syslog(LOG_CRIT, "SERVER_GRACEFUL_SHUTDOWN successful for FRU: %d", slot);
break;
case SERVER_12V_CYCLE:
syslog(LOG_CRIT, "SERVER_12V_CYCLE successful for FRU: %d", slot);
pal_power_policy_control(slot, pwr_state);
break;
}
}
m_slot_pwr_ctrl[slot] = false;
pthread_exit(0);
}
int
pal_chassis_control(uint8_t slot, uint8_t *req_data, uint8_t req_len) {
uint8_t comp_code = CC_SUCCESS, cmd = 0xFF;
int ret, cmd_slot;
pthread_t tid;
if ((slot < FRU_SLOT1) || (slot > FRU_SLOT4)) {
return CC_UNSPECIFIED_ERROR;
}
if (req_len != 1) {
return CC_INVALID_LENGTH;
}
if (m_slot_pwr_ctrl[slot] != false) {
return CC_NOT_SUPP_IN_CURR_STATE;
}
switch (req_data[0]) {
case 0x00: // power off
cmd = SERVER_POWER_OFF;
break;
case 0x01: // power on
cmd = SERVER_POWER_ON;
break;
case 0x02: // power cycle
cmd = SERVER_POWER_CYCLE;
break;
case 0x03: // power reset
cmd = SERVER_POWER_RESET;
break;
case 0x05: // graceful-shutdown
cmd = SERVER_GRACEFUL_SHUTDOWN;
break;
default:
comp_code = CC_INVALID_DATA_FIELD;
break;
}
if (comp_code == CC_SUCCESS) {
m_slot_pwr_ctrl[slot] = true;
cmd_slot = (cmd << 8) | slot;
ret = pthread_create(&tid, NULL, slot_pwr_ctrl, (void *)cmd_slot);
if (ret < 0) {
syslog(LOG_WARNING, "[%s] Create slot_pwr_ctrl thread failed!", __func__);
m_slot_pwr_ctrl[slot] = false;
return CC_NODE_BUSY;
}
}
return comp_code;
}
static int
pal_slot_ac_cycle(uint8_t slot) {
int ret, cmd_slot;
pthread_t tid;
if (m_slot_pwr_ctrl[slot] != false) {
return CC_NOT_SUPP_IN_CURR_STATE;
}
m_slot_pwr_ctrl[slot] = true;
cmd_slot = (SERVER_12V_CYCLE << 8) | slot;
ret = pthread_create(&tid, NULL, slot_pwr_ctrl, (void *)cmd_slot);
if (ret < 0) {
syslog(LOG_WARNING, "[%s] Create slot_ac_cycle thread failed!", __func__);
m_slot_pwr_ctrl[slot] = false;
return CC_NODE_BUSY;
}
return CC_SUCCESS;
}
int
pal_sled_ac_cycle(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len) {
uint8_t comp_code = CC_UNSPECIFIED_ERROR;
uint8_t *data = req_data;
if ( fby3_common_check_slot_id(slot) < 0 ) {
return comp_code;
}
if ((*data != 0x55) || (*(data+1) != 0x66)) {
return comp_code;
}
switch (*(data+2)) {
case 0x0f: //do slot ac cycle
comp_code = pal_slot_ac_cycle(slot);
break;
default:
comp_code = CC_INVALID_DATA_FIELD;
break;
}
return comp_code;
}
int
pal_get_exp_power(uint8_t fru, uint8_t *status) {
int i2cfd = BIC_STATUS_FAILURE;
int ret = BIC_STATUS_FAILURE;
int bus = 0;
uint8_t tbuf = 0x0;
uint8_t rbuf = 0x0;
uint8_t tlen = 0x0;
uint8_t rlen = 0x0;
uint8_t retry = MAX_READ_RETRY;
uint8_t mask = 0;
switch (fru) {
case FRU_CWC:
bus = FRU_SLOT1 + SLOT_BUS_BASE;
mask = 0x01;
break;
case FRU_2U_TOP:
bus = FRU_SLOT1 + SLOT_BUS_BASE;
mask = 0x02;
break;
case FRU_2U_BOT:
bus = FRU_SLOT1 + SLOT_BUS_BASE;
mask = 0x04;
break;
default:
printf("unknown expantion fru : %d\n", fru);
return POWER_STATUS_FRU_ERR;
}
i2cfd = i2c_cdev_slave_open(bus, CWC_CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open i2c device %d", __func__, CWC_CPLD_ADDRESS);
return i2cfd;
}
tbuf = REG_CWC_CPLD_CARD_PWROK;
tlen = 1;
rlen = 1;
do {
ret = i2c_rdwr_msg_transfer(i2cfd, CWC_CPLD_ADDRESS, &tbuf, tlen, &rbuf, rlen);
if ( ret < 0 ) {
msleep(100);
} else {
break;
}
} while( retry-- > 0 );
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
} else {
if ( rbuf & mask ) {
*status = SERVER_12V_ON;
} else {
*status = SERVER_12V_OFF;
}
}
if ( i2cfd > 0 ) {
close(i2cfd);
}
return ret;
}
int
pal_get_gpv3_hsc(int bus, uint8_t *val) {
int i2cfd = BIC_STATUS_FAILURE;
int ret = BIC_STATUS_FAILURE;
uint8_t tbuf = 0x0;
uint8_t rbuf = 0x0;
uint8_t tlen = 0x0;
uint8_t rlen = 0x0;
uint8_t retry = MAX_READ_RETRY;
i2cfd = i2c_cdev_slave_open(bus, CWC_CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM);
if ( i2cfd < 0 ) {
syslog(LOG_WARNING, "%s() Failed to open i2c device %d", __func__, CWC_CPLD_ADDRESS);
return i2cfd;
}
tbuf = REG_CWC_CPLD_GPV3_HSC;
tlen = 1;
rlen = 1;
do {
ret = i2c_rdwr_msg_transfer(i2cfd, CWC_CPLD_ADDRESS, &tbuf, tlen, &rbuf, rlen);
if ( ret < 0 ) {
msleep(100);
} else {
break;
}
} while( retry-- > 0 );
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
} else {
*val = rbuf;
}
if ( i2cfd > 0 ) {
close(i2cfd);
}
return ret;
}
int
pal_set_vr_interrupt(uint8_t fru, uint8_t enable) {
switch (fru) {
case FRU_CWC:
if (bic_enable_vr_fault_monitor(FRU_SLOT1, enable ? true : false, REXP_BIC_INTF)) {
syslog(LOG_WARNING, "%s() Failed to disable 2U-cwc vr interrupt", __func__);
}
if (bic_enable_vr_fault_monitor(FRU_SLOT1, enable ? true : false, RREXP_BIC_INTF1)) {
syslog(LOG_WARNING, "%s() Failed to disable 2U-top vr interrupt", __func__);
}
if (bic_enable_vr_fault_monitor(FRU_SLOT1, enable ? true : false, RREXP_BIC_INTF2)) {
syslog(LOG_WARNING, "%s() Failed to disable 2U-bot vr interrupt", __func__);
}
break;
case FRU_2U_TOP:
if (bic_enable_vr_fault_monitor(FRU_SLOT1, enable ? true : false, RREXP_BIC_INTF1)) {
syslog(LOG_WARNING, "%s() Failed to disable 2U-top vr interrupt", __func__);
}
break;
case FRU_2U_BOT:
if (bic_enable_vr_fault_monitor(FRU_SLOT1, enable ? true : false, RREXP_BIC_INTF2)) {
syslog(LOG_WARNING, "%s() Failed to disable 2U-bot vr interrupt", __func__);
}
break;
}
return 0;
}
int
pal_wait_exp_pwr(uint8_t fru, uint8_t pwr_status) {
int res = MAX_EXP_POWER_DELAY;
uint8_t status = 0;
while (res > 0) {
sleep(DELAY_EXP_POWER);
res -= DELAY_EXP_POWER;
if (pal_get_exp_power(fru, &status) < 0) {
continue;
}
if (status == pwr_status) {
return 0;
}
}
return POWER_STATUS_ERR;
}
int
pal_set_exp_12v_on(uint8_t fru, bool pwr_on) {
int i2cfd = BIC_STATUS_FAILURE;
int ret = BIC_STATUS_FAILURE;
int ina_alert_ret = BIC_STATUS_SUCCESS;
int bus = 0;
uint8_t tbuf[2] = {0x0};
uint8_t rbuf = 0x0;
uint8_t tlen = 0x02;
uint8_t rlen = 0x0;
uint8_t retry = MAX_READ_RETRY;
uint8_t gpv3_hsc = 0;
if (!pwr_on) {
if (bic_enable_ina233_alert(fru, false)) {
syslog(LOG_WARNING, "%s() Failed to disable INA233 Alert", __func__);
}
}
switch (fru) {
case FRU_CWC:
bus = FRU_SLOT1 + SLOT_BUS_BASE;
tbuf[0] = REG_CWC_CPLD_CWC_HSC;
tbuf[1] = pwr_on ? 0x1 : 0x0;
break;
case FRU_2U_TOP:
bus = FRU_SLOT1 + SLOT_BUS_BASE;
tbuf[0] = REG_CWC_CPLD_GPV3_HSC;
ina_alert_ret = pal_get_gpv3_hsc(bus, &gpv3_hsc);
if ( ina_alert_ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to get gpv3 hsc", __func__);
goto error_exit;
}
tbuf[1] = pwr_on ? (gpv3_hsc | 0x01) : (gpv3_hsc & ~0x01);
break;
case FRU_2U_BOT:
bus = FRU_SLOT1 + SLOT_BUS_BASE;
tbuf[0] = REG_CWC_CPLD_GPV3_HSC;
ina_alert_ret = pal_get_gpv3_hsc(bus, &gpv3_hsc);
if ( ina_alert_ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to get gpv3 hsc", __func__);
goto error_exit;
}
tbuf[1] = pwr_on ? (gpv3_hsc | 0x02) : (gpv3_hsc & ~0x02);
break;
default:
printf("unknown expantion fru : %d\n", fru);
ina_alert_ret = POWER_STATUS_FRU_ERR;
goto error_exit;
}
if (!pwr_on) {
pal_set_vr_interrupt(fru, 0);
}
i2cfd = i2c_cdev_slave_open(bus, CWC_CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM);
if ( i2cfd < 0 ) {
ina_alert_ret = i2cfd;
syslog(LOG_WARNING, "%s() Failed to open i2c device %d", __func__, CWC_CPLD_ADDRESS);
goto error_exit;
}
do {
ret = i2c_rdwr_msg_transfer(i2cfd, CWC_CPLD_ADDRESS, tbuf, tlen, &rbuf, rlen);
if ( ret < 0 ) {
msleep(100);
} else {
break;
}
} while( retry-- > 0 );
if ( ret < 0 ) {
ina_alert_ret = ret;
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
if (!pwr_on) {
pal_set_vr_interrupt(fru, 1);
}
} else if (pwr_on) {
msleep(100);
pal_set_vr_interrupt(fru, 1);
}
if ( i2cfd > 0 ) {
close(i2cfd);
}
error_exit:
if ( !pwr_on && ina_alert_ret < 0 ) {
if (bic_enable_ina233_alert(fru, true)) {
syslog(LOG_WARNING, "%s() Failed to disable INA233 Alert", __func__);
}
}
return ina_alert_ret;
}
int
pal_set_exp_12v_check(uint8_t fru, bool pwr_on) {
uint8_t retry = MAX_PWR_RETRY;
for (; retry > 0; --retry) {
if (pal_set_exp_12v_on(fru, pwr_on)) {
syslog(LOG_WARNING, "%s() Failed to power %s fru : %d", __func__, pwr_on ? "on" : "off", fru);
return POWER_STATUS_ERR;
}
if (pal_wait_exp_pwr(fru, pwr_on ? SERVER_12V_ON : SERVER_12V_OFF) == 0) {
break;
}
}
return retry == 0 ? POWER_STATUS_ERR : 0;
}
int
pal_set_exp_12v_cycle(uint8_t fru) {
if (pal_set_exp_12v_check(fru, false)) {
return POWER_STATUS_ERR;
}
return pal_set_exp_12v_check(fru, true);
}
int
pal_set_exp_power(uint8_t fru, uint8_t cmd) {
uint8_t status = 0, root = 0;
if (pal_get_root_fru(fru, &root) != PAL_EOK) {
return POWER_STATUS_ERR;
}
if (pal_is_fw_update_ongoing(root)) {
printf("fw update is on going on fru:%d...\n", root);
return POWER_STATUS_ERR;
}
if (pal_get_exp_power(fru, &status) < 0) {
return POWER_STATUS_ERR;
}
switch (cmd) {
case SERVER_12V_OFF:
if (status == SERVER_12V_ON) {
if (pal_set_exp_12v_check(fru, false)) {
return POWER_STATUS_ERR;
}
} else {
return 1;
}
break;
case SERVER_12V_ON:
if (status == SERVER_12V_OFF) {
if (pal_set_exp_12v_check(fru, true)) {
return POWER_STATUS_ERR;
}
} else {
return 1;
}
break;
case SERVER_12V_CYCLE:
if (status == SERVER_12V_ON) {
if (pal_set_exp_12v_cycle(fru)) {
return POWER_STATUS_ERR;
}
} else {
if (pal_set_exp_12v_check(fru, true)) {
return POWER_STATUS_ERR;
}
}
break;
default:
printf("command not supported for fru:%d\n", fru);
return POWER_STATUS_ERR;
}
return 0;
}