meta-facebook/meta-fby35/recipes-fby35/plat-libs/files/pal/pal_power.c (845 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 <openbmc/misc-utils.h> #include "pal.h" #define CPLD_PWR_CTRL_BUS 12 #define CPLD_PWR_CTRL_ADDR 0x1F #define CPLD_PWR_OFF_BIC_REG 0x1E 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 = fby35_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 == NIC_BMC ) { if ( pal_set_nic_perst(fru, NIC_PE_RST_LOW) < 0 ) 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 = fby35_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 == NIC_BMC ) { if ( pal_set_nic_perst(fru, NIC_PE_RST_HIGH) < 0 ) 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 ret = 0; int i2cfd = 0; uint8_t tbuf[4] = {0}; uint8_t rbuf[4] = {0}; char cmd[64] = {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); return -1; } do { tbuf[0] = 0x09 + (fru-1); // toggle HSC_EN when the HSC output was turned OFF // ex: when HSC_FAULT#, status == SERVER_12V_OFF, but HSC_EN == AC_ON ret = retry_cond(!i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, 1, rbuf, 1), MAX_READ_RETRY, 100); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to read HSC_EN", __func__); break; } if ( rbuf[0] == AC_ON ) { tbuf[1] = AC_OFF; ret = retry_cond(!i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, 2, NULL, 0), MAX_READ_RETRY, 100); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to write HSC_EN %u", __func__, tbuf[1]); break; } sleep(1); } tbuf[1] = AC_ON; ret = retry_cond(!i2c_rdwr_msg_transfer(i2cfd, CPLD_PWR_CTRL_ADDR, tbuf, 2, NULL, 0), MAX_READ_RETRY, 100); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Failed to write HSC_EN %u", __func__, tbuf[1]); break; } } while (0); close(i2cfd); if ( ret < 0 ) { return -1; } sleep(1); ret = fby35_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); return ret; } sleep(1); // 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; return ret; } pal_power_policy_control(fru, NULL); 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); } memset(cmd, 0, 64); snprintf(cmd, 64, FRU_ID_CPLD_NEW_VER_KEY, fru); kv_del(cmd, 0); ret = fby35_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 = fby35_common_server_stby_pwr_sts(slot_id, status); if ( ret < 0 ) { syslog(LOG_WARNING, "%s: Failed to run fby35_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; } static int set_nic_pwr_en_time(void) { char value[MAX_VALUE_LEN]; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); snprintf(value, sizeof(value), "%ld", ts.tv_sec + 10); if (kv_set("nic_pwr", value, 0, 0) < 0) { return -1; } return 0; } static int check_nic_pwr_en_time(void) { char value[MAX_VALUE_LEN] = {0}; struct timespec ts; if (kv_get("nic_pwr", value, NULL, 0)) { return 0; } clock_gettime(CLOCK_MONOTONIC, &ts); if (ts.tv_sec >= strtoul(value, NULL, 10)) { return 0; } return -1; } int pal_server_set_nic_power(const uint8_t expected_pwr) { int ret = -1; int lockfd = -1, ifd = -1; uint8_t tbuf[4] = {0x0f, (expected_pwr&0x1),}; uint8_t rbuf[4] = {0}; do { if ( SERVER_POWER_ON == expected_pwr ) { lockfd = single_instance_lock_blocked("nic_pwr"); } else { // SERVER_POWER_OFF if ( (lockfd = single_instance_lock("nic_pwr")) < 0 ) { break; // break since there is SERVER_POWER_ON processing } } ifd = i2c_cdev_slave_open(CPLD_PWR_CTRL_BUS, CPLD_PWR_CTRL_ADDR >> 1, I2C_SLAVE_FORCE_CLAIM); if ( ifd < 0 ) { syslog(LOG_WARNING, "Failed to open bus %d", CPLD_PWR_CTRL_BUS); break; } if ( SERVER_POWER_ON == expected_pwr ) { set_nic_pwr_en_time(); ret = retry_cond(!i2c_rdwr_msg_transfer(ifd, CPLD_PWR_CTRL_ADDR, tbuf, 1, rbuf, 1), 2, 100); if ( !ret && (rbuf[0] & 0x1) ) { // nic power is already ON break; } } else if ( check_nic_pwr_en_time() != 0 ) { // SERVER_POWER_OFF break; // break since there is SERVER_POWER_ON processing } ret = retry_cond(!i2c_rdwr_msg_transfer(ifd, CPLD_PWR_CTRL_ADDR, tbuf, 2, NULL, 0), 2, 100); if ( lockfd >= 0 ) { single_instance_unlock(lockfd); lockfd = -1; } if ( ret < 0 ) { syslog(LOG_WARNING, "Failed to change NIC Power mode"); break; } if ( SERVER_POWER_ON == expected_pwr ) { sleep(2); // wait 2s for PERST# when waking up } } while (0); if ( ifd >= 0 ) { close(ifd); } if ( lockfd >= 0 ) { single_instance_unlock(lockfd); } return (!ret)?PAL_EOK:PAL_ENOTSUP; } int pal_get_server_power(uint8_t fru, uint8_t *status) { int ret; ret = fby35_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; } int pal_set_bic_power_off(int fru) { int i2cfd = 0, bus = 0, tlen = 0, rlen = 0, retry = 0, ret = 0; uint8_t tbuf[2] = {0}; bus = fby35_common_get_bus_id(fru) + 4; i2cfd = i2c_cdev_slave_open(bus, CPLD_ADDRESS >> 1, I2C_SLAVE_FORCE_CLAIM); if (i2cfd < 0) { printf("Failed to open CPLD 0x%x\n", CPLD_ADDRESS); return -1; } tbuf[0] = CPLD_PWR_OFF_BIC_REG; tbuf[1] = 0; // power off tlen = 2; rlen = 0; retry = 0; while (retry < RETRY_TIME) { ret = i2c_rdwr_msg_transfer(i2cfd, CPLD_ADDRESS, tbuf, tlen, NULL, rlen); if ( ret < 0 ) { retry++; msleep(100); } else { break; } } if (retry == RETRY_TIME) { syslog(LOG_CRIT, "%s(): Failed to do i2c_rdwr_msg_transfer\n", __func__); ret = -1; } 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; ret = fby35_common_check_slot_id(fru); if ( ret < 0 ) { return POWER_STATUS_FRU_ERR; } ret = fby35_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_CYCLE: case SERVER_12V_ON: //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 } else ret = PAL_EOK; return (ret == PAL_ENOTSUP)?POWER_STATUS_ERR: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; } return (status == SERVER_12V_ON)?POWER_STATUS_ALREADY_OK: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; pal_set_bic_power_off(fru); return server_power_12v_off(fru); break; case SERVER_12V_CYCLE: if ( bmc_location == 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 { pal_set_bic_power_off(fru); if ( server_power_12v_off(fru) < 0 ) { return POWER_STATUS_ERR; } sleep(DELAY_12V_CYCLE); if ( server_power_12v_on(fru) < 0 ) { return POWER_STATUS_ERR; } } } else { if ( pal_set_nic_perst(fru, NIC_PE_RST_LOW) < 0 ) 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; int i = 0; uint8_t bmc_location = 0, is_fru_present = 0, status = 0; uint8_t tbuf[2] = {0}; int tlen = 0, retry = 0, i2cfd = 0; ret = fby35_common_get_bmc_location(&bmc_location); if ( ret < 0 ) { syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__); return POWER_STATUS_ERR; } ret = system("sv stop sensord > /dev/null 2>&1 &"); if ( ret < 0 ) { printf("Fail to stop sensord\n"); } if ( bmc_location == BB_BMC ) { for (i = 1; i <= 4; i++) { ret = pal_is_fru_prsnt(i, &is_fru_present); if (ret < 0 || is_fru_present == 0) { continue; } ret = pal_get_server_12v_power(i, &status); if (ret < 0 || status == SERVER_12V_OFF) { continue; } pal_set_bic_power_off(i); } 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, error: %s", __func__, CPLD_PWR_CTRL_BUS, strerror(errno)); return -1; } tbuf[0] = 0x2B; tbuf[1] = 0x01; 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 sled cycle, max retry: %d", __func__, retry); } } else { if ( pal_set_nic_perst(1, NIC_PE_RST_LOW) < 0 ) { syslog(LOG_CRIT, "Set NIC PERST failed.\n"); } 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 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; } } ret = system("sv start sensord > /dev/null 2>&1 &"); if ( ret < 0 ) { printf("Fail to start sensord\n"); } 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}; 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 = fby35_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 ( fby35_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 { // dev not found return POWER_STATUS_FRU_ERR; } return POWER_STATUS_OK; } 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 (fby35_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_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 ret = fby35_common_check_slot_id(slot_id); if ( ret < 0 ) { return POWER_STATUS_FRU_ERR; } 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]; 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; uint8_t *data = res_data; if (slot == FRU_BB) { // 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; } if (slot == FRU_ALL) { *data++ = 0x00 | (policy << 5); } else { 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 ( fby35_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; }