meta-facebook/meta-fbsp/recipes-fbsp/plat-libs/files/pal/pal.c (1,437 lines of code) (raw):
/*
*
* Copyright 2015-present Facebook. All Rights Reserved.
*
* This file contains code to support IPMI2.0 Specification available @
* http://www.intel.com/content/www/us/en/servers/ipmi/ipmi-specifications.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <openbmc/kv.h>
#include <openbmc/libgpio.h>
#include <openbmc/nm.h>
#include <openbmc/ncsi.h>
#include <openbmc/nl-wrapper.h>
#include <openbmc/obmc-i2c.h>
#include "pal.h"
#define PLATFORM_NAME "sonorapass"
#define LAST_KEY "last_key"
#define REV_ID_FILE "/tmp/mb_rev"
#define SKU_ID_FILE "/tmp/mb_sku"
#define GPIO_LOCATE_LED "FP_LOCATE_LED"
#define GPIO_FAULT_LED "FP_FAULT_LED_N"
#define GPIO_NIC0_PRSNT "HP_LVC3_OCP_V3_1_PRSNT2_N"
#define GPIO_NIC1_PRSNT "HP_LVC3_OCP_V3_2_PRSNT2_N"
#define OFFSET_SYS_GUID 0x17F0
#define OFFSET_DEV_GUID 0x1800
const char pal_fru_list[] = "all, mb, nic0, nic1, riser1, riser2, fcb, bmc";
const char pal_server_list[] = "mb";
const char pal_fru_list_print[] = "all, mb, nic0, nic1, riser1, riser2, bmc"; // Cannot read fruid from "fcb"
const char pal_fru_list_rw[] = "mb, nic0, nic1, riser1, riser2, bmc"; // Cannot write fruid to "fcb"
const char pal_fru_list_sensor_history[] = "all, mb, nic0, nic1, riser1, riser2, fcb, bmc";
static int key_func_por_policy (int event, void *arg);
static int key_func_lps (int event, void *arg);
static bool is_cpu_socket_occupy(unsigned int cpu_id);
static char *dimm_label[24] = {
"A0", "C0", "A1", "C1", "A2", "C2", "A3", "C3", "A4", "C4", "A5", "C5",
"B0", "D0", "B1", "D1", "B2", "D2", "B3", "D3", "B4", "D4", "B5", "D5"};
struct dimm_map {
unsigned char index;
char *label;
};
enum key_event {
KEY_BEFORE_SET,
KEY_AFTER_INI,
};
struct pal_key_cfg {
char *name;
char *def_val;
int (*function)(int, void*);
} key_cfg[] = {
/* name, default value, function */
{"pwr_server_last_state", "on", key_func_lps},
{"sysfw_ver_server", "0", NULL},
{"identify_sled", "off", NULL},
{"timestamp_sled", "0", NULL},
{"server_por_cfg", "lps", key_func_por_policy},
{"server_sensor_health", "1", NULL},
{"nic0_sensor_health", "1", NULL},
{"nic1_sensor_health", "1", NULL},
{"server_sel_error", "1", NULL},
{"server_boot_order", "0100090203ff", NULL},
{"ntp_server", "", NULL},
/* Add more Keys here */
{LAST_KEY, LAST_KEY, NULL} /* This is the last key of the list */
};
struct fsc_monitor
{
uint8_t sensor_num;
char *sensor_name;
bool (*check_sensor_sts)(uint8_t);
bool is_alive;
uint8_t init_count;
uint8_t retry;
};
static struct fsc_monitor fsc_monitor_basic_snr_list[] =
{
{MB_SNR_INLET_REMOTE_TEMP , "mb_inlet_remote_temp" , NULL, false, 5, 5},
{MB_SNR_CPU0_THERM_MARGIN , "mb_cpu0_therm_margin" , NULL, false, 5, 5},
{MB_SNR_CPU1_THERM_MARGIN , "mb_cpu1_therm_margin" , NULL, false, 5, 5},
{RISER2_SNR_SLOT0_NVME_TEMP , "riser2_slot0_nvme_temp" , NULL, false, 5, 5},
{RISER2_SNR_SLOT1_NVME_TEMP , "riser2_slot1_nvme_temp" , NULL, false, 5, 5},
{RISER2_SNR_SLOT2_NVME_TEMP , "riser2_slot2_nvme_temp" , NULL, false, 5, 5},
{RISER2_SNR_SLOT3_NVME_TEMP , "riser2_slot3_nvme_temp" , NULL, false, 5, 5},
{NIC_MEZZ0_SNR_TEMP , "nic0_mezz0_temp" , pal_is_nic_prsnt, false, 5, 5},
{NIC_MEZZ1_SNR_TEMP , "nic1_mezz1_temp" , pal_is_nic_prsnt, false, 5, 5},
//dimm sensors wait for 240s. 240=80*3(fsc monitor interval)
{MB_SNR_CPU0_DIMM_GRPA_TEMP, "mb_cpu0_dimm_a_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU0_DIMM_GRPB_TEMP, "mb_cpu0_dimm_b_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU0_DIMM_GRPC_TEMP, "mb_cpu0_dimm_c_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU0_DIMM_GRPD_TEMP, "mb_cpu0_dimm_d_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU0_DIMM_GRPE_TEMP, "mb_cpu0_dimm_e_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU0_DIMM_GRPF_TEMP, "mb_cpu0_dimm_f_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU1_DIMM_GRPA_TEMP, "mb_cpu1_dimm_a_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU1_DIMM_GRPB_TEMP, "mb_cpu1_dimm_b_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU1_DIMM_GRPC_TEMP, "mb_cpu1_dimm_c_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU1_DIMM_GRPD_TEMP, "mb_cpu1_dimm_d_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU1_DIMM_GRPE_TEMP, "mb_cpu1_dimm_e_temp", pal_dimm_present_check, false, 80, 5},
{MB_SNR_CPU1_DIMM_GRPF_TEMP, "mb_cpu1_dimm_f_temp", pal_dimm_present_check, false, 80, 5},
};
static int fsc_monitor_basic_snr_list_size = sizeof(fsc_monitor_basic_snr_list) / sizeof(struct fsc_monitor);
static int
pal_key_index(char *key) {
int i;
i = 0;
while(strcmp(key_cfg[i].name, LAST_KEY)) {
// If Key is valid, return success
if (!strcmp(key, key_cfg[i].name))
return i;
i++;
}
#ifdef DEBUG
syslog(LOG_WARNING, "pal_key_index: invalid key - %s", key);
#endif
return -1;
}
int
pal_get_key_value(char *key, char *value) {
int index;
// Check is key is defined and valid
if ((index = pal_key_index(key)) < 0)
return -1;
return kv_get(key, value, NULL, KV_FPERSIST);
}
int
pal_set_key_value(char *key, char *value) {
int index, ret;
// Check is key is defined and valid
if ((index = pal_key_index(key)) < 0)
return -1;
if (key_cfg[index].function) {
ret = key_cfg[index].function(KEY_BEFORE_SET, value);
if (ret < 0)
return ret;
}
return kv_set(key, value, 0, KV_FPERSIST);
}
static int
fw_getenv(char *key, char *value)
{
char cmd[MAX_KEY_LEN + 32] = {0};
char *p;
FILE *fp;
sprintf(cmd, "/sbin/fw_printenv -n %s", key);
fp = popen(cmd, "r");
if (!fp) {
return -1;
}
if (fgets(value, MAX_VALUE_LEN, fp) == NULL) {
pclose(fp);
return -1;
}
for (p = value; *p != '\0'; p++) {
if (*p == '\n' || *p == '\r') {
*p = '\0';
break;
}
}
pclose(fp);
return 0;
}
static int
fw_setenv(char *key, char *value) {
char old_value[MAX_VALUE_LEN] = {0};
if (fw_getenv(key, old_value) != 0 ||
strcmp(old_value, value) != 0) {
/* Set the env key:value if either the key
* does not exist or the value is different from
* what we want set */
char cmd[MAX_VALUE_LEN] = {0};
snprintf(cmd, MAX_VALUE_LEN, "/sbin/fw_setenv %s %s", key, value);
return system(cmd);
}
return 0;
}
static int
key_func_por_policy(int event, void *arg) {
char value[MAX_VALUE_LEN] = {0};
int ret = 0;
switch (event) {
case KEY_BEFORE_SET:
if (strcmp((char *)arg, "lps") && strcmp((char *)arg, "on") && strcmp((char *)arg, "off"))
return -1;
if (pal_is_fw_update_ongoing(FRU_BMC)) {
syslog(LOG_WARNING, "key_func_por_policy: cannot setenv por_policy=%s", (char *)arg);
break;
}
ret = fw_setenv("por_policy", (char *)arg);
break;
case KEY_AFTER_INI:
kv_get("server_por_cfg", value, NULL, KV_FPERSIST);
ret = fw_setenv("por_policy", value);
break;
}
return ret;
}
static int
key_func_lps(int event, void *arg)
{
char value[MAX_VALUE_LEN] = {0};
switch (event) {
case KEY_BEFORE_SET:
if (pal_is_fw_update_ongoing(FRU_BMC)) {
syslog(LOG_WARNING, "key_func_lps: cannot setenv por_ls=%s", (char *)arg);
break;
}
fw_setenv("por_ls", (char *)arg);
break;
case KEY_AFTER_INI:
kv_get("pwr_server_last_state", value, NULL, KV_FPERSIST);
fw_setenv("por_ls", value);
break;
}
return 0;
}
static int
read_device(const char *device, int *value) {
FILE *fp;
int rc;
fp = fopen(device, "r");
if (!fp) {
int err = errno;
syslog(LOG_INFO, "failed to open device %s", device);
return err;
}
rc = fscanf(fp, "%d", value);
fclose(fp);
if (rc != 1) {
syslog(LOG_INFO, "failed to read device %s", device);
return ENOENT;
} else {
return 0;
}
}
int
pal_is_bmc_por(void) {
FILE *fp;
int por = 0;
fp = fopen("/tmp/ast_por", "r");
if (fp != NULL) {
if (fscanf(fp, "%d", &por) != 1) {
por = 0;
}
fclose(fp);
}
return (por)?1:0;
}
int
pal_get_platform_name(char *name) {
strcpy(name, PLATFORM_NAME);
return 0;
}
int
pal_get_num_slots(uint8_t *num) {
*num = 1;
return 0;
}
int
pal_get_platform_id(uint8_t id_type, uint8_t *id) {
int ret = 0, retry = 3, val;
uint8_t *id_cache = NULL;
char *id_file = NULL;
static uint8_t rev_id = 0xFF, sku_id = 0xFF;
switch (id_type) {
case BOARD_REV_ID:
id_cache = &rev_id;
id_file = REV_ID_FILE;
break;
case BOARD_SKU_ID:
id_cache = &sku_id;
id_file = SKU_ID_FILE;
break;
default:
return -1;
}
if (*id_cache != 0xFF) {
*id = *id_cache;
} else {
do {
ret = read_device(id_file, &val);
if (!ret) {
*id_cache = (uint8_t)val;
*id = *id_cache;
break;
}
syslog(LOG_WARNING, "pal_get_platform_id failed, id_type: %u", id_type);
msleep(10);
} while (--retry);
}
return ret;
}
int
pal_get_board_id(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len)
{
int ret;
uint8_t platform_id = 0x00;
uint8_t board_rev_id = 0x00;
int completion_code=CC_UNSPECIFIED_ERROR;
ret = pal_get_platform_id(BOARD_SKU_ID, &platform_id);
if (ret) {
*res_len = 0x00;
return completion_code;
}
ret = pal_get_platform_id(BOARD_REV_ID, &board_rev_id);
if (ret) {
*res_len = 0x00;
return completion_code;
}
// Prepare response buffer
completion_code = CC_SUCCESS;
res_data[0] = platform_id;
res_data[1] = board_rev_id;
*res_len = 0x02;
return completion_code;
}
int
pal_is_fru_prsnt(uint8_t fru, uint8_t *status) {
gpio_desc_t *gdesc = NULL;
gpio_value_t val;
*status = 0;
switch (fru) {
case FRU_MB:
*status = 1;
break;
case FRU_NIC0:
if ((gdesc = gpio_open_by_shadow(GPIO_NIC0_PRSNT))) {
if (!gpio_get_value(gdesc, &val)) {
*status = !val;
}
gpio_close(gdesc);
}
break;
case FRU_NIC1:
if ((gdesc = gpio_open_by_shadow(GPIO_NIC1_PRSNT))) {
if (!gpio_get_value(gdesc, &val)) {
*status = !val;
}
gpio_close(gdesc);
}
break;
case FRU_RISER1:
*status = 1;
break;
case FRU_RISER2:
*status = 1;
break;
case FRU_BMC:
*status = 1;
break;
case FRU_FCB:
*status = 1;
break;
default:
return -1;
}
return 0;
}
int
pal_is_slot_server(uint8_t fru) {
if (fru == FRU_MB)
return 1;
return 0;
}
// Update the Identification LED for the given fru with the status
int
pal_set_id_led(uint8_t fru, uint8_t status) {
int ret;
gpio_desc_t *gdesc = NULL;
gpio_value_t val;
if (fru != FRU_MB)
return -1;
gdesc = gpio_open_by_shadow(GPIO_LOCATE_LED);
if (gdesc == NULL)
return -1;
val = status? GPIO_VALUE_HIGH: GPIO_VALUE_LOW;
ret = gpio_set_value(gdesc, val);
if (ret != 0)
goto error;
error:
gpio_close(gdesc);
return ret;
}
int
pal_set_fault_led(uint8_t fru, uint8_t status) {
int ret;
gpio_desc_t *gdesc = NULL;
gpio_value_t val;
if (fru != FRU_MB)
return -1;
gdesc = gpio_open_by_shadow(GPIO_FAULT_LED);
if (gdesc == NULL)
return -1;
val = status? GPIO_VALUE_HIGH: GPIO_VALUE_LOW;
ret = gpio_set_value(gdesc, val);
if (ret != 0)
goto error;
error:
gpio_close(gdesc);
return ret;
}
int
pal_get_fru_id(char *str, uint8_t *fru) {
if (!strcmp(str, "all")) {
*fru = FRU_ALL;
} else if (!strcmp(str, "mb") || !strcmp(str, "vr")) {
*fru = FRU_MB;
} else if (!strcmp(str, "nic0") || !strcmp(str, "nic")) {
*fru = FRU_NIC0;
} else if (!strcmp(str, "nic1")) {
*fru = FRU_NIC1;
} else if (!strcmp(str, "riser1")) {
*fru = FRU_RISER1;
} else if (!strcmp(str, "riser2")) {
*fru = FRU_RISER2;
} else if (!strcmp(str, "bmc")) {
*fru = FRU_BMC;
} else if (!strcmp(str, "fcb")) {
*fru = FRU_FCB;
} else {
syslog(LOG_WARNING, "pal_get_fru_id: Wrong fru#%s", str);
return -1;
}
return 0;
}
int
pal_get_fru_name(uint8_t fru, char *name) {
switch (fru) {
case FRU_MB:
strcpy(name, "mb");
break;
case FRU_NIC0:
strcpy(name, "nic0");
break;
case FRU_NIC1:
strcpy(name, "nic1");
break;
case FRU_RISER1:
strcpy(name, "riser1");
break;
case FRU_RISER2:
strcpy(name, "riser2");
break;
case FRU_BMC:
strcpy(name, "bmc");
break;
case FRU_FCB:
strcpy(name, "fcb");
break;
default:
syslog(LOG_WARNING, "[%s] unknown fruid %d", __func__, fru);
return -1;
}
return 0;
}
void
pal_update_ts_sled()
{
char key[MAX_KEY_LEN] = {0};
char tstr[MAX_VALUE_LEN] = {0};
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
sprintf(tstr, "%ld", ts.tv_sec);
sprintf(key, "timestamp_sled");
pal_set_key_value(key, tstr);
}
int
pal_get_fruid_path(uint8_t fru, char *path) {
char fname[16] = {0};
switch(fru) {
case FRU_ALL: //no bin for FRU_ALL, when fru id is 0 the default is set to FRU_MB
case FRU_MB:
sprintf(fname, "mb");
break;
case FRU_NIC0:
sprintf(fname, "nic0");
break;
case FRU_NIC1:
sprintf(fname, "nic1");
break;
case FRU_RISER1:
sprintf(fname, "riser1");
break;
case FRU_RISER2:
sprintf(fname, "riser2");
break;
case FRU_BMC:
sprintf(fname, "bmc");
break;
default:
return -1;
}
sprintf(path, "/tmp/fruid_%s.bin", fname);
return 0;
}
int
pal_get_fruid_eeprom_path(uint8_t fru, char *path) {
uint8_t rev_id = 0xFF;
pal_get_platform_id(BOARD_REV_ID, &rev_id);
switch(fru) {
case FRU_MB:
if (rev_id == PLATFORM_EVT) {
sprintf(path, FRU_EEPROM_MB_EVT);
}
else if (rev_id == PLATFORM_DVT) {
sprintf(path, FRU_EEPROM_MB_DVT);
}
break;
case FRU_NIC0:
sprintf(path, FRU_EEPROM_NIC0);
break;
case FRU_NIC1:
sprintf(path, FRU_EEPROM_NIC1);
break;
case FRU_RISER1:
sprintf(path, FRU_EEPROM_RISER1);
break;
case FRU_RISER2:
sprintf(path, FRU_EEPROM_RISER2);
break;
case FRU_BMC:
sprintf(path, FRU_EEPROM_BMC);
break;
default:
return -1;
}
return 0;
}
int
pal_get_fruid_name(uint8_t fru, char *name) {
switch(fru) {
case FRU_MB:
sprintf(name, "Mother Board");
break;
case FRU_NIC0:
sprintf(name, "Mezz Card 0");
break;
case FRU_NIC1:
sprintf(name, "Mezz Card 1");
break;
case FRU_RISER1:
sprintf(name, "Riser Card 1");
break;
case FRU_RISER2:
sprintf(name, "Riser Card 2");
break;
case FRU_BMC:
sprintf(name, "BMC");
break;
case FRU_FCB:
sprintf(name, "FCB");
break;
default:
return -1;
}
return 0;
}
int
pal_is_fru_ready(uint8_t fru, uint8_t *status) {
*status = 1;
return 0;
}
// GUID for System and Device
static int
pal_get_guid(uint16_t offset, char *guid) {
int fd;
ssize_t bytes_rd;
char path[128];
uint8_t rev_id = 0xFF;
errno = 0;
pal_get_platform_id(BOARD_REV_ID, &rev_id);
if (rev_id == PLATFORM_EVT) {
sprintf(path, FRU_EEPROM_MB_EVT);
}
else if (rev_id == PLATFORM_DVT) {
sprintf(path, FRU_EEPROM_MB_DVT);
}
// check for file presence
if (access(path, F_OK)) {
syslog(LOG_ERR, "pal_get_guid: unable to access %s: %s", path, strerror(errno));
return errno;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
syslog(LOG_ERR, "pal_get_guid: unable to open %s: %s", path, strerror(errno));
return errno;
}
lseek(fd, offset, SEEK_SET);
bytes_rd = read(fd, guid, GUID_SIZE);
if (bytes_rd != GUID_SIZE) {
syslog(LOG_ERR, "pal_get_guid: read from %s failed: %s", path, strerror(errno));
}
close(fd);
return errno;
}
static int
pal_set_guid(uint16_t offset, char *guid) {
int fd;
ssize_t bytes_wr;
char path[128];
uint8_t rev_id = 0xFF;
errno = 0;
pal_get_platform_id(BOARD_REV_ID, &rev_id);
if (rev_id == PLATFORM_EVT) {
sprintf(path, FRU_EEPROM_MB_EVT);
}
else if (rev_id == PLATFORM_DVT) {
sprintf(path, FRU_EEPROM_MB_DVT);
}
// check for file presence
if (access(path, F_OK)) {
syslog(LOG_ERR, "pal_set_guid: unable to access %s: %s", path, strerror(errno));
return errno;
}
fd = open(path, O_WRONLY);
if (fd < 0) {
syslog(LOG_ERR, "pal_set_guid: unable to open %s: %s", path, strerror(errno));
return errno;
}
lseek(fd, offset, SEEK_SET);
bytes_wr = write(fd, guid, GUID_SIZE);
if (bytes_wr != GUID_SIZE) {
syslog(LOG_ERR, "pal_set_guid: write to %s failed: %s", path, strerror(errno));
}
close(fd);
return errno;
}
int
pal_get_sys_guid(uint8_t fru, char *guid) {
pal_get_guid(OFFSET_SYS_GUID, guid);
return 0;
}
int
pal_set_def_key_value() {
int i;
char key[MAX_KEY_LEN] = {0};
for(i = 0; strcmp(key_cfg[i].name, LAST_KEY) != 0; i++) {
if (kv_set(key_cfg[i].name, key_cfg[i].def_val, 0, KV_FCREATE | KV_FPERSIST)) {
#ifdef DEBUG
syslog(LOG_WARNING, "pal_set_def_key_value: kv_set failed.");
#endif
}
if (key_cfg[i].function) {
key_cfg[i].function(KEY_AFTER_INI, key_cfg[i].name);
}
}
/* Actions to be taken on Power On Reset */
if (pal_is_bmc_por()) {
/* Clear all the SEL errors */
memset(key, 0, MAX_KEY_LEN);
strcpy(key, "server_sel_error");
/* Write the value "1" which means FRU_STATUS_GOOD */
pal_set_key_value(key, "1");
/* Clear all the sensor health files*/
memset(key, 0, MAX_KEY_LEN);
strcpy(key, "server_sensor_health");
/* Write the value "1" which means FRU_STATUS_GOOD */
pal_set_key_value(key, "1");
}
return 0;
}
int
pal_set_sys_guid(uint8_t fru, char *str) {
char guid[GUID_SIZE] = {0};
pal_populate_guid(guid, str);
return pal_set_guid(OFFSET_SYS_GUID, guid);
}
int
pal_get_dev_guid(uint8_t fru, char *guid) {
pal_get_guid(OFFSET_DEV_GUID, guid);
return 0;
}
int
pal_set_dev_guid(uint8_t fru, char *str) {
char guid[GUID_SIZE] = {0};
pal_populate_guid(guid, str);
return pal_set_guid(OFFSET_DEV_GUID, guid);
}
int
pal_devnum_to_fruid(int devnum) {
return FRU_MB;
}
int
pal_channel_to_bus(int channel) {
switch (channel) {
case IPMI_CHANNEL_0:
return I2C_BUS_0; // USB (LCD Debug Board)
case IPMI_CHANNEL_6:
return I2C_BUS_5; // ME
}
// Debug purpose, map to real bus number
if (channel & 0x80) {
return (channel & 0x7f);
}
return channel;
}
bool
pal_is_fw_update_ongoing_system(void) {
uint8_t i;
for (i = FRU_MB; i <= FRU_BMC; i++) {
if (pal_is_fw_update_ongoing(i) == true)
return true;
}
return false;
}
bool
pal_check_boot_device_is_vaild(uint8_t device) {
bool vaild = false;
switch (device)
{
case BOOT_DEVICE_USB:
case BOOT_DEVICE_IPV4:
case BOOT_DEVICE_HDD:
case BOOT_DEVICE_CDROM:
case BOOT_DEVICE_OTHERS:
case BOOT_DEVICE_IPV6:
case BOOT_DEVICE_RESERVED:
vaild = true;
break;
default:
break;
}
return vaild;
}
int
pal_set_boot_order(uint8_t slot, uint8_t *boot, uint8_t *res_data, uint8_t *res_len) {
int i, j, network_dev = 0;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
char *tstr = str;
*res_len = 0;
sprintf(key, "server_boot_order");
for (i = 0; i < SIZE_BOOT_ORDER; i++) {
//Byte 0 is boot mode, Byte 1~5 is boot order
if ((i > 0) && (boot[i] != 0xFF)) {
if(!pal_check_boot_device_is_vaild(boot[i]))
return CC_INVALID_PARAM;
for (j = i+1; j < SIZE_BOOT_ORDER; j++) {
if ( boot[i] == boot[j])
return CC_INVALID_PARAM;
}
//If Bit 2:0 is 001b (Network), Bit3 is IPv4/IPv6 order
//Bit3=0b: IPv4 first
//Bit3=1b: IPv6 first
if ( boot[i] == BOOT_DEVICE_IPV4 || boot[i] == BOOT_DEVICE_IPV6)
network_dev++;
}
snprintf(tstr, 3, "%02x", boot[i]);
tstr += 2;
}
//Not allow having more than 1 network boot device in the boot order.
if (network_dev > 1)
return CC_INVALID_PARAM;
return pal_set_key_value(key, str);
}
int
pal_get_boot_order(uint8_t slot, uint8_t *req_data, uint8_t *boot, uint8_t *res_len) {
int i;
int j = 0;
int ret;
int msb, lsb;
char key[MAX_KEY_LEN] = {0};
char str[MAX_VALUE_LEN] = {0};
char tstr[4] = {0};
sprintf(key, "server_boot_order");
ret = pal_get_key_value(key, str);
if (ret) {
*res_len = 0;
return ret;
}
for (i = 0; i < 2*SIZE_BOOT_ORDER; i += 2) {
sprintf(tstr, "%c\n", str[i]);
msb = strtol(tstr, NULL, 16);
sprintf(tstr, "%c\n", str[i+1]);
lsb = strtol(tstr, NULL, 16);
boot[j++] = (msb << 4) | lsb;
}
*res_len = SIZE_BOOT_ORDER;
return 0;
}
int
pal_set_sysfw_ver(uint8_t slot, uint8_t *ver) {
int i;
char str[MAX_VALUE_LEN] = {0};
char tstr[8] = {0};
for (i = 0; i < SIZE_SYSFW_VER; i++) {
sprintf(tstr, "%02x", ver[i]);
strcat(str, tstr);
}
return pal_set_key_value("sysfw_ver_server", str);
}
int
pal_get_sysfw_ver(uint8_t slot, uint8_t *ver) {
int ret;
int i, j;
char str[MAX_VALUE_LEN] = {0};
char tstr[8] = {0};
ret = pal_get_key_value("sysfw_ver_server", str);
if (ret) {
return ret;
}
for (i = 0, j = 0; i < 2*SIZE_SYSFW_VER; i += 2) {
sprintf(tstr, "%c%c", str[i], str[i+1]);
ver[j++] = strtol(tstr, NULL, 16);
}
return 0;
}
// Get ME Firmware Version
int
pal_get_me_fw_ver(uint8_t bus, uint8_t addr, uint8_t *ver) {
ipmi_dev_id_t dev_id;
NM_RW_INFO info;
int ret;
info.bus = bus;
info.nm_addr = addr;
ret = pal_get_bmc_ipmb_slave_addr(&info.bmc_addr, info.bus);
if (ret != 0) {
return ret;
}
ret = cmd_NM_get_dev_id(&info, &dev_id);
if (ret != 0) {
return ret;
}
/*
Major version number: byte 4[6:0]
Minor version number: high 4 bits of byte 5
Milestone version number: low 4 bits of byte 5
Build version number: byte 14 and byte 15
dev_id.fw_rev1 = byte 4
dev_id.fw_rev2 = byte 5
dev_id.aux_fw_rev[1] = byte 14
dev_id.aux_fw_rev[2] = byte 15
*/
ver[0] = dev_id.fw_rev1 & 0x7F ;
ver[1] = dev_id.fw_rev2 >> 4;
ver[2] = dev_id.fw_rev2 & 0x0F;
ver[3] = dev_id.aux_fw_rev[1];
ver[4] = dev_id.aux_fw_rev[2] >> 4;
ver[5] = dev_id.aux_fw_rev[2] & 0x0F;
return ret;
}
int
pal_uart_select (uint32_t base, uint8_t offset, int option, uint32_t para) {
uint32_t mmap_fd;
uint32_t ctrl;
void *reg_base;
void *reg_offset;
mmap_fd = open("/dev/mem", O_RDWR | O_SYNC );
if (mmap_fd < 0) {
return -1;
}
reg_base = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mmap_fd, base);
reg_offset = (char*) reg_base + offset;
ctrl = *(volatile uint32_t*) reg_offset;
switch(option) {
case UARTSW_BY_BMC: //UART Switch control by bmc
ctrl &= 0x00ffffff;
break;
case UARTSW_BY_DEBUG: //UART Switch control by debug card
ctrl |= 0x01000000;
break;
case SET_SEVEN_SEGMENT: //set channel on the seven segment display
ctrl &= 0x00ffffff;
ctrl |= para;
break;
default:
syslog(LOG_WARNING, "pal_mmap: unknown option");
break;
}
*(volatile uint32_t*) reg_offset = ctrl;
munmap(reg_base, PAGE_SIZE);
close(mmap_fd);
return 0;
}
int
pal_uart_select_led_set(void) {
static uint32_t pre_channel = 0xffffffff;
unsigned int vals;
uint32_t channel = 0;
const char *shadows[] = {
"FM_UARTSW_LSB_N",
"FM_UARTSW_MSB_N"
};
//UART Switch control by bmc
pal_uart_select(AST_GPIO_BASE, UARTSW_OFFSET, UARTSW_BY_BMC, 0);
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &vals)) {
return -1;
}
// The GPIOs are active-low. So, invert it.
channel = (uint32_t)(~vals & 0x3);
// Shift to get to the bit position of the led.
channel = channel << 24;
// If the requested channel is the same as the previous, do nothing.
if (channel == pre_channel) {
return -1;
}
pre_channel = channel;
//show channel on 7-segment display
pal_uart_select(AST_GPIO_BASE, SEVEN_SEGMENT_OFFSET, SET_SEVEN_SEGMENT, channel);
return 0;
}
int
parse_mem_error_sel(uint8_t fru, uint8_t snr_num, uint8_t *event_data, char *error_log) {
uint8_t *ed = &event_data[3];
char temp_log[512] = {0};
uint8_t sen_type = event_data[0];
uint8_t chn_num, dimm_num;
if (snr_num == MEMORY_ECC_ERR) {
// SEL from MEMORY_ECC_ERR Sensor
if ((ed[0] & 0x0F) == 0x0) {
if (sen_type == 0x0C) {
strcat(error_log, "Correctable");
snprintf(temp_log, sizeof(temp_log), "DIMM%02X ECC err,FRU:%u", ed[2], fru);
pal_add_cri_sel(temp_log);
} else if (sen_type == 0x10)
strcat(error_log, "Correctable ECC error Logging Disabled");
} else if ((ed[0] & 0x0F) == 0x1) {
strcat(error_log, "Uncorrectable");
snprintf(temp_log, sizeof(temp_log), "DIMM%02X UECC err,FRU:%u", ed[2], fru);
pal_add_cri_sel(temp_log);
} else if ((ed[0] & 0x0F) == 0x5)
strcat(error_log, "Correctable ECC error Logging Limit Reached");
else
strcat(error_log, "Unknown");
} else if (snr_num == MEMORY_ERR_LOG_DIS) {
// SEL from MEMORY_ERR_LOG_DIS Sensor
if ((ed[0] & 0x0F) == 0x0)
strcat(error_log, "Correctable Memory Error Logging Disabled");
else
strcat(error_log, "Unknown");
}
// Common routine for both MEM_ECC_ERR and MEMORY_ERR_LOG_DIS
chn_num = (ed[2] & 0x1C) >> 2;
bool support_mem_mapping = false;
char mem_mapping_string[32];
pal_parse_mem_mapping_string(chn_num, &support_mem_mapping, mem_mapping_string);
if(support_mem_mapping) {
snprintf(temp_log, sizeof(temp_log), " (DIMM %s)", mem_mapping_string);
} else {
snprintf(temp_log, sizeof(temp_log), " (DIMM %02X)", ed[2]);
}
strcat(error_log, temp_log);
snprintf(temp_log, sizeof(temp_log), " Logical Rank %d", ed[1] & 0x03);
strcat(error_log, temp_log);
// DIMM number (ed[2]):
// Bit[7:5]: Socket number (Range: 0-7)
// Bit[4:2]: Channel number (Range: 0-7)
// Bit[1:0]: DIMM number (Range: 0-3)
if (((ed[1] & 0xC) >> 2) == 0x0) {
/* All Info Valid */
chn_num = (ed[2] & 0x1C) >> 2;
dimm_num = ed[2] & 0x3;
/* If critical SEL logging is available, do it */
if (sen_type == 0x0C) {
if ((ed[0] & 0x0F) == 0x0) {
snprintf(temp_log, sizeof(temp_log), "DIMM%c%d ECC err,FRU:%u", 'A'+chn_num,
dimm_num, fru);
pal_add_cri_sel(temp_log);
} else if ((ed[0] & 0x0F) == 0x1) {
snprintf(temp_log, sizeof(temp_log), "DIMM%c%d UECC err,FRU:%u", 'A'+chn_num,
dimm_num, fru);
pal_add_cri_sel(temp_log);
}
}
/* Then continue parse the error into a string. */
/* All Info Valid */
sprintf(temp_log, " (DIMM %02X) Logical Rank %d", ed[2], ed[1] & 0x03);
} else if (((ed[1] & 0xC) >> 2) == 0x1) {
/* DIMM info not valid */
snprintf(temp_log, sizeof(temp_log), " (CPU# %d, CHN# %d)",
(ed[2] & 0xE0) >> 5, (ed[2] & 0x1C) >> 2);
} else if (((ed[1] & 0xC) >> 2) == 0x2) {
/* CHN info not valid */
snprintf(temp_log, sizeof(temp_log), " (CPU# %d, DIMM# %d)",
(ed[2] & 0xE0) >> 5, ed[2] & 0x3);
} else if (((ed[1] & 0xC) >> 2) == 0x3) {
/* CPU info not valid */
snprintf(temp_log, sizeof(temp_log), " (CHN# %d, DIMM# %d)",
(ed[2] & 0x1C) >> 2, ed[2] & 0x3);
}
strcat(error_log, temp_log);
return 0;
}
int
pal_parse_sel(uint8_t fru, uint8_t *sel, char *error_log) {
uint8_t snr_num = sel[11];
uint8_t *event_data = &sel[10];
bool parsed = false;
error_log[0] = '\0';
switch(snr_num) {
case MEMORY_ECC_ERR:
case MEMORY_ERR_LOG_DIS:
parse_mem_error_sel(fru, snr_num, event_data, error_log);
parsed = true;
break;
}
if (parsed == true) {
if ((event_data[2] & 0x80) == 0) {
strcat(error_log, " Assertion");
} else {
strcat(error_log, " Deassertion");
}
return 0;
}
pal_parse_sel_helper(fru, sel, error_log);
return 0;
}
void
pal_dump_key_value(void) {
int ret;
int i = 0;
char value[MAX_VALUE_LEN] = {0x0};
while (strcmp(key_cfg[i].name, LAST_KEY)) {
printf("%s:", key_cfg[i].name);
if ((ret = kv_get(key_cfg[i].name, value, NULL, KV_FPERSIST)) < 0) {
printf("\n");
} else {
printf("%s\n", value);
}
i++;
memset(value, 0, MAX_VALUE_LEN);
}
}
// OEM Command "CMD_OEM_BYPASS_CMD" 0x34
int pal_bypass_cmd(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len){
int ret;
int completion_code=CC_UNSPECIFIED_ERROR;
uint8_t cmd, select;
uint8_t tlen;
uint8_t status;
NCSI_NL_MSG_T *msg = NULL;
NCSI_NL_RSP_T *rsp = NULL;
uint8_t channel = 0;
uint8_t netdev = 0;
int i;
*res_len = 0;
ret = pal_is_fru_prsnt(slot, &status);
if (ret < 0) {
return -1;
}
if (status == 0) {
syslog(LOG_ERR, "%s pal_is_fru_prsnt status == 0", __func__);
return CC_UNSPECIFIED_ERROR;
}
ret = pal_get_server_power(FRU_MB, &status);
if(ret < 0 || 0 == status) {
return CC_NOT_SUPP_IN_CURR_STATE;
}
if(!pal_is_slot_server(slot)) {
syslog(LOG_ERR, "%s pal_is_slot_server false", __func__);
return CC_UNSPECIFIED_ERROR;
}
select = req_data[0];
switch (select) {
case BYPASS_NCSI:
tlen = req_len - 7; // payload_id, netfn, cmd, data[0] (select), netdev, channel, cmd
if (tlen < 0) {
completion_code = CC_INVALID_LENGTH;
break;
}
netdev = req_data[1];
channel = req_data[2];
cmd = req_data[3];
msg = calloc(1, sizeof(NCSI_NL_MSG_T));
if (!msg) {
syslog(LOG_ERR, "%s Error: failed msg buffer allocation", __func__);
break;
}
memset(msg, 0, sizeof(NCSI_NL_MSG_T));
sprintf(msg->dev_name, "eth%d", netdev);
msg->channel_id = channel;
msg->cmd = cmd;
msg->payload_length = tlen;
for (i=0; i<msg->payload_length; i++) {
msg->msg_payload[i] = req_data[4+i];
}
rsp = send_nl_msg_libnl(msg);
if (rsp) {
memcpy(&res_data[0], &rsp->msg_payload[0], rsp->hdr.payload_length);
*res_len = rsp->hdr.payload_length;
completion_code = CC_SUCCESS;
} else {
completion_code = CC_UNSPECIFIED_ERROR;
}
free(msg);
if (rsp)
free(rsp);
break;
default:
return completion_code;
}
return completion_code;
}
int
pal_is_debug_card_prsnt(uint8_t *status) {
gpio_desc_t *desc = gpio_open_by_shadow("FM_POST_CARD_PRES_BMC_N");
gpio_value_t value;
int ret = -1;
if (!desc) {
return -1;
}
if (gpio_get_value(desc, &value) == 0) {
*status = value == GPIO_VALUE_LOW ? 1 : 0;
ret = 0;
}
gpio_close(desc);
return ret;
}
static bool
is_cpu_socket_occupy(unsigned int cpu_idx) {
static bool cached = false;
static unsigned int cached_id = 0;
if (!cached) {
const char *shadows[] = {
"FM_CPU0_SKTOCC_LVT3_PLD_N",
"FM_CPU1_SKTOCC_LVT3_PLD_N"
};
if (gpio_get_value_by_shadow_list(shadows, ARRAY_SIZE(shadows), &cached_id)) {
return false;
}
cached = true;
}
// bit == 1 implies CPU is absent.
if (cached_id & (1 << cpu_idx)) {
return false;
}
return true;
}
int
pal_get_syscfg_text (char *text) {
char key[MAX_KEY_LEN], value[MAX_VALUE_LEN], entry[MAX_VALUE_LEN];
char *key_prefix = "sys_config/";
int num_cpu=2, num_dimm, num_drive=14;
int index, surface, bubble;
size_t ret;
char **dimm_labels;
struct dimm_map map[48], temp_map;
if (text == NULL)
return -1;
// Clear string buffer
text[0] = '\0';
// CPU information
for (index = 0; index < num_cpu; index++) {
if (!is_cpu_socket_occupy((unsigned int)index))
continue;
sprintf(entry, "CPU%d:", index);
// Processor#
snprintf(key, MAX_KEY_LEN, "%sfru1_cpu%d_product_name",
key_prefix, index);
if (kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 26) {
// Read 4 bytes Processor#
if (snprintf(&entry[strlen(entry)], 5, "%s", &value[22]) > 5) {
syslog(LOG_ERR, "%s: CPU processor ID truncation detected!\n", __func__);
}
}
// Frequency & Core Number
snprintf(key, MAX_KEY_LEN, "%sfru1_cpu%d_basic_info",
key_prefix, index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 5) {
sprintf(&entry[strlen(entry)], "/%.1fG/%dc",
(float) (value[4] << 8 | value[3])/1000, value[0]);
}
sprintf(&entry[strlen(entry)], "\n");
strcat(text, entry);
}
num_dimm = 24;
dimm_labels = dimm_label;
// Initialize map
for (index = 0; index < num_dimm; index++) {
map[index].index = index;
map[index].label = dimm_labels[index];
}
// Bubble Sort the map according label string
surface = num_dimm;
for (surface = num_dimm; surface > 1;) {
bubble = 0;
for(index = 0; index < surface - 1; index++) {
if (strcmp(map[index].label, map[index+1].label) > 0) {
// Swap
temp_map = map[index+1];
map[index+1] = map[index];
map[index] = temp_map;
bubble = index + 1;
}
}
surface = bubble;
}
// DIMM information
for (index = 0; index < num_dimm; index++) {
sprintf(entry, "MEM%s:", map[index].label);
// Check Present
snprintf(key, MAX_KEY_LEN, "%sfru1_dimm%d_location",
key_prefix, map[index].index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 1) {
// Skip if not present
if (value[0] != 0x01)
continue;
}
// Module Manufacturer ID
snprintf(key, MAX_KEY_LEN, "%sfru1_dimm%d_manufacturer_id",
key_prefix, map[index].index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 2) {
switch (value[1]) {
case 0xce:
sprintf(&entry[strlen(entry)], "Samsung");
break;
case 0xad:
sprintf(&entry[strlen(entry)], "Hynix");
break;
case 0x2c:
sprintf(&entry[strlen(entry)], "Micron");
break;
default:
sprintf(&entry[strlen(entry)], "unknown");
break;
}
}
// Speed
snprintf(key, MAX_KEY_LEN, "%sfru1_dimm%d_speed",
key_prefix, map[index].index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 6) {
sprintf(&entry[strlen(entry)], "/%dMhz/%dGB",
value[1]<<8 | value[0],
(value[5]<<24 | value[4]<<16 | value[3]<<8 | value[2])/1024 );
}
sprintf(&entry[strlen(entry)], "\n");
strcat(text, entry);
}
// Drive information
for (index = 0; index < num_drive; index++) {
sprintf(entry, "HDD%d:", index);
// Check Present
snprintf(key, MAX_KEY_LEN, "%sfru1_B_drive%d_location",
key_prefix, index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 3) {
// Skip if not present
if (value[2] == 0xff)
continue;
}
// Model name
snprintf(key, MAX_KEY_LEN, "%sfru1_B_drive%d_model_name",
key_prefix, index);
if(kv_get(key, value, &ret, KV_FPERSIST) == 0 && ret >= 1) {
snprintf(&entry[strlen(entry)], ret+1, "%s", value);
}
sprintf(&entry[strlen(entry)], "\n");
strcat(text, entry);
}
return 0;
}
int
pal_set_ppin_info(uint8_t slot, uint8_t *req_data, uint8_t req_len, uint8_t *res_data, uint8_t *res_len)
{
char key[] = "mb_cpu_ppin";
char str[MAX_VALUE_LEN] = {0};
int i;
int completion_code = CC_UNSPECIFIED_ERROR;
*res_len = 0;
if (req_len > SIZE_CPU_PPIN*2)
req_len = SIZE_CPU_PPIN*2;
for (i = 0; i < req_len; i++) {
sprintf(str+(i*2), "%02x", req_data[i]);
}
if (kv_set(key, str, 0, KV_FPERSIST) != 0)
return completion_code;
completion_code = CC_SUCCESS;
return completion_code;
}
void
pal_get_chassis_status(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len) {
char str_server_por_cfg[64];
char buff[MAX_VALUE_LEN];
int policy = 3;
unsigned char *data = res_data;
// Platform Power Policy
memset(str_server_por_cfg, 0 , sizeof(char) * 64);
sprintf(str_server_por_cfg, "%s", "server_por_cfg");
if (pal_get_key_value(str_server_por_cfg, 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;
}
*data++ = ((is_server_off())?0x00:0x01) | (policy << 5);
*data++ = 0x00; // Last Power Event
*data++ = 0x40; // Misc. Chassis Status
*data++ = 0x00; // Front Panel Button Disable
*res_len = data - res_data;
}
int
pal_fsc_get_target_snr(char *sname, struct fsc_monitor *fsc_fru_list, int fsc_fru_list_size)
{
int i;
for ( i=0; i<fsc_fru_list_size; i++)
{
if ( 0 == strcmp(sname, fsc_fru_list[i].sensor_name) )
{
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s]sensor is found:%s, idx:%d", __func__, sname, i);
#endif
if ( NULL != fsc_fru_list[i].check_sensor_sts )
{
if(fsc_fru_list[i].check_sensor_sts(fsc_fru_list[i].sensor_num))
{
return i;
} else {
return PAL_ENOTSUP;
}
}
}
}
syslog(LOG_WARNING,"[%s]Unknown sensor name:%s", __func__, sname);
return PAL_ENOTSUP;
}
bool
pal_sensor_is_valid(char *fru_name, char *sensor_name)
{
uint8_t fru_id;
struct fsc_monitor *fsc_fru_list;
int fsc_fru_list_size;
int ret;
//check the fru name is valid or not
ret = pal_get_fru_id(fru_name, &fru_id);
if ( ret < 0 )
{
syslog(LOG_WARNING,"[%s] Wrong fru#%s", __func__, fru_name);
return false;
}
fsc_fru_list = fsc_monitor_basic_snr_list;
fsc_fru_list_size = fsc_monitor_basic_snr_list_size;
//get the target sensor
ret = pal_fsc_get_target_snr(sensor_name, fsc_fru_list, fsc_fru_list_size);
if ( ret < 0 )
{
#ifdef FSC_DEBUG
syslog(LOG_WARNING,"[%s] undefined sensor: %s", __func__, sensor_name);
#endif
return false;
}
return true;
}
int
pal_convert_to_dimm_str(uint8_t cpu, uint8_t channel, uint8_t slot, char *str) {
uint8_t idx;
char label[] = {'A','C','B','D'};
if ((idx = cpu*2+slot) < sizeof(label)) {
sprintf(str, "%c%d", label[idx], channel);
} else {
sprintf(str, "NA");
}
return 0;
}
int
pal_get_fru_list(char *list) {
strcpy(list, pal_fru_list);
return 0;
}
int
pal_get_fru_capability(uint8_t fru, unsigned int *caps)
{
int ret = 0;
switch (fru) {
case FRU_MB:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL |
FRU_CAPABILITY_POWER_ALL | FRU_CAPABILITY_SERVER;
break;
case FRU_NIC0:
case FRU_NIC1:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL |
FRU_CAPABILITY_NETWORK_CARD;
break;
case FRU_BMC:
*caps = FRU_CAPABILITY_FRUID_ALL | FRU_CAPABILITY_SENSOR_ALL |
FRU_CAPABILITY_MANAGEMENT_CONTROLLER;
break;
case FRU_RISER1:
case FRU_RISER2:
case FRU_FCB:
*caps = FRU_CAPABILITY_SENSOR_ALL;
break;
default:
ret = -1;
break;
}
return ret;
}
void
pal_set_post_end(uint8_t slot, uint8_t *req_data, uint8_t *res_data, uint8_t *res_len)
{
*res_len = 0;
// log the post end event
syslog (LOG_INFO, "POST End Event for Payload#%d\n", slot);
// Sync time with system
if (system("/etc/init.d/sync_date.sh &") != 0) {
syslog(LOG_ERR, "Sync date failed!\n");
}
pal_set_post_complete(true);
}
int
pal_get_nm_selftest_result(uint8_t fruid, uint8_t *data)
{
uint8_t bus_id = 0x5;
int rlen = 0;
int ret = PAL_EOK;
rlen = ipmb_send(
bus_id,
0x2c,
NETFN_APP_REQ << 2,
CMD_APP_GET_SELFTEST_RESULTS);
if ( rlen < 2 ) {
ret = PAL_ENOTSUP;
}
else {
//get the response data
memcpy(data, ipmb_rxb()->data, 2);
}
return ret;
}
int
pal_handle_dcmi(uint8_t fru, uint8_t *request, uint8_t req_len, uint8_t *response, uint8_t *rlen) {
return me_xmit(request, req_len, response, rlen);
}
int
pal_get_pfr_address(uint8_t fru, uint8_t *bus, uint8_t *addr, bool *bridged) {
if (fru != FRU_MB) {
return -1;
}
*bus = PFR_MAILBOX_BUS;
*addr = PFR_MAILBOX_ADDR;
*bridged = false;
return 0;
}
bool
pal_is_nic_prsnt(uint8_t snr_num) {
uint8_t fru, status;
if(snr_num == NIC_MEZZ0_SNR_TEMP) {
fru = FRU_NIC0;
pal_is_fru_prsnt(fru, &status);
} else {
fru = FRU_NIC1;
pal_is_fru_prsnt(fru, &status);
}
return status;
}
int
pal_fw_update_finished(uint8_t fru, const char *comp, int status) {
int ret = 0;
int ifd, retry = 3;
uint8_t buf[16];
char dev_i2c[16];
ret = status;
if (ret == 0) {
sprintf(dev_i2c, "/dev/i2c-%d", PFR_MAILBOX_BUS);
ifd = open(dev_i2c, O_RDWR);
if (ifd < 0) {
return -1;
}
buf[0] = 0x13; // BMC update intent
if (!strcmp(comp, "bmc")) {
buf[1] = UPDATE_BMC_ACTIVE;
} else if (!strcmp(comp, "bios")) {
buf[1] = UPDATE_UPDATE_DYNAMIC | UPDATE_PCH_ACTIVE;
} else if (!strcmp(comp, "cpld")) {
buf[1] = UPDATE_CPLD_ACTIVE;
}
sync();
sleep(3);
ret = system("sv stop sensord > /dev/null 2>&1");
ret = system("sv stop ipmbd_0 > /dev/null 2>&1");
ret = system("sv stop ipmbd_5 > /dev/null 2>&1");
printf("sending update intent to CPLD...\n");
fflush(stdout);
sleep(1);
do {
ret = i2c_rdwr_msg_transfer(ifd, PFR_MAILBOX_ADDR, buf, 2, NULL, 0);
if (ret) {
syslog(LOG_WARNING, "i2c%u xfer failed, cmd: %02x %02x", PFR_MAILBOX_BUS, buf[0], buf[1]);
if (--retry > 0) {
msleep(100);
}
}
} while (ret && retry > 0);
close(ifd);
}
return ret;
}
int
pal_is_pfr_active(void) {
int pfr_active = PFR_NONE;
int ifd, retry = 3;
uint8_t tbuf[8], rbuf[8];
char dev_i2c[16];
sprintf(dev_i2c, "/dev/i2c-%d", PFR_MAILBOX_BUS);
ifd = open(dev_i2c, O_RDWR);
if (ifd < 0) {
return pfr_active;
}
tbuf[0] = 0x0A;
do {
if (!i2c_rdwr_msg_transfer(ifd, PFR_MAILBOX_ADDR, tbuf, 1, rbuf, 1)) {
pfr_active = (rbuf[0] & 0x20) ? PFR_ACTIVE : PFR_UNPROVISIONED;
break;
}
#ifdef DEBUG
syslog(LOG_WARNING, "i2c%u xfer failed, cmd: %02x", 4, tbuf[0]);
#endif
if (--retry > 0)
msleep(20);
} while (retry > 0);
close(ifd);
return pfr_active;
}