meta-facebook/meta-fby3/recipes-fby3/plat-libs/files/bic/bic_ipmi.c (2,273 lines of code) (raw):
/*
*
* Copyright 2015-present Facebook. All Rights Reserved.
*
* This file contains code to support IPMI2.0 Specificaton 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 <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <errno.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/file.h>
#include <openbmc/obmc-i2c.h>
#include <openbmc/kv.h>
#include "bic_ipmi.h"
//FRU
#define FRUID_READ_COUNT_MAX 0x20
#define FRUID_WRITE_COUNT_MAX 0x20
#define FRUID_SIZE 256
//GPIO
#define GPIO_LOW 0
#define GPIO_HIGH 1
#define GPIO_HSC_MUX_SWITCH 0x2F
//SDR
#define SDR_READ_COUNT_MAX 0x1A
#pragma pack(push, 1)
typedef struct _sdr_rec_hdr_t {
uint16_t rec_id;
uint8_t ver;
uint8_t type;
uint8_t len;
} sdr_rec_hdr_t;
#pragma pack(pop)
#define SIZE_SYS_GUID 16
#define MAX_VER_STR_LEN 80
#define KV_SLOT_IS_M2_EXP_PRESENT "slot%x_is_m2_exp_prsnt"
#define KV_SLOT_GET_1OU_TYPE "slot%x_get_1ou_type"
#define KV_MB_INDEX "get_mb_index"
#define KV_SLOT_IS_2U_TOPBOT_PRESENT "slot%x_is_2u_topbot_prsnt"
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define BIC_SENSOR_SYSTEM_STATUS 0x46
#define BB_FW_UPDATE_STAT_FILE "/tmp/cache_store/bb_fw_update"
#define GPIO_FALSE_DIR "/tmp/gpio/bic%d_%d"
enum {
M2_PWR_OFF = 0x00,
M2_PWR_ON = 0x01,
M2_REG_2OU = 0x04,
M2_REG_1OU = 0x05,
};
enum {
M2_ROOT_PORT0 = 0x0,
M2_ROOT_PORT1 = 0x1,
M2_ROOT_PORT2 = 0x2,
M2_ROOT_PORT3 = 0x3,
M2_ROOT_PORT4 = 0x4,
M2_ROOT_PORT5 = 0x5,
};
uint8_t mapping_m2_prsnt[2][6] = { {M2_ROOT_PORT0, M2_ROOT_PORT1, M2_ROOT_PORT5, M2_ROOT_PORT4, M2_ROOT_PORT2, M2_ROOT_PORT3},
{M2_ROOT_PORT4, M2_ROOT_PORT3, M2_ROOT_PORT2, M2_ROOT_PORT1}};
uint8_t mapping_e1s_prsnt[2][6] = { {M2_ROOT_PORT4, M2_ROOT_PORT5, M2_ROOT_PORT3, M2_ROOT_PORT2, M2_ROOT_PORT1, M2_ROOT_PORT0},
{M2_ROOT_PORT1, M2_ROOT_PORT2, M2_ROOT_PORT3, M2_ROOT_PORT4}};
uint8_t mapping_e1s_pwr[2][6] = { {M2_ROOT_PORT3, M2_ROOT_PORT2, M2_ROOT_PORT5, M2_ROOT_PORT4, M2_ROOT_PORT1, M2_ROOT_PORT0},
{M2_ROOT_PORT4, M2_ROOT_PORT3, M2_ROOT_PORT2, M2_ROOT_PORT1} };
// S/E - Get Sensor reading
// Netfn: 0x04, Cmd: 0x2d
int
bic_get_sensor_reading(uint8_t slot_id, uint8_t sensor_num, ipmi_sensor_reading_t *sensor, uint8_t intf) {
uint8_t rlen = 0;
return bic_ipmb_send(slot_id, NETFN_SENSOR_REQ, CMD_SENSOR_GET_SENSOR_READING, &sensor_num, 1, (uint8_t *)sensor, &rlen, intf);
}
int
bic_get_oem_sensor_reading(uint8_t slot_id, uint8_t index, ipmi_sensor_reading_t *sensor, uint8_t mul, uint8_t intf) {
#define BIC_SENSOR_READ_NA 0x20
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, index};
uint8_t rbuf[16] = {0x00};
uint8_t rlen = 0;
uint32_t val = 0;
int ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_GPV3_GET_DUAL_M2_PWR, tbuf, 4, rbuf, &rlen, intf);
if (ret == 0 && rlen == 5) {
if (mul > 0) {
val = (rbuf[3] + rbuf[4]) / mul;
} else {
val = (rbuf[3] + rbuf[4]);
}
sensor->flags = 0;
sensor->status = 0;
sensor->ext_status = 0;
if (val > 0xff) {
sensor->value = 0xff;
} else {
sensor->value = (uint8_t)val;
}
} else {
sensor->flags = BIC_SENSOR_READ_NA;
}
return ret;
}
// APP - Get Device ID
// Netfn: 0x06, Cmd: 0x01
int
bic_get_dev_id(uint8_t slot_id, ipmi_dev_id_t *dev_id, uint8_t intf) {
uint8_t rlen = 0;
return bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_GET_DEVICE_ID, NULL, 0, (uint8_t *) dev_id, &rlen, intf);
}
// APP - Get Device ID
// Netfn: 0x06, Cmd: 0x04
int
bic_get_self_test_result(uint8_t slot_id, uint8_t *self_test_result, uint8_t intf) {
uint8_t rlen = 0;
return bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_GET_SELFTEST_RESULTS, NULL, 0, (uint8_t *)self_test_result, &rlen, intf);
}
// Storage - Get FRUID info
// Netfn: 0x0A, Cmd: 0x10
int
bic_get_fruid_info(uint8_t slot_id, uint8_t fru_id, ipmi_fruid_info_t *info, uint8_t intf) {
uint8_t rlen = 0;
uint8_t fruid = 0;
return bic_ipmb_send(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_FRUID_INFO, &fruid, 1, (uint8_t *) info, &rlen, intf);
}
// Storage - Reserve SDR
// Netfn: 0x0A, Cmd: 0x22
static int
_get_sdr_rsv(uint8_t slot_id, uint8_t *rsv, uint8_t intf) {
uint8_t rlen = 0;
return bic_ipmb_send(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_RSV_SDR, NULL, 0, (uint8_t *) rsv, &rlen, intf);
}
// Storage - Get SDR
// Netfn: 0x0A, Cmd: 0x23
static int
_get_sdr(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen, uint8_t intf) {
return bic_ipmb_send(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_GET_SDR, (uint8_t *)req, sizeof(ipmi_sel_sdr_req_t), (uint8_t*)res, rlen, intf);
}
int
bic_get_sdr(uint8_t slot_id, ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen, uint8_t intf) {
int ret;
uint8_t tbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t tlen;
uint8_t len;
ipmi_sel_sdr_res_t *tres;
sdr_rec_hdr_t *hdr;
tres = (ipmi_sel_sdr_res_t *) tbuf;
// Get SDR reservation ID for the given record
ret = _get_sdr_rsv(slot_id, rbuf, intf);
if (ret) {
syslog(LOG_ERR, "%s() _get_sdr_rsv returns %d\n", __func__, ret);
return ret;
}
req->rsv_id = (rbuf[1] << 8) | rbuf[0];
// Initialize the response length to zero
*rlen = 0;
// Read SDR Record Header
req->offset = 0;
req->nbytes = sizeof(sdr_rec_hdr_t);
ret = _get_sdr(slot_id, req, (ipmi_sel_sdr_res_t *)tbuf, &tlen, intf);
if (ret) {
syslog(LOG_ERR, "%s() _get_sdr returns %d\n", __func__, ret);
return ret;
}
// Copy the next record id to response
res->next_rec_id = tres->next_rec_id;
// Copy the header excluding first two bytes(next_rec_id)
memcpy(res->data, tres->data, tlen-2);
// Update response length and offset for next requesdr_rec_hdr_t
*rlen += tlen-2;
req->offset = tlen-2;
// Find length of data from header info
hdr = (sdr_rec_hdr_t *) tres->data;
len = hdr->len;
// Keep reading chunks of SDR record in a loop
while (len > 0) {
if (len > SDR_READ_COUNT_MAX) {
req->nbytes = SDR_READ_COUNT_MAX;
} else {
req->nbytes = len;
}
ret = _get_sdr(slot_id, req, (ipmi_sel_sdr_res_t *)tbuf, &tlen, intf);
if (ret) {
syslog(LOG_ERR, "%s() _get_sdr returns %d\n", __func__, ret);
return ret;
}
// Copy the data excluding the first two bytes(next_rec_id)
memcpy(&res->data[req->offset], tres->data, tlen-2);
// Update response length, offset for next request, and remaining length
*rlen += tlen-2;
req->offset += tlen-2;
len -= tlen-2;
}
return BIC_STATUS_SUCCESS;
}
// Storage - Get SDR
// Netfn: 0x0A, Cmd: 0x11
static int
_read_fruid(uint8_t slot_id, uint8_t fru_id, uint32_t offset, uint8_t count, uint8_t *rbuf, uint8_t *rlen, uint8_t intf) {
uint8_t tbuf[4] = {0};
uint8_t tlen;
tbuf[0] = fru_id;
tbuf[1] = offset & 0xFF;
tbuf[2] = (offset >> 8) & 0xFF;
tbuf[3] = count;
tlen = 4;
return bic_ipmb_send(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_READ_FRUID_DATA, tbuf, tlen, rbuf, rlen, intf);
}
static int
_zero_chksum(uint8_t *data, uint16_t len) {
bool is_valid = false;
uint8_t checksum = 0;
for (int i = 0; i < (len - 1); i++ ) {
// if all data is 0, its checksum would be 0.
// try to avoid the false positive since one of them should be > 0
if ( is_valid == false && data[i] > 0 ) is_valid = true;
// calc zero-checksum
checksum += data[i];
}
checksum = ~(checksum) + 1;
if ( (is_valid == false) || (checksum != data[len-1]) ) {
return BIC_STATUS_FAILURE;
}
return BIC_STATUS_SUCCESS;
}
static int
_verify_fruid(uint8_t *data, int fru_size) {
enum {
HDR_CHASSIS_AREA_IDX = 0x2,
HDR_BOARD_AREA_IDX,
HDR_PRODUCT_AREA_IDX,
HDR_FIELD_END,
};
// check header - 8 bytes including its checksum
if ( _zero_chksum(data, 8) < 0 ) {
syslog(LOG_WARNING,"%s() check header failed", __func__);
return BIC_STATUS_FAILURE;
}
// start checking from chassis(2) to product(5)
// for internal and multi-record area, they are not supported.
for (int i = HDR_CHASSIS_AREA_IDX; i < HDR_FIELD_END; i++ ) {
uint8_t *st_idx = &data[i];
if ( *st_idx == 0 ) continue;
*st_idx *= 8; // in multiples of 8 bytes
if ( _zero_chksum(&data[*st_idx], data[*(st_idx)+1]*8) < 0 ) {
syslog(LOG_WARNING,"%s() check %d fru field failed", __func__, i);
return BIC_STATUS_FAILURE;
}
}
return BIC_STATUS_SUCCESS;
}
bool
bic_is_crit_act_ongoing(uint8_t fruid) {
char value[MAX_VALUE_LEN] = {0};
int ret = kv_get("pwr_lock", value, NULL, 0);
if (ret < 0) {
// power lock hasn't been asserted
if (errno == ENOENT) {
// return false because there is no critical activity in progress
return false;
}
syslog(LOG_WARNING, "%s() Cannot get pwr_lock", __func__);
return true;
}
// if pwr_lock is 1, return true
return (strncmp(value, "1", 1) == 0)?true:false;
}
#define FW_UPDATING_STR "fru%d_fwupd"
bool
bic_is_fw_update_ongoing(uint8_t fruid) {
char key[MAX_KEY_LEN] = {0};
char value[MAX_VALUE_LEN] = {0};
int ret = BIC_STATUS_SUCCESS;
struct timespec ts;
sprintf(key, FW_UPDATING_STR, fruid);
ret = kv_get(key, value, NULL, 0);
if (ret < 0) {
return false;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
if (strtoul(value, NULL, 10) > ts.tv_sec)
return true;
return false;
}
int
_set_fw_update_ongoing(uint8_t slot_id, uint16_t tmout) {
char key[MAX_KEY_LEN] = {0};
char value[MAX_VALUE_LEN] = {0};
struct timespec ts;
sprintf(key, FW_UPDATING_STR, slot_id);
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += tmout;
sprintf(value, "%ld", ts.tv_sec);
if (kv_set(key, value, 0, 0) < 0) {
return -1;
}
return 0;
}
int
bic_read_fruid(uint8_t slot_id, uint8_t fru_id, const char *path, int *fru_size, uint8_t intf, uint8_t less_retry) {
#define RETRY_DELAY 3
int ret = BIC_STATUS_FAILURE;
uint32_t nread = 0;
uint32_t offset = 0;
uint8_t count = 0;
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t rlen = 0;
int fd = 0;
ipmi_fruid_info_t info = {0};
uint8_t *buf = NULL;
int retry = 0, retryMax = less_retry == 1 ? RETRY_3_TIME : RETRY_TIME;
// Remove the file if exists already
unlink(path);
// Open the file exclusively for write
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0) {
syslog(LOG_ERR, "bic_read_fruid: open fails for path: %s\n", path);
goto error_exit;
}
while ( retry < RETRY_3_TIME ) {
if ( bic_is_fw_update_ongoing(slot_id) == true ) {
sleep(5);
continue;
}
// Read the FRUID information
ret = bic_get_fruid_info(slot_id, fru_id, &info, intf);
if ( ret < 0 ) {
syslog(LOG_ERR, "bic_read_fruid: bic_read_fruid_info returns %d\n", ret);
sleep(RETRY_DELAY * (retry + 1));
} else break;
retry++;
}
if ( retry == RETRY_3_TIME ) goto error_exit;
else ret = BIC_STATUS_FAILURE;
// Indicates the size of the FRUID
nread = (info.size_msb << 8) | info.size_lsb;
if ( nread > FRUID_SIZE ) nread = FRUID_SIZE;
else if ( nread == 0 ) goto error_exit;
*fru_size = nread;
// Allocate buffer
buf = (uint8_t *)malloc(*fru_size);
if ( buf == NULL ) {
printf("Failed to malloc memory for fruid\n");
goto error_exit;
}
retry = 0;
while ( retry < retryMax) {
if ( bic_is_fw_update_ongoing(slot_id) == true ) {
sleep(5);
continue;
}
// Read chunks of FRUID binary data in a loop
offset = 0;
nread = *fru_size;
lseek(fd, 0, SEEK_SET);
while ( nread > 0 ) {
if (nread > FRUID_READ_COUNT_MAX) count = FRUID_READ_COUNT_MAX;
else count = nread;
ret = _read_fruid(slot_id, fru_id, offset, count, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_ERR, "bic_read_fruid: ipmb_wrapper fails\n");
break;
}
// Ignore the first byte as it indicates length of response
if ( write(fd, &rbuf[1], rlen-1) != (rlen-1) ) {
syslog(LOG_ERR, "bic_read_fruid: write to FRU failed\n");
ret = BIC_STATUS_FAILURE;
break;
}
// Update offset
memcpy(&buf[offset], &rbuf[1], rlen-1);
offset += (rlen-1);
nread -= (rlen-1);
}
if ( ret == BIC_STATUS_SUCCESS ) {
ret = _verify_fruid(buf, *fru_size);
}
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() verified fruid failed, slot:%d, retry:%d, intf:%02X, size: %d\n", __func__, slot_id, retry, intf, offset);
if (less_retry) {
sleep(3);
} else {
sleep(RETRY_DELAY * (retry + 1));
}
} else break;
retry++;
}
error_exit:
if ( buf != NULL ) free(buf);
if ( fd > 0 ) close(fd);
return ret;
}
// Storage - Get SDR
// Netfn: 0x0A, Cmd: 0x12
static int
_write_fruid(uint8_t slot_id, uint8_t fru_id, uint32_t offset, uint8_t count, uint8_t *buf, uint8_t intf) {
int ret;
uint8_t tbuf[64] = {0};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
tbuf[0] = fru_id;
tbuf[1] = offset & 0xFF;
tbuf[2] = (offset >> 8) & 0xFF;
memcpy(&tbuf[3], buf, count);
tlen = count + 3;
ret = bic_ipmb_send(slot_id, NETFN_STORAGE_REQ, CMD_STORAGE_WRITE_FRUID_DATA, tbuf, tlen, rbuf, &rlen, intf);
if ( rbuf[0] != count ) {
syslog(LOG_WARNING, "%s() Failed to write fruid data. %d != %d \n", __func__, rbuf[0], count);
return -1;
}
return ret;
}
int
bic_write_fruid(uint8_t slot_id, uint8_t fru_id, const char *path, uint8_t intf) {
int ret = -1;
uint32_t offset;
int8_t count;
uint8_t buf[64] = {0};
int fd;
// Open the file exclusively for read
fd = open(path, O_RDONLY, 0666);
if (fd < 0) {
syslog(LOG_ERR, "%s() Failed to open %s\n", __func__, path);
goto error_exit;
}
// Write chunks of FRUID binary data in a loop
offset = 0;
while (1) {
// Read from file
count = read(fd, buf, FRUID_WRITE_COUNT_MAX);
if (count <= 0) {
break;
}
// Write to the FRUID
ret = _write_fruid(slot_id, fru_id, offset, count, buf, intf);
if (ret) {
break;
}
// Update counter
offset += count;
}
error_exit:
if (fd > 0 ) {
close(fd);
}
return ret;
}
// OEM - Get Firmware Version
// Netfn: 0x38, Cmd: 0x0B
static int
_bic_get_fw_ver(uint8_t slot_id, uint8_t fw_comp, uint8_t *ver, uint8_t intf) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, fw_comp}; //IANA ID + FW_COMP
uint8_t rbuf[16] = {0x00};
uint8_t rlen = 0;
int ret = BIC_STATUS_FAILURE;
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_FW_VER, tbuf, 4, rbuf, &rlen, intf);
// rlen should be greater than or equal to 4 (IANA + Data1 +...+ DataN)
if ( ret < 0 || rlen < 4 ) {
syslog(LOG_ERR, "%s: ret: %d, rlen: %d, slot_id:%x, intf:%x\n", __func__, ret, rlen, slot_id, intf);
} else {
//Ignore IANA ID
memcpy(ver, &rbuf[3], rlen-3);
ret = BIC_STATUS_SUCCESS;
}
return ret;
}
// It's an API and provided to fw-util
int
bic_get_fw_ver(uint8_t slot_id, uint8_t comp, uint8_t *ver) {
uint8_t fw_comp = 0x0;
uint8_t intf = 0x0;
int ret = BIC_STATUS_FAILURE;
//get the component
switch (comp) {
case FW_1OU_BIC:
case FW_2OU_BIC:
case FW_BB_BIC:
case FW_CWC_BIC:
case FW_GPV3_TOP_BIC:
case FW_GPV3_BOT_BIC:
fw_comp = FW_BIC;
break;
case FW_1OU_BIC_BOOTLOADER:
case FW_2OU_BIC_BOOTLOADER:
case FW_BB_BIC_BOOTLOADER:
case FW_CWC_BIC_BL:
case FW_GPV3_TOP_BIC_BL:
case FW_GPV3_BOT_BIC_BL:
fw_comp = FW_BIC_BOOTLOADER;
break;
case FW_CWC_CPLD:
case FW_GPV3_TOP_CPLD:
case FW_GPV3_BOT_CPLD:
fw_comp = FW_2OU_CPLD;
break;
case FW_CWC_PESW:
case FW_GPV3_TOP_PESW:
case FW_GPV3_BOT_PESW:
fw_comp = FW_2OU_PESW_FW_VER;
break;
case FW_CWC_PESW_VR:
case FW_GPV3_TOP_PESW_VR:
case FW_GPV3_BOT_PESW_VR:
fw_comp = FW_2OU_PESW_VR;
break;
case FW_2U_TOP_PESW_CFG_VER:
case FW_2U_BOT_PESW_CFG_VER:
fw_comp = FW_2OU_PESW_CFG_VER;
break;
case FW_2U_TOP_PESW_FW_VER:
case FW_2U_BOT_PESW_FW_VER:
fw_comp = FW_2OU_PESW_FW_VER;
break;
case FW_2U_TOP_PESW_BL0_VER:
case FW_2U_BOT_PESW_BL0_VER:
fw_comp = FW_2OU_PESW_BL0_VER;
break;
case FW_2U_TOP_PESW_BL1_VER:
case FW_2U_BOT_PESW_BL1_VER:
fw_comp = FW_2OU_PESW_BL1_VER;
break;
case FW_2U_TOP_PESW_PART_MAP0_VER:
case FW_2U_BOT_PESW_PART_MAP0_VER:
fw_comp = FW_2OU_PESW_PART_MAP0_VER;
break;
case FW_2U_TOP_PESW_PART_MAP1_VER:
case FW_2U_BOT_PESW_PART_MAP1_VER:
fw_comp = FW_2OU_PESW_PART_MAP1_VER;
break;
case FW_2U_TOP_3V3_VR1:
case FW_2U_BOT_3V3_VR1:
fw_comp = FW_2OU_3V3_VR1;
break;
case FW_2U_TOP_3V3_VR2:
case FW_2U_BOT_3V3_VR2:
fw_comp = FW_2OU_3V3_VR2;
break;
case FW_2U_TOP_3V3_VR3:
case FW_2U_BOT_3V3_VR3:
fw_comp = FW_2OU_3V3_VR3;
break;
case FW_2U_TOP_1V8_VR:
case FW_2U_BOT_1V8_VR:
fw_comp = FW_2OU_1V8_VR;
break;
default:
fw_comp = comp;
break;
}
//get the intf
switch (comp) {
case FW_CPLD:
case FW_ME:
case FW_BIC:
case FW_BIC_BOOTLOADER:
intf = NONE_INTF;
break;
case FW_1OU_BIC:
case FW_1OU_BIC_BOOTLOADER:
case FW_1OU_CPLD:
intf = FEXP_BIC_INTF;
break;
case FW_2OU_BIC:
case FW_2OU_BIC_BOOTLOADER:
case FW_2OU_CPLD:
case FW_2OU_3V3_VR1:
case FW_2OU_3V3_VR2:
case FW_2OU_3V3_VR3:
case FW_2OU_1V8_VR:
case FW_2OU_PESW_VR:
case FW_2OU_PESW_CFG_VER:
case FW_2OU_PESW_FW_VER:
case FW_2OU_PESW_BL0_VER:
case FW_2OU_PESW_BL1_VER:
case FW_2OU_PESW_PART_MAP0_VER:
case FW_2OU_PESW_PART_MAP1_VER:
case FW_CWC_BIC:
case FW_CWC_BIC_BL:
case FW_CWC_CPLD:
case FW_CWC_PESW:
case FW_CWC_PESW_VR:
intf = REXP_BIC_INTF;
break;
case FW_BB_BIC:
case FW_BB_BIC_BOOTLOADER:
case FW_BB_CPLD:
intf = BB_BIC_INTF;
break;
case FW_GPV3_TOP_BIC:
case FW_GPV3_TOP_BIC_BL:
case FW_GPV3_TOP_CPLD:
case FW_GPV3_TOP_PESW:
case FW_GPV3_TOP_PESW_VR:
case FW_2U_TOP_PESW_CFG_VER:
case FW_2U_TOP_PESW_FW_VER:
case FW_2U_TOP_PESW_BL0_VER:
case FW_2U_TOP_PESW_BL1_VER:
case FW_2U_TOP_PESW_PART_MAP0_VER:
case FW_2U_TOP_PESW_PART_MAP1_VER:
case FW_2U_TOP_3V3_VR1:
case FW_2U_TOP_3V3_VR2:
case FW_2U_TOP_3V3_VR3:
case FW_2U_TOP_1V8_VR:
intf = RREXP_BIC_INTF1;
break;
case FW_GPV3_BOT_BIC:
case FW_GPV3_BOT_BIC_BL:
case FW_GPV3_BOT_CPLD:
case FW_GPV3_BOT_PESW:
case FW_GPV3_BOT_PESW_VR:
case FW_2U_BOT_PESW_CFG_VER:
case FW_2U_BOT_PESW_FW_VER:
case FW_2U_BOT_PESW_BL0_VER:
case FW_2U_BOT_PESW_BL1_VER:
case FW_2U_BOT_PESW_PART_MAP0_VER:
case FW_2U_BOT_PESW_PART_MAP1_VER:
case FW_2U_BOT_3V3_VR1:
case FW_2U_BOT_3V3_VR2:
case FW_2U_BOT_3V3_VR3:
case FW_2U_BOT_1V8_VR:
intf = RREXP_BIC_INTF2;
break;
}
//run cmd
switch (comp) {
case FW_CPLD:
case FW_ME:
case FW_BIC:
case FW_BIC_BOOTLOADER:
case FW_1OU_BIC:
case FW_1OU_BIC_BOOTLOADER:
case FW_2OU_BIC:
case FW_2OU_BIC_BOOTLOADER:
case FW_2OU_3V3_VR1:
case FW_2OU_3V3_VR2:
case FW_2OU_3V3_VR3:
case FW_2OU_1V8_VR:
case FW_2OU_PESW_VR:
case FW_2OU_PESW_CFG_VER:
case FW_2OU_PESW_FW_VER:
case FW_2OU_PESW_BL0_VER:
case FW_2OU_PESW_BL1_VER:
case FW_2OU_PESW_PART_MAP0_VER:
case FW_2OU_PESW_PART_MAP1_VER:
case FW_BB_BIC:
case FW_BB_BIC_BOOTLOADER:
case FW_CWC_BIC:
case FW_GPV3_TOP_BIC:
case FW_GPV3_BOT_BIC:
case FW_CWC_BIC_BL:
case FW_GPV3_TOP_BIC_BL:
case FW_GPV3_BOT_BIC_BL:
case FW_CWC_PESW:
case FW_GPV3_TOP_PESW:
case FW_GPV3_BOT_PESW:
case FW_CWC_CPLD:
case FW_GPV3_TOP_CPLD:
case FW_GPV3_BOT_CPLD:
case FW_CWC_PESW_VR:
case FW_GPV3_TOP_PESW_VR:
case FW_GPV3_BOT_PESW_VR:
case FW_2U_TOP_PESW_CFG_VER:
case FW_2U_TOP_PESW_FW_VER:
case FW_2U_TOP_PESW_BL0_VER:
case FW_2U_TOP_PESW_BL1_VER:
case FW_2U_TOP_PESW_PART_MAP0_VER:
case FW_2U_TOP_PESW_PART_MAP1_VER:
case FW_2U_BOT_PESW_CFG_VER:
case FW_2U_BOT_PESW_FW_VER:
case FW_2U_BOT_PESW_BL0_VER:
case FW_2U_BOT_PESW_BL1_VER:
case FW_2U_BOT_PESW_PART_MAP0_VER:
case FW_2U_BOT_PESW_PART_MAP1_VER:
case FW_2U_TOP_3V3_VR1:
case FW_2U_TOP_3V3_VR2:
case FW_2U_TOP_3V3_VR3:
case FW_2U_TOP_1V8_VR:
case FW_2U_BOT_3V3_VR1:
case FW_2U_BOT_3V3_VR2:
case FW_2U_BOT_3V3_VR3:
case FW_2U_BOT_1V8_VR:
ret = _bic_get_fw_ver(slot_id, fw_comp, ver, intf);
break;
case FW_1OU_CPLD:
ret = bic_get_exp_cpld_ver(slot_id, fw_comp, ver, 0/*bus 0*/, 0x80/*8-bit addr*/, intf);
break;
case FW_2OU_CPLD:
{
uint8_t board_type = 0;
if ( fby3_common_get_2ou_board_type(slot_id, &board_type) < 0 ) {
syslog(LOG_WARNING, "Failed to get 2ou board type\n");
}
if ( board_type == GPV3_MCHP_BOARD ||
board_type == GPV3_BRCM_BOARD ) {
ret = _bic_get_fw_ver(slot_id, fw_comp, ver, intf);
} else {
ret = bic_get_exp_cpld_ver(slot_id, fw_comp, ver, 0/*bus 0*/, 0x80/*8-bit addr*/, intf);
}
}
break;
case FW_BB_CPLD:
ret = bic_get_cpld_ver(slot_id, fw_comp, ver, 0/*bus 0*/, 0x80/*8-bit addr*/, intf);
break;
}
return ret;
}
// OEM - Get Firmware Version
// Netfn: 0x38, Cmd: 0x0B
static int
_bic_get_vr_vendor_fw_ver(uint8_t slot_id, uint8_t fw_comp, uint8_t *ver, uint8_t intf, uint8_t *rlen) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, fw_comp}; //IANA ID + FW_COMP
uint8_t rbuf[16] = {0x00};
int ret = BIC_STATUS_FAILURE;
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_FW_VER, tbuf, 4, rbuf, rlen, intf);
if ( ret < 0 || *rlen < 4 ) {
syslog(LOG_ERR, "%s: ret: %d, rlen: %d, slot_id:%x, intf:%x\n", __func__, ret, *rlen, slot_id, intf);
} else {
//Ignore IANA ID
*rlen = *rlen - 3;
memcpy(ver, &rbuf[3], *rlen);
ret = BIC_STATUS_SUCCESS;
}
return ret;
}
int
bic_get_vr_vendor_fw_ver(uint8_t slot_id, uint8_t comp, uint8_t *ver, uint8_t *rlen) {
uint8_t fw_comp = 0x0;
uint8_t intf = 0x0;
int ret = BIC_STATUS_FAILURE;
//get the component
switch(comp) {
case FW_CWC_PESW_VR:
case FW_GPV3_TOP_PESW_VR:
case FW_GPV3_BOT_PESW_VR:
fw_comp = FW_2OU_PESW_VR;
break;
case FW_2U_TOP_3V3_VR1:
case FW_2U_BOT_3V3_VR1:
fw_comp = FW_2OU_3V3_VR1;
break;
case FW_2U_TOP_3V3_VR2:
case FW_2U_BOT_3V3_VR2:
fw_comp = FW_2OU_3V3_VR2;
break;
case FW_2U_TOP_3V3_VR3:
case FW_2U_BOT_3V3_VR3:
fw_comp = FW_2OU_3V3_VR3;
break;
case FW_2U_TOP_1V8_VR:
case FW_2U_BOT_1V8_VR:
fw_comp = FW_2OU_1V8_VR;
break;
default:
fw_comp = comp;
break;
}
// get the intf
switch (comp) {
case FW_2OU_3V3_VR1:
case FW_2OU_3V3_VR2:
case FW_2OU_3V3_VR3:
case FW_2OU_1V8_VR:
case FW_2OU_PESW_VR:
case FW_CWC_PESW_VR:
intf = REXP_BIC_INTF;
break;
case FW_GPV3_TOP_PESW_VR:
case FW_2U_TOP_3V3_VR1:
case FW_2U_TOP_3V3_VR2:
case FW_2U_TOP_3V3_VR3:
case FW_2U_TOP_1V8_VR:
intf = RREXP_BIC_INTF1;
break;
case FW_GPV3_BOT_PESW_VR:
case FW_2U_BOT_3V3_VR1:
case FW_2U_BOT_3V3_VR2:
case FW_2U_BOT_3V3_VR3:
case FW_2U_BOT_1V8_VR:
intf = RREXP_BIC_INTF2;
break;
}
// run cmd
switch (comp) {
case FW_2OU_3V3_VR1:
case FW_2OU_3V3_VR2:
case FW_2OU_3V3_VR3:
case FW_2OU_1V8_VR:
case FW_2OU_PESW_VR:
case FW_CWC_PESW_VR:
case FW_GPV3_TOP_PESW_VR:
case FW_GPV3_BOT_PESW_VR:
case FW_2U_TOP_3V3_VR1:
case FW_2U_TOP_3V3_VR2:
case FW_2U_TOP_3V3_VR3:
case FW_2U_TOP_1V8_VR:
case FW_2U_BOT_3V3_VR1:
case FW_2U_BOT_3V3_VR2:
case FW_2U_BOT_3V3_VR3:
case FW_2U_BOT_1V8_VR:
ret = _bic_get_vr_vendor_fw_ver(slot_id, fw_comp, ver, intf, rlen);
break;
}
return ret;
}
uint8_t
get_gpv3_bus_number(uint8_t dev_id) {
switch(dev_id) {
case FW_2OU_M2_DEV0:
case FW_2OU_M2_DEV1:
case DEV_ID0_2OU:
case DEV_ID1_2OU:
return 0x2;
case FW_2OU_M2_DEV2:
case FW_2OU_M2_DEV3:
case DEV_ID2_2OU:
case DEV_ID3_2OU:
return 0x4;
case FW_2OU_M2_DEV4:
case FW_2OU_M2_DEV5:
case DEV_ID4_2OU:
case DEV_ID5_2OU:
return 0x6;
case FW_2OU_M2_DEV6:
case FW_2OU_M2_DEV7:
case DEV_ID6_2OU:
case DEV_ID7_2OU:
return 0x5;
case FW_2OU_M2_DEV8:
case FW_2OU_M2_DEV9:
case DEV_ID8_2OU:
case DEV_ID9_2OU:
return 0x7;
case FW_2OU_M2_DEV10:
case FW_2OU_M2_DEV11:
case DEV_ID10_2OU:
case DEV_ID11_2OU:
return 0x3;
case DEV_ID12_2OU:
case DEV_ID13_2OU:
return 0x9;
}
return 0xff;
}
uint8_t
get_gpv3_channel_number(uint8_t dev_id) {
switch(dev_id) {
case FW_2OU_M2_DEV0:
case FW_2OU_M2_DEV2:
case FW_2OU_M2_DEV4:
case FW_2OU_M2_DEV6:
case FW_2OU_M2_DEV8:
case FW_2OU_M2_DEV10:
case DEV_ID0_2OU:
case DEV_ID2_2OU:
case DEV_ID4_2OU:
case DEV_ID6_2OU:
case DEV_ID8_2OU:
case DEV_ID10_2OU:
return 0x0;
case FW_2OU_M2_DEV1:
case FW_2OU_M2_DEV3:
case FW_2OU_M2_DEV5:
case FW_2OU_M2_DEV7:
case FW_2OU_M2_DEV9:
case FW_2OU_M2_DEV11:
case DEV_ID1_2OU:
case DEV_ID3_2OU:
case DEV_ID5_2OU:
case DEV_ID7_2OU:
case DEV_ID9_2OU:
case DEV_ID11_2OU:
return 0x1;
case DEV_ID12_2OU: // E1.S A
return 0x4;
case DEV_ID13_2OU: // E1.S B
return 0x8;
}
return 0xff;
}
int
bic_enable_vr_fault_monitor(uint8_t slot_id, bool enable, uint8_t intf) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, ( enable == true )?0x1:0x0};
uint8_t tlen = 4;
uint8_t rbuf[24] = {0};
uint8_t rlen = 0;
return bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_BIC_VR_MONITOR, tbuf, tlen, rbuf, &rlen, intf);
}
int
bic_get_gpv3_pci_link(uint8_t slot_id, uint8_t *rbuf, uint8_t *rlen, uint8_t intf) {
uint8_t tbuf[3] = {0x9c, 0x9c, 0x00};
uint8_t tlen = 3;
return bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_PCI_LINK_STATUS, tbuf, tlen, rbuf, rlen, intf);
}
int
bic_enable_ssd_sensor_monitor(uint8_t slot_id, bool enable, uint8_t intf) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, ( enable == true )?0x1:0x0};
uint8_t tlen = 4;
uint8_t rbuf[16] = {0};
uint8_t rlen = 0;
return bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_BIC_SNR_MONITOR, tbuf, tlen, rbuf, &rlen, intf);
}
int
bic_get_1ou_type(uint8_t slot_id, uint8_t *type) {
uint8_t tbuf[3] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[16] = {0};
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
int val = 0;
snprintf(key, sizeof(key), KV_SLOT_GET_1OU_TYPE, slot_id);
while (retry < 3) {
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_BOARD_ID, tbuf, 3, rbuf, &rlen, FEXP_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret == 0) {
*type = rbuf[3];
val = *type;
} else {
syslog(LOG_WARNING, "[%s] fail at slot%d", __func__, slot_id);
val = ret;
}
snprintf(tmp_str, sizeof(tmp_str), "%d", val);
kv_set(key, tmp_str, 0, 0);
return ret;
}
int
bic_get_1ou_type_cache(uint8_t slot_id, uint8_t *type) {
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
int val = 0;
snprintf(key, sizeof(key), KV_SLOT_GET_1OU_TYPE, slot_id);
if (kv_get(key, tmp_str, NULL, 0))
return -1;
val = atoi(tmp_str);
if (val < 0 || val > 255)
return -1;
*type = val;
return 0;
}
int
bic_set_amber_led(uint8_t slot_id, uint8_t dev_id, uint8_t status) {
uint8_t tbuf[5] = {0x9c, 0x9c, 0x00, 0x00, 0x00};
uint8_t rbuf[2] = {0};
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[3] = dev_id; // 0'base
tbuf[4] = status; // 0->off, 1->on
while (retry < 3) {
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_SET_AMBER_LED, tbuf, 5, rbuf, &rlen, FEXP_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
syslog(LOG_WARNING, "[%s] fail at slot%u dev%u", __func__, slot_id, dev_id);
}
return ret;
}
int
bic_get_amber_led_status(uint8_t slot_id, uint8_t dev_id, uint8_t *status) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, 0x00};
uint8_t rbuf[4] = {0};
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[3] = dev_id; // 0'base
while (retry < 3) {
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_AMBER_LED_STATUS, tbuf, 4, rbuf, &rlen, FEXP_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
syslog(LOG_WARNING, "[%s] fail at slot%u dev%u", __func__, slot_id, dev_id);
} else {
*status = rbuf[3];
}
return ret;
}
int
bic_spe_led_ctrl(uint8_t dev_id, uint8_t option, uint8_t* status) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x9c, 0x9c, 0x00, 0x00, 0x00};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
if (status == NULL) {
syslog(LOG_WARNING, "%s() status is missing", __func__);
return -1;
}
tbuf[3] = dev_id - DEV_ID0_2OU;
tbuf[4] = option;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_SET_AMBER_LED, tbuf, 5, rbuf, &rlen, REXP_BIC_INTF);
if (ret == 0) {
break;
}
retry++;
}
if (ret != 0) {
syslog(LOG_WARNING, "%s() fail at dev%u", __func__, dev_id);
}
if (option == GET_LED_STAT) {
if (rlen != 4) {
syslog(LOG_WARNING, "%s() failed to get LED status, rlen = %d", __func__, rlen);
return -1;
}
// byte 0~2: IANA ID
// byte 3: status
*status = rbuf[3];
}
return ret;
}
// OEM - Get Post Code buffer
// Netfn: 0x38, Cmd: 0x12
int
bic_get_80port_record(uint8_t slot_id, uint8_t *rbuf, uint8_t *rlen, uint8_t intf) {
int ret = 0;
uint8_t tbuf[3] = {0};
uint8_t tlen = sizeof(tbuf);
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_POST_BUF, tbuf, tlen, rbuf, rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "[%s] Cannot get the postcode buffer from slot%d", __func__, slot_id);
} else {
*rlen -= 3;
memmove(rbuf, &rbuf[3], *rlen);
}
return ret;
}
// Custom Command for getting cpld version
int
bic_get_cpld_ver(uint8_t slot_id, uint8_t comp, uint8_t *ver, uint8_t bus, uint8_t addr, uint8_t intf) {
uint8_t tbuf[32] = {0};
uint8_t rbuf[4] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
const uint32_t reg = 0x00200028; //for altera cpld
tbuf[0] = (bus << 1) + 1;
tbuf[1] = addr;
tbuf[2] = 0x04; //read back 4 bytes
tbuf[3] = (reg >> 24) & 0xff;
tbuf[4] = (reg >> 16) & 0xff;
tbuf[5] = (reg >> 8) & 0xff;
tbuf[6] = (reg >> 0) & 0xff;
tlen = 7;
int ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
for (int i = 0; i < rlen; i++) ver[i] = rbuf[3-i];
return ret;
}
// Custom Command for getting vr version/device id
int
bic_get_vr_device_id(uint8_t slot_id, uint8_t comp, uint8_t *rbuf, uint8_t *rlen, uint8_t bus, uint8_t addr, uint8_t intf) {
uint8_t tbuf[32] = {0};
uint8_t tlen = 0;
int ret = 0;
tbuf[0] = (bus << 1) + 1;
tbuf[1] = addr;
tbuf[2] = 0x07; //read back 7 bytes
tbuf[3] = 0xAD; //get device id command
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to get vr device id, ret=%d", __func__, ret);
} else {
*rlen = rbuf[0];//read cnt
memmove(rbuf, &rbuf[1], *rlen);
}
return ret;
}
int
bic_get_ifx_vr_remaining_writes(uint8_t slot_id, uint8_t bus, uint8_t addr, uint8_t *writes, uint8_t intf) {
#define REMAINING_TIMES(x) (((x[1] << 8) + x[0]) & 0xFC0) >> 6
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = 0;
tbuf[0] = (bus << 1) + 1;
tbuf[1] = addr;
tbuf[2] = 0x00; //read cnt
tbuf[3] = VR_PAGE;
tbuf[4] = VR_PAGE50;
tlen = 5;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Couldn't set page to 0x%02X", __func__, tbuf[4]);
goto error_exit;
}
tbuf[2] = 0x02; //read cnt
tbuf[3] = 0x82;
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Couldn't get data from 0x%02X", __func__, tbuf[3]);
goto error_exit;
}
*writes = REMAINING_TIMES(rbuf);
error_exit:
return ret;
}
int
bic_get_isl_vr_remaining_writes(uint8_t slot_id, uint8_t bus, uint8_t addr, uint8_t *writes, uint8_t intf) {
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = 0;
tbuf[0] = (bus << 1) + 1;
tbuf[1] = addr;
tbuf[2] = 0x00; //read cnt
tbuf[3] = 0xC7; //command code
tbuf[4] = 0xC2; //data1
tbuf[5] = 0x00; //data2
tlen = 6;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to send command and data...", __func__);
goto error_exit;
}
tbuf[2] = 0x04; //read cnt
tbuf[3] = 0xC5; //command code
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to read NVM slots...", __func__);
goto error_exit;
}
*writes = rbuf[0];
error_exit:
return ret;
}
int
bic_get_vr_ver(uint8_t slot_id, uint8_t intf, uint8_t bus, uint8_t addr, char *key, char *ver_str) {
uint8_t tbuf[32] = {0};
uint8_t tlen = 0;
uint8_t rbuf[32] = {0};
uint8_t rlen = 0;
uint8_t remaining_writes = 0;
char path[128];
int fd = 0;
int ret = 0, rc = 0;
ret = bic_get_vr_device_id(slot_id, 0, rbuf, &rlen, bus, addr, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to get vr device id, ret=%d", __func__, ret);
return ret;
}
tbuf[0] = (bus << 1) + 1;
tbuf[1] = addr;
//The length of GET_DEVICE_ID is different.
if ( rlen == 2 ) {
//Infineon
//to avoid sensord changing the page of VRs, so use the LOCK file
//to stop monitoring sensors of VRs
sprintf(path, SLOT_SENSOR_LOCK, slot_id);
fd = open(path, O_CREAT | O_RDWR, 0666);
rc = flock(fd, LOCK_EX | LOCK_NB);
if(rc) {
if(EWOULDBLOCK == errno) {
return -1;
}
}
//get the remaining writes of VRs
ret = bic_get_ifx_vr_remaining_writes(slot_id, bus, addr, &remaining_writes, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr remaining writes. ret=%d", __func__,__LINE__, ret);
goto error_exit;
}
//get the CRC32 of the VR
tbuf[2] = 0x00; //read cnt
tbuf[3] = 0x00; //command code
tbuf[4] = 0x62;
tlen = 5;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr ver. ret=%d", __func__,__LINE__, ret);
goto error_exit;
}
tbuf[2] = 0x2; //read cnt
tbuf[3] = 0x42; //command code
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr ver. ret=%d", __func__,__LINE__, ret);
goto error_exit;
}
tbuf[2] = 0x2; //read cnt
tbuf[3] = 0x43; //command code
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, &rbuf[2], &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr ver. ret=%d", __func__,__LINE__, ret);
goto error_exit;
}
snprintf(ver_str, MAX_VALUE_LEN, "Infineon %02X%02X%02X%02X, Remaining Writes: %d", rbuf[3], rbuf[2], rbuf[1], rbuf[0], remaining_writes);
kv_set(key, ver_str, 0, 0);
error_exit:
rc = flock(fd, LOCK_UN);
if (rc == -1) {
syslog(LOG_WARNING, "%s: failed to unflock on %s", __func__, path);
close(fd);
return rc;
}
close(fd);
remove(path);
return ret;
} else if ( rlen > 4 ) {
//TI
tbuf[2] = 0x02; //read cnt
tbuf[3] = 0xF0; //command code
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr ver. ret=%d", __func__,__LINE__, ret);
return ret;
}
snprintf(ver_str, MAX_VALUE_LEN, "Texas Instruments %02X%02X", rbuf[1], rbuf[0]);
kv_set(key, ver_str, 0, 0);
} else {
//ISL
//get the reamaining write
ret = bic_get_isl_vr_remaining_writes(slot_id, bus, addr, &remaining_writes, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr remaining writes. ret=%d", __func__,__LINE__, ret);
goto error_exit;
}
//get the CRC32 of the VR
tbuf[2] = 0x00; //read cnt
tbuf[3] = 0xC7; //command code
tbuf[4] = 0x3F; //reg
tbuf[5] = 0x00; //dummy data
tlen = 6;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr ver. ret=%d", __func__,__LINE__, ret);
return ret;
}
tbuf[2] = 0x04; //read cnt
tbuf[3] = 0xC5; //command code
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to get vr ver. ret=%d", __func__,__LINE__, ret);
return ret;
}
snprintf(ver_str, MAX_VALUE_LEN, "Renesas %02X%02X%02X%02X, Remaining Writes: %d", rbuf[3], rbuf[2], rbuf[1], rbuf[0], remaining_writes);
kv_set(key, ver_str, 0, 0);
}
return ret;
}
int
bic_get_vr_ver_cache(uint8_t slot_id, uint8_t intf, uint8_t bus, uint8_t addr, char *ver_str) {
char key[MAX_KEY_LEN], tmp_str[MAX_VALUE_LEN] = {0};
snprintf(key, sizeof(key), "slot%x_vr_%02xh_crc", slot_id, addr);
if (kv_get(key, tmp_str, NULL, 0)) {
if (bic_get_vr_ver(slot_id, intf, bus, addr, key, tmp_str))
return -1;
}
if (snprintf(ver_str, MAX_VER_STR_LEN, "%s", tmp_str) > (MAX_VER_STR_LEN-1))
return -1;
return 0;
}
int
bic_get_exp_cpld_ver(uint8_t slot_id, uint8_t comp, uint8_t *ver, uint8_t bus, uint8_t addr, uint8_t intf) {
uint8_t tbuf[32] = {0};
uint8_t rbuf[4] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = 0;
//mux
tbuf[0] = (bus << 1) + 1; //bus
tbuf[1] = 0xE2; //mux addr
tbuf[2] = 0x00;
tbuf[3] = 0x02;
tlen = 4;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to send the command to switch the mux. ret=%d", __func__, ret);
goto error_exit;
}
//read cpld
tbuf[1] = addr;
tbuf[2] = 0x04; //read cnt
tbuf[3] = 0xC0; //data 1
tbuf[4] = 0x00; //data 2
tbuf[5] = 0x00; //data 3
tbuf[6] = 0x00; //data 4
tlen = 7;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, ver, &rlen, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to send the command code to get cpld ver. ret=%d", __func__, ret);
}
error_exit:
return ret;
}
int
bic_is_m2_exp_prsnt(uint8_t slot_id) {
uint8_t tbuf[4] = {0};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t tlen = 4;
uint8_t rlen = 0;
int ret = 0;
int present = 0;
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
int val = 0;
snprintf(key, sizeof(key), KV_SLOT_IS_M2_EXP_PRESENT, slot_id);
if (kv_get(key, tmp_str, NULL, 0)) {
// get form bic
tbuf[0] = 0x05; //bus id
tbuf[1] = 0x42; //slave addr
tbuf[2] = 0x01; //read 1 byte
tbuf[3] = 0x0D; //register offset
ret = bic_ipmb_wrapper(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
present = rbuf[0] & 0xC;
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to get expansion present status. ret=%d", __func__, ret);
return ret;
} else {
if ( present == 0) {
val = 3; //1OU+2OU present
} else if ( present == 8) {
val = 1; //1OU present
} else if ( present == 4) {
val = 2; //2OU present
}
}
snprintf(tmp_str, sizeof(tmp_str), "%d", val);
kv_set(key, tmp_str, 0, 0);
return val;
} else {
// get from cache
val = atoi(tmp_str);
return val;
}
}
int
bic_is_m2_exp_prsnt_cache(uint8_t slot_id) {
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
int val = 0;
snprintf(key, sizeof(key), KV_SLOT_IS_M2_EXP_PRESENT, slot_id);
if (kv_get(key, tmp_str, NULL, 0))
return -1;
val = atoi(tmp_str);
return val;
}
int
bic_is_2u_top_bot_prsnt(uint8_t slot_id) {
#define REG_CWC_CPLD_GPV3_PRSNT 0x04
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
int val = 0;
snprintf(key, sizeof(key), KV_SLOT_IS_2U_TOPBOT_PRESENT, slot_id);
if (kv_get(key, tmp_str, NULL, 0)) {
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(FRU_SLOT1 + SLOT_BUS_BASE, 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_PRSNT;
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 & 0x03) == 0 ) {
val |= PRESENT_2U_TOP;
}
if ( (rbuf & 0x0C) == 0 ) {
val |= PRESENT_2U_BOT;
}
}
if ( i2cfd > 0 ) {
close(i2cfd);
}
snprintf(tmp_str, sizeof(tmp_str), "%d", val);
kv_set(key, tmp_str, 0, 0);
return val;
} else {
// get from cache
val = atoi(tmp_str);
return val;
}
}
int
bic_is_2u_top_bot_prsnt_cache(uint8_t slot_id) {
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
int val = 0;
snprintf(key, sizeof(key), KV_SLOT_IS_2U_TOPBOT_PRESENT, slot_id);
if (kv_get(key, tmp_str, NULL, 0))
return -1;
val = atoi(tmp_str);
return val;
}
/*
0x2E 0xDF: Force Intel ME Recovery
Request
Byte 1:3 = Intel Manufacturer ID - 000157h, LS byte first.
Byte 4 - Command
= 01h Restart using Recovery Firmware
(Intel ME FW configuration is not restored to factory defaults)
= 02h Restore Factory Default Variable values and restart the Intel ME FW
= 03h PTT Initial State Restore
Response
Byte 1 - Completion Code
= 00h - Success
(Remaining standard Completion Codes are shown in Section 2.12)
= 81h - Unsupported Command parameter value in the Byte 4 of the request.
Byte 2:4 = Intel Manufacturer ID - 000157h, LS byte first.
*/
int
me_recovery(uint8_t slot_id, uint8_t command) {
uint8_t tbuf[256] = {0x00};
uint8_t rbuf[256] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
while (retry <= RETRY_3_TIME) {
tbuf[0] = 0xB8;
tbuf[1] = 0xDF;
tbuf[2] = 0x57;
tbuf[3] = 0x01;
tbuf[4] = 0x00;
tbuf[5] = command;
tlen = 6;
ret = bic_me_xmit(slot_id, tbuf, tlen, rbuf, &rlen);
if (ret) {
retry++;
sleep(1);
continue;
}
else
break;
}
if (retry > RETRY_3_TIME) { //if the third retry still failed, return -1
syslog(LOG_CRIT, "%s: Restart using Recovery Firmware failed..., retried: %d", __func__, retry);
return -1;
}
sleep(10);
retry = 0;
memset(&tbuf, 0, 256);
memset(&rbuf, 0, 256);
/*
0x6 0x4: Get Self-Test Results
Byte 1 - Completion Code
Byte 2
= 55h - No error. All Self-Tests Passed.
= 81h - Firmware entered Recovery bootloader mode
Byte 3 For byte 2 = 55h, 56h, FFh:
=00h
=02h - recovery mode entered by IPMI command "Force ME Recovery"
*/
//Using ME self-test result to check if the ME Recovery Command Success or not
while (retry <= RETRY_3_TIME) {
tbuf[0] = 0x18;
tbuf[1] = 0x04;
tlen = 2;
ret = bic_me_xmit(slot_id, tbuf, tlen, rbuf, &rlen);
if (ret) {
retry++;
sleep(1);
continue;
}
//if Get Self-Test Results is 0x55 0x00, means No error. All Self-Tests Passed.
//if Get Self-Test Results is 0x81 0x02, means Firmware entered Recovery bootloader mode
if ( (command == RECOVERY_MODE) && (rbuf[1] == 0x81) && (rbuf[2] == 0x02) ) {
return 0;
}
else if ( (command == RESTORE_FACTORY_DEFAULT) && (rbuf[1] == 0x55) && (rbuf[2] == 0x00) ) {
return 0;
}
else {
return -1;
}
}
if (retry > RETRY_3_TIME) { //if the third retry still failed, return -1
syslog(LOG_CRIT, "%s: Restore Factory Default failed..., retried: %d", __func__, retry);
return -1;
}
return 0;
}
int
me_reset(uint8_t slot_id) {
uint8_t tbuf[2] = {0x00};
uint8_t rbuf[2] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
while (retry <= RETRY_3_TIME) {
tbuf[0] = 0x18;
tbuf[1] = 0x02;
tlen = 2;
ret = bic_me_xmit(slot_id, tbuf, tlen, rbuf, &rlen);
if (ret) {
retry++;
sleep(1);
continue;
}
break;
}
if (retry > RETRY_3_TIME) { //if the third retry still failed, return -1
syslog(LOG_CRIT, "%s: ME Reset failed..., retried: %d", __func__, retry);
return -1;
}
return 0;
}
int
bic_switch_mux_for_bios_spi(uint8_t slot_id, uint8_t mux) {
uint8_t tbuf[5] = {0};
uint8_t rbuf[1] = {0};
uint8_t tlen = 5;
uint8_t rlen = 0;
int ret = 0;
tbuf[0] = 0x05; //bus id
tbuf[1] = 0x42; //slave addr
tbuf[2] = 0x01; //read 1 byte
tbuf[3] = 0x00; //register offset
tbuf[4] = mux; //mux setting
ret = bic_ipmb_wrapper(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
if ( ret < 0 ) {
return -1;
}
return 0;
}
int
bic_asd_init(uint8_t slot_id, uint8_t cmd) {
uint8_t tbuf[4] = {0x00};
uint8_t rbuf[8] = {0x00};
uint8_t tlen = 4;
uint8_t rlen = 0;
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = cmd;
return bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_ASD_INIT, tbuf, tlen, rbuf, &rlen);
}
int
bic_get_gpio_config(uint8_t slot_id, uint8_t gpio, uint8_t *data) {
uint8_t tbuf[13] = {0x00};
uint8_t rbuf[6] = {0x00};
uint8_t rlen = 0;
uint8_t tlen = sizeof(tbuf);
uint8_t index = 0;
uint8_t pin = 0;
int ret = 0;
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
//get the buffer index
index = (gpio / 8) + 3; //3 is the size of IANA ID
pin = 1 << (gpio % 8);
tbuf[index] = pin;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO_CONFIG, tbuf, tlen, rbuf, &rlen);
*data = rbuf[3];
return ret;
}
int
remote_bic_get_gpio_config(uint8_t slot_id, uint8_t gpio, uint8_t *data, uint8_t intf) {
uint8_t tbuf[16] = {0x00};
uint8_t rbuf[6] = {0x00};
uint8_t rlen = 0;
uint8_t tlen = sizeof(tbuf);
uint8_t index = 0;
uint8_t pin = 0;
int ret = 0;
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
//get the buffer index
index = (gpio / 8) + 3; //3 is the size of IANA ID
pin = 1 << (gpio % 8);
tbuf[index] = pin;
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO_CONFIG, tbuf, tlen, rbuf, &rlen, intf);
*data = rbuf[3];
return ret;
}
int
bic_set_gpio_config(uint8_t slot_id, uint8_t gpio, uint8_t data) {
uint8_t tbuf[15] = {0x00};
uint8_t rbuf[6] = {0x00};
uint8_t rlen = 0;
uint8_t tlen = sizeof(tbuf);
uint8_t index = 0;
uint8_t pin = 0;
int ret = 0;
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
//get the buffer index
index = (gpio / 8) + 3; //3 is the size of IANA ID
pin = 1 << (gpio % 8);
tbuf[index] = pin;
tbuf[14] = data & 0x1f;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_SET_GPIO_CONFIG, tbuf, tlen, rbuf, &rlen);
return ret;
}
int
remote_bic_set_gpio_config(uint8_t slot_id, uint8_t gpio, uint8_t data, uint8_t intf) {
uint8_t tbuf[17] = {0x00};
uint8_t rbuf[6] = {0x00};
uint8_t rlen = 0;
uint8_t tlen = sizeof(tbuf);
uint8_t index = 0;
uint8_t pin = 0;
int ret = 0;
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
//get the buffer index
index = (gpio / 8) + 3; //3 is the size of IANA ID
pin = 1 << (gpio % 8);
tbuf[index] = pin;
tbuf[16] = data & 0x1f;
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_SET_GPIO_CONFIG, tbuf, tlen, rbuf, &rlen, intf);
return ret;
}
int
bic_set_gpio(uint8_t slot_id, uint8_t gpio_num, uint8_t value) {
uint8_t tbuf[6] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[1] = {0};
uint8_t tlen = 6;
uint8_t rlen = 0;
int ret = 0;
tbuf[3] = 0x01;
tbuf[4] = gpio_num;
tbuf[5] = value;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_SET_GPIO, tbuf, tlen, rbuf, &rlen);
if ( ret < 0 ) {
return -1;
}
return 0;
}
int
remote_bic_set_gpio(uint8_t slot_id, uint8_t gpio_num, uint8_t value, uint8_t intf) {
uint8_t tbuf[6] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[1] = {0};
uint8_t tlen = 6;
uint8_t rlen = 0;
int ret = 0;
tbuf[3] = 0x01;
tbuf[4] = gpio_num;
tbuf[5] = value;
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_SET_GPIO, tbuf, tlen, rbuf, &rlen, intf);
if ( ret < 0 ) {
return -1;
}
return 0;
}
// Get all GPIO pin status
int
bic_get_gpio(uint8_t slot_id, bic_gpio_t *gpio, uint8_t intf) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[13] = {0x00};
uint8_t rlen = 0;
int ret;
memset(gpio, 0, sizeof(*gpio));
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO, tbuf, 3, rbuf, &rlen, intf);
if (ret != 0 || rlen < 3)
return -1;
rlen -= 3;
if (rlen > sizeof(bic_gpio_t))
rlen = sizeof(bic_gpio_t);
// Ignore first 3 bytes of IANA ID
memcpy((uint8_t*) gpio, &rbuf[3], rlen);
#ifdef ENABLE_INJECTION
// After getting the real values, check for injected vals
uint32_t i, bmask;
int fd, flen;
char fpath[30], fdata;
for (i = 0; i < MAX_GPIO_PINS; i++) {
sprintf(fpath, GPIO_FALSE_DIR, slot_id, i);
if (!access(fpath, F_OK)) {
fd = open(fpath, O_RDONLY);
if (fd == -1) {
syslog(LOG_WARNING, "Could not open bic injection file for gpio %d", i);
return -1;
}
flen = read(fd, &fdata, 1);
if (flen == 0) {
close(fd);
return -1;
}
int fret = close(fd);
if (fret) {
syslog(LOG_WARNING, "Failed to close bic injection file for gpio %d", i);
return -1;
}
// First set the bit to 0
bmask = 1 << (i % 32);
gpio->gpio[i/32] &= ~bmask;
// Now we can change it to whatever we want
gpio->gpio[i/32] |= (((fdata - 0x30) & 0x1) << (i % 32));
syslog(LOG_INFO, "Injected %d into gpio %d at slot %d", (fdata - 0x30), i, slot_id);
}
}
#endif // ENABLE_INJECITON
return ret;
}
// Get an GPIO pin status
int
bic_get_one_gpio_status(uint8_t slot_id, uint8_t gpio_num, uint8_t *value){
uint8_t tbuf[5] = {0x00};
uint8_t rbuf[5] = {0x00};
uint8_t tlen = 5;
uint8_t rlen = 0;
int ret = 0;
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = 0x00;
tbuf[4] = gpio_num;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_SET_GPIO, tbuf, tlen, rbuf, &rlen);
*value = rbuf[4] & 0x01;
return ret;
}
int
bic_get_sys_guid(uint8_t slot_id, uint8_t *guid) {
int ret;
uint8_t rlen = 0;
ret = bic_ipmb_wrapper(slot_id, NETFN_APP_REQ, CMD_APP_GET_SYSTEM_GUID, NULL, 0, guid, &rlen);
if (rlen != SIZE_SYS_GUID) {
#ifdef DEBUG
syslog(LOG_ERR, "bic_get_sys_guid: returned rlen of %d\n");
#endif
return -1;
}
return ret;
}
int
bic_set_sys_guid(uint8_t slot_id, uint8_t *guid) {
int ret;
uint8_t rlen = 0;
uint8_t rbuf[MAX_IPMB_RES_LEN]={0x00};
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_REQ, CMD_OEM_SET_SYSTEM_GUID, guid, SIZE_SYS_GUID, rbuf, &rlen);
return ret;
}
int
bic_do_sled_cycle(uint8_t slot_id) {
uint8_t tbuf[4] = {0};
uint8_t tlen = 4;
tbuf[0] = 0x05; //bus id
tbuf[1] = 0x80; //slave addr
tbuf[2] = 0x00; //read 0 byte
tbuf[3] = 0xd9; //register offset
tlen = 4;
return bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, NULL, 0, BB_BIC_INTF);
}
// Only For Class 2
int
bic_set_fan_auto_mode(uint8_t crtl, uint8_t *status) {
uint8_t tbuf[1] = {0};
uint8_t rbuf[1] = {0};
uint8_t tlen = 1;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[0] = crtl;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_REQ, BIC_CMD_OEM_FAN_CTRL_STAT, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
return -1;
}
*status = rbuf[0];
return 0;
}
// Only For Class 2
int
bic_set_fan_speed(uint8_t fan_id, uint8_t pwm) {
uint8_t tbuf[5] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[1] = {0};
uint8_t tlen = 5;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[3] = fan_id;
tbuf[4] = pwm;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_BMC_FAN_CTRL, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if ( ret == 0 ) break;
retry++;
}
if (ret != 0) {
return -1;
}
return 0;
}
// Only For Class 2
int
bic_manual_set_fan_speed(uint8_t fan_id, uint8_t pwm) {
uint8_t tbuf[2] = {0};
uint8_t rbuf[1] = {0};
uint8_t tlen = 2;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[0] = fan_id;
tbuf[1] = pwm;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_REQ, BIC_CMD_OEM_SET_FAN_DUTY, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
return -1;
}
return 0;
}
// Only For Class 2
int
bic_get_fan_speed(uint8_t fan_id, float *value) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[5] = {0};
uint8_t tlen = 4;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[3] = fan_id;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_FAN_RPM, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
return -1;
}
*value = (float)((rbuf[3] << 8)+ rbuf[4]);
return 0;
}
// Only For Class 2
int
bic_get_fan_pwm(uint8_t fan_id, float *value) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[4] = {0};
uint8_t tlen = 4;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
tbuf[3] = fan_id;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_FAN_DUTY, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
return -1;
}
*value = (float)rbuf[3];
return 0;
}
// Only for class 2 system to get the power lock bit
int
bic_set_crit_act_flag(uint8_t dir_type) {
int ret = BIC_STATUS_SUCCESS;
uint8_t tbuf[5] = {CPLD_BB_BUS, CPLD_FLAG_REG_ADDR, 0x0/*read cnt*/, 0x10/*base reg*/, 0x0/*data*/};
uint8_t rbuf[5] = {0};
uint8_t tlen = 5;
uint8_t rlen = 0;
uint8_t mb_index = 0;
ret = bic_get_mb_index(&mb_index);
if (ret < 0) {
printf("Failed to get MB index\n");
return ret;
}
// set the register for the other side of BMC
tbuf[3] += (mb_index == FRU_SLOT1)?FRU_SLOT3:FRU_SLOT1;
// the default is high, so 0x00 means it's asserted
tbuf[4] = (dir_type == SEL_ASSERT)?0x00:0x01;
ret = bic_ipmb_send(FRU_SLOT1, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if ( ret < 0 ) {
printf("Failed to set power lock flag\n");
}
return ret;
}
int
bic_get_dev_info(uint8_t slot_id, uint8_t dev_id, uint8_t *nvme_ready, uint8_t *status, uint8_t *type) {
int ret = 0;
uint8_t retry = MAX_READ_RETRY;
uint16_t vendor_id = 0, reversed_vender_sph = 0;
uint8_t ffi = 0 ,meff = 0 ,major_ver = 0, minor_ver = 0;
uint8_t type_2ou = UNKNOWN_BOARD;
if (slot_id == FRU_2U_TOP || slot_id == FRU_2U_BOT) {
type_2ou = CWC_MCHP_BOARD;
} else {
ret = bic_is_m2_exp_prsnt(slot_id);
if (ret < 0) {
syslog(LOG_WARNING,"%s() Failed to get 1ou & 2ou present status", __func__);
goto err_out;
}
if ( (ret & PRESENT_2OU) != PRESENT_2OU ) {
syslog(LOG_WARNING,"%s() Cannot get 2ou board", __func__);
goto err_out;
}
ret = fby3_common_get_2ou_board_type(slot_id, &type_2ou);
if ( ret < 0 ) {
syslog(LOG_WARNING,"%s() Cannot get 2ou board type", __func__);
goto err_out;
}
}
if ( type_2ou == GPV3_MCHP_BOARD || type_2ou == GPV3_BRCM_BOARD || type_2ou == CWC_MCHP_BOARD ) {
while (retry) {
if (slot_id == FRU_2U_TOP) {
ret = bic_get_dev_power_status(FRU_SLOT1, dev_id, nvme_ready, status, &ffi, &meff,
&vendor_id, &major_ver,&minor_ver, RREXP_BIC_INTF1);
} else if (slot_id == FRU_2U_BOT) {
ret = bic_get_dev_power_status(FRU_SLOT1, dev_id, nvme_ready, status, &ffi, &meff,
&vendor_id, &major_ver,&minor_ver, RREXP_BIC_INTF2);
} else {
ret = bic_get_dev_power_status(slot_id, dev_id, nvme_ready, status, &ffi, &meff, &vendor_id, &major_ver,&minor_ver, REXP_BIC_INTF);
}
if (!ret)
break;
msleep(50);
retry--;
}
//syslog(LOG_WARNING, "bic_get_dev_power_status: dev_id %d nvme_ready %d status %d",dev_id, *nvme_ready, *status);
reversed_vender_sph = (((VENDOR_SPH << 8) & 0xFF00) | ((VENDOR_SPH >> 8) & 0x00FF));
if (*nvme_ready) {
if ( meff == MEFF_DUAL_M2 ) {
*type = DEV_TYPE_DUAL_M2;
} else{
if (ffi == FFI_ACCELERATOR) {
if (vendor_id == VENDOR_BRCM) {
*type = DEV_TYPE_BRCM_ACC;
} else if (vendor_id == VENDOR_SPH || vendor_id == reversed_vender_sph) {
*type = DEV_TYPE_SPH_ACC;
} else {
*type = DEV_TYPE_M2;
}
} else {
*type = DEV_TYPE_SSD;
}
}
} else {
*type = DEV_TYPE_UNKNOWN;
}
return 0;
}
err_out:
*type = DEV_TYPE_UNKNOWN;
return -1;
}
int
bic_get_dev_power_status(uint8_t slot_id, uint8_t dev_id, uint8_t *nvme_ready, uint8_t *status, \
uint8_t *ffi, uint8_t *meff, uint16_t *vendor_id, uint8_t *major_ver, uint8_t *minor_ver, uint8_t intf) {
uint8_t tbuf[5] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[11] = {0x00};
uint8_t tlen = 5;
uint8_t rlen = 0;
int ret = 0;
uint8_t table = 0, board_type = 0;
if (intf == FEXP_BIC_INTF) {
table = 1;
ret = bic_get_1ou_type(slot_id, &board_type);
if (ret < 0) {
syslog(LOG_ERR, "%s() Cannot get 1ou board_type", __func__);
board_type = M2_BOARD;
}
} else if (intf == REXP_BIC_INTF) {
table = 0;
ret = fby3_common_get_2ou_board_type(slot_id, &board_type);
if (ret < 0) {
syslog(LOG_ERR, "%s() Cannot get 2ou board_type", __func__);
board_type = M2_BOARD;
}
} else if (intf == RREXP_BIC_INTF1 || intf == RREXP_BIC_INTF2) {
board_type = M2_BOARD;
} else {
return -1;
}
//Send the command
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
if (board_type == EDSFF_1U) {
// case 1OU E1S
tbuf[3] = mapping_e1s_pwr[table][dev_id - 1];
} else if (board_type == E1S_BOARD) {
// case 2OU E1S
tbuf[3] = mapping_e1s_pwr[table][dev_id - 1] + 1; // device ID 1 based in power control
} else {
// case 1/2OU M.2
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
tbuf[3] = dev_id - DUAL_DEV_ID0_2OU + DUAL_DEV_BIC_ID0;
} else {
tbuf[3] = dev_id;
}
}
tbuf[4] = 0x3; //get power status
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_DEV_POWER, tbuf, tlen, rbuf, &rlen, intf);
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) { //dual m.2 sitauation, it will return two byte.
status[0] = rbuf[3];
status[1] = rbuf[4];
} else {
// Ignore first 3 bytes of IANA ID
*status = rbuf[3];
if (intf == REXP_BIC_INTF || intf == RREXP_BIC_INTF1 || intf == RREXP_BIC_INTF2) {
*nvme_ready = rbuf[4]; //1 is assigned directly. for REXP_EXP_INTF, we assige it from rbuf[4]
} else {
*nvme_ready = 0x1;
}
if ( ffi != NULL ) *ffi = rbuf[5]; // FFI_0 0:Storage 1:Accelerator
if ( meff != NULL ) *meff = rbuf[6]; // MEFF 0x35: M.2 22110 0xF0: Dual M.2
if ( vendor_id != NULL ) *vendor_id = (rbuf[7] << 8 ) | rbuf[8]; // PCIe Vendor ID
if ( major_ver != NULL ) *major_ver = rbuf[9]; //FW version Major Revision
if ( minor_ver != NULL ) *minor_ver = rbuf[10]; //FW version Minor Revision
}
return ret;
}
int
bic_set_dev_power_status(uint8_t slot_id, uint8_t dev_id, uint8_t status, uint8_t intf) {
uint8_t tbuf[5] = {0x00};
uint8_t rbuf[10] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
uint8_t bus_num = 0;
uint8_t table = 0, board_type = 0;
uint8_t prsnt_bit = 0;
int fd = 0;
int ret = 0;
do {
if (intf == FEXP_BIC_INTF) {
table = 1;
ret = bic_get_1ou_type(slot_id, &board_type);
if (ret < 0) {
syslog(LOG_ERR, "%s() Cannot get 1ou board_type", __func__);
board_type = M2_BOARD;
}
} else if (intf == REXP_BIC_INTF) {
table = 0;
ret = fby3_common_get_2ou_board_type(slot_id, &board_type);
if (ret < 0) {
syslog(LOG_ERR, "%s() Cannot get 2ou board_type", __func__);
board_type = M2_BOARD;
}
// No VPP and hotplug on GPv3, skip it
if ( board_type == GPV3_MCHP_BOARD || board_type == GPV3_BRCM_BOARD ) break;
} else if (intf == RREXP_BIC_INTF1 || intf == RREXP_BIC_INTF2) {
board_type = M2_BOARD;
break;
} else {
return -1;
}
bus_num = fby3_common_get_bus_id(slot_id) + 4;
//set the present status of M.2
fd = i2c_open(bus_num, CPLD_ADDRESS >> 1);
if ( fd < 0 ) {
printf("Cannot open /dev/i2c-%d\n", bus_num);
ret = BIC_STATUS_FAILURE;
goto error_exit;
}
tbuf[0] = (intf == REXP_BIC_INTF )?M2_REG_2OU:M2_REG_1OU;
tlen = 1;
rlen = 1;
ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDRESS, tbuf, tlen, rbuf, rlen);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d, ret", __func__, tlen);
goto error_exit;
}
if (board_type == EDSFF_1U || board_type == E1S_BOARD) {
// case 1/2OU E1S
prsnt_bit = mapping_e1s_prsnt[table][dev_id - 1];
} else {
// case 1/2OU M.2
prsnt_bit = mapping_m2_prsnt[table][dev_id - 1];
}
if ( status == M2_PWR_OFF ) {
tbuf[1] = (rbuf[0] | (0x1 << (prsnt_bit)));
} else {
tbuf[1] = (rbuf[0] & ~(0x1 << (prsnt_bit)));
}
tlen = 2;
rlen = 0;
ret = i2c_rdwr_msg_transfer(fd, CPLD_ADDRESS, tbuf, tlen, rbuf, rlen);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to do i2c_rdwr_msg_transfer, tlen=%d", __func__, tlen);
goto error_exit;
}
} while(0);
//Send the command
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
if (board_type == EDSFF_1U) {
// case 1OU E1S
tbuf[3] = mapping_e1s_pwr[table][dev_id - 1];
} else if (board_type == E1S_BOARD) {
// case 2OU E1S
tbuf[3] = mapping_e1s_pwr[table][dev_id - 1] + 1; // device ID 1 based in power control
} else {
// case 1/2OU M.2
if (dev_id >= DUAL_DEV_ID0_2OU && dev_id <= DUAL_DEV_ID5_2OU) {
tbuf[3] = dev_id - DUAL_DEV_ID0_2OU + DUAL_DEV_BIC_ID0;
} else {
tbuf[3] = dev_id;
}
}
tbuf[4] = status; //set power status
tlen = 5;
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_DEV_POWER, tbuf, tlen, rbuf, &rlen, intf);
error_exit:
if ( fd > 0 ) close(fd);
return ret;
}
int
bic_master_write_read(uint8_t slot_id, uint8_t bus, uint8_t addr, uint8_t *wbuf, uint8_t wcnt, uint8_t *rbuf, uint8_t rcnt) {
uint8_t tbuf[256];
uint8_t tlen = 3, rlen = 0;
int ret;
tbuf[0] = bus;
tbuf[1] = addr;
tbuf[2] = rcnt;
if (wcnt) {
memcpy(&tbuf[3], wbuf, wcnt);
tlen += wcnt;
}
ret = bic_ipmb_wrapper(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
return ret;
}
int
bic_usb_hub_reset(uint8_t slot_id, uint8_t board_type, uint8_t intf) {
uint8_t rst_list[] = {GPV3_GPIO_RST_USB_HUB1, GPV3_GPIO_RST_USB_HUB2, GPV3_GPIO_RST_USB_HUB3, CWC_GPIO_RST_USB_HUB, GPIO_RST_USB_HUB};
size_t st_idx = 0;
size_t end_idx = sizeof(rst_list);
int ret = BIC_STATUS_FAILURE;
// if intf is REXP_BIC_INTF and board_type is CWC_MCHP_BOARD
// rst seq: CWC HUB -> SB HUB
// else if intf is REXP_BIC_INTF
// rst seq: GPV3 HUB1/2/3 -> SB HUB
// else if intf is RREXP_BIC_INTF1 or RREXP_BIC_INTF2
// rst seq: GPV3 HUB1/2/3 -> CWC HUB -> SB HUB
if ( intf == REXP_BIC_INTF ) {
if ( board_type == CWC_MCHP_BOARD ) {
st_idx = 3;
} else {
// 2U config doesnt contain CWC
rst_list[3] = GPIO_RST_USB_HUB;
end_idx--;
}
} else if ( intf == RREXP_BIC_INTF1 || intf == RREXP_BIC_INTF2 ) {
// do nothing
} else {
syslog(LOG_WARNING, "intf(%02Xh) and board_type(%02Xh) are not supported\n", intf, board_type);
return ret;
}
// reset
printf("HUB reset...");
for ( size_t i = 0; i < 2; i++ ) {
for ( size_t j = st_idx; j < end_idx; j++ ) {
ret = remote_bic_set_gpio(slot_id, rst_list[j], i, intf);
if ( ret < 0 ) {
printf("Failed to reset USB HUB, pin#:%02zX, val:%02zuX, intf:%02X, board_type:%02X\n", rst_list[i], i, intf, board_type);
break;
}
if ( i == VALUE_HIGH ) msleep(500);
}
}
printf("Done\n");
return ret;
}
int
bic_reset(uint8_t slot_id, uint8_t intf) {
uint8_t tbuf[3] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[8] = {0x00};
uint8_t rlen = 0;
int ret = BIC_STATUS_FAILURE;
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_COLD_RESET, tbuf, 0, rbuf, &rlen, intf);
return ret;
}
int
bic_clear_cmos(uint8_t slot_id) {
uint8_t tbuf[3] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[8] = {0x00};
uint8_t rlen = 0;
return bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_CLEAR_CMOS, tbuf, 3, rbuf, &rlen);
}
// Only For Class 2
int
bic_inform_sled_cycle(void) {
uint8_t tbuf[3] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[1] = {0x00};
uint8_t tlen = 3;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
while (retry < 3) {
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_INFORM_SLED_CYCLE, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
return -1;
}
return 0;
}
// For Discovery Point, get pcie config
int
bic_get_dp_pcie_config(uint8_t slot_id, uint8_t *pcie_config) {
uint8_t tbuf[3] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[4] = {0x00};
uint8_t tlen = 3;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
while (retry < 3) {
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_PCIE_CONFIG, tbuf, tlen, rbuf, &rlen);
if (ret == 0) break;
retry++;
}
if (ret != 0) {
return -1;
}
(*pcie_config) = (rbuf[3] & 0x0f);
return 0;
}
// For class 2 system, BMC need to get MB index from BB BIC
int
bic_get_mb_index(uint8_t *index) {
GET_MB_INDEX_RESP resp = {0};
uint8_t rlen = 0;
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0};
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
snprintf(key, sizeof(key), KV_MB_INDEX);
if (index == NULL) {
syslog(LOG_WARNING, "%s(): invalid index parameter", __func__);
return -1;
}
if (kv_get(key, tmp_str, NULL, 0)) {
memset(tbuf, 0, sizeof(tbuf));
memset(&resp, 0, sizeof(resp));
if (bic_ipmb_send(FRU_SLOT1, NETFN_OEM_REQ, BIC_CMD_OEM_GET_MB_INDEX, tbuf, 0, (uint8_t*) &resp, &rlen, BB_BIC_INTF) < 0) {
syslog(LOG_WARNING, "%s(): fail to get MB index", __func__);
return -1;
}
if (rlen == sizeof(GET_MB_INDEX_RESP)) {
*index = resp.index;
} else {
syslog(LOG_WARNING, "%s(): wrong response length (%d), while getting MB index, expected = %d",
__func__, rlen, sizeof(GET_MB_INDEX_RESP));
return -1;
}
snprintf(tmp_str, sizeof(tmp_str), "%d", *index);
kv_set(key, tmp_str, 0, 0);
}
else {
// get from cache
*index = atoi(tmp_str);
}
return 0;
}
// For class 2 system, bypass command to another slot BMC
int
bic_bypass_to_another_bmc(uint8_t* data, uint8_t len) {
uint8_t tlen = 0;
uint8_t rlen = 0;
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
char iana_id[IANA_LEN] = {0x9c, 0x9c, 0x0};
BYPASS_MSG req = {0};
if (data == NULL) {
syslog(LOG_WARNING, "%s(): NULL bypass data", __func__);
return -1;
}
memset(&req, 0, sizeof(req));
memset(rbuf, 0, sizeof(rbuf));
memcpy(req.iana_id, iana_id, MIN(sizeof(req.iana_id), sizeof(iana_id)));
req.bypass_intf = BMC_INTF;
memcpy(req.bypass_data, data, MIN(sizeof(req.bypass_data), len));
tlen = sizeof(BYPASS_MSG_HEADER) + len;
if (bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, (uint8_t*) &req, tlen, rbuf, &rlen, BB_BIC_INTF) < 0) {
syslog(LOG_WARNING, "%s(): fail to bypass command to another BMC", __func__);
return -1;
}
return 0;
}
int
bic_enable_ina233_alert(uint8_t fru, bool enable) {
uint8_t tbuf[5] = {0x00};
uint8_t tlen = sizeof(tbuf);
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t rlen = 0;
uint8_t ret = BIC_STATUS_FAILURE;
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = 0x1;
tbuf[4] = enable?0x0:0x1;
switch(fru) {
case FRU_2U_TOP:
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_INA233_ALERT_CTRL, tbuf, tlen, rbuf, &rlen, RREXP_BIC_INTF1);
break;
case FRU_2U_BOT:
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_INA233_ALERT_CTRL, tbuf, tlen, rbuf, &rlen, RREXP_BIC_INTF2);
break;
case FRU_CWC:
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_INA233_ALERT_CTRL, tbuf, tlen, rbuf, &rlen, RREXP_BIC_INTF1);
if ( ret != BIC_STATUS_SUCCESS ) break;
ret = bic_ipmb_send(FRU_SLOT1, NETFN_OEM_1S_REQ, BIC_CMD_OEM_INA233_ALERT_CTRL, tbuf, tlen, rbuf, &rlen, RREXP_BIC_INTF2);
if ( ret != BIC_STATUS_SUCCESS ) break;
break;
default:
printf("not expantion fru: %d\n", fru);
return ret;
}
return ret;
}
int
cpld_update_flag(uint8_t slot_id, uint8_t data, uint8_t read_cnt, uint8_t *rbuf) {
int ret = BIC_STATUS_SUCCESS;
int retries = RETRY_3_TIME;
uint8_t txbuf[32] = {0};
uint8_t rxbuf[32] = {0};
uint8_t txlen = 0;
uint8_t rxlen = 0;
txbuf[0] = CPLD_BB_BUS;
txbuf[1] = CPLD_FLAG_REG_ADDR;
txbuf[2] = read_cnt;
txbuf[3] = 0x0D;
//only do one action at the time.
//use read_cnt to check which actions should be performed.
if ( read_cnt > 0 ) {
txlen = 4;
} else {
txbuf[4] = data;
txlen = 5;
}
do {
ret = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, txbuf, txlen, rxbuf, &rxlen, BB_BIC_INTF);
if ( ret < 0 ) {
sleep(1);
} else break;
} while ( retries-- > 0 );
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to set/get the flag of CPLD", __func__);
} else {
if ( read_cnt > 0 ) {
*rbuf = rxbuf[0];
}
}
return ret;
}
// In class 2 system, to prevent two BMC update bb firmware at the same time,
// use BB CPLD register to determine whether to update firmware or not.
// 1. Read the register to check no one is updating.
// 2. Set register to notify the update will be started.
// 3. Check the register not be overrided by another BMC.
int
bb_fw_update_prepare(uint8_t slot_id) {
uint8_t mb_index;
uint8_t rxbuf = 0x0;
if (cpld_update_flag(slot_id, 0x0, 1, &rxbuf) || rxbuf != 0) {
syslog(LOG_WARNING, "another slot is updating baseboard firmware");
return -1;
}
if (bic_get_mb_index(&mb_index) < 0) {
syslog(LOG_WARNING, "Failed to get MB index");
return -1;
}
// write register to notify update wiil be started
if (cpld_update_flag(slot_id, mb_index, 0, NULL)) {
return -1;
}
sleep(1);
if (cpld_update_flag(slot_id, 0x0, 1, &rxbuf)) {
return -1;
}
if (rxbuf != mb_index) {
syslog(LOG_WARNING, "slot%d is updating baseboard firmware", mb_index);
return -1;
}
return 0;
}
int
bb_fw_update_finish(uint8_t slot_id) {
return cpld_update_flag(slot_id, 0x0, 0, NULL);
}
int
bic_get_m2_config(uint8_t *config, uint8_t slot, uint8_t intf) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, 0x00};
uint8_t rbuf[8] = {0x00};
uint8_t tlen = 4;
uint8_t rlen = 0;
int ret = 0;
ret = bic_ipmb_send(slot, NETFN_OEM_1S_REQ, BIC_CMD_GPV3_GET_M2_CONFIG, tbuf, tlen, rbuf, &rlen, intf);
if (ret == 0 && rlen == 4) {
*config = rbuf[3];
}
return ret;
}
void
bic_open_cwc_usb(uint8_t slot) {
bic_gpio_t gpio = {0};
printf("Opening USB hubs...\n");
if (bic_get_gpio(slot, &gpio, NONE_INTF) == 0 &&
(gpio.gpio[0] & (1 << RST_USB_HUB_N)) == GPIO_LOW) { //not to open all hubs at once
remote_bic_set_gpio(slot, CWC_GPIO_RST_USB_HUB, GPIO_LOW, REXP_BIC_INTF);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_LOW, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_LOW, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_LOW, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_LOW, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_LOW, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_LOW, RREXP_BIC_INTF2);
}
bic_set_gpio(slot, RST_USB_HUB_N, GPIO_HIGH);
sleep(SW_USB_HUB_DELAY);
remote_bic_set_gpio(slot, CWC_GPIO_RST_USB_HUB, GPIO_HIGH, REXP_BIC_INTF);
sleep(SW_USB_HUB_DELAY);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_HIGH, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_HIGH, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_HIGH, RREXP_BIC_INTF1);
sleep(SW_USB_HUB_DELAY);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_HIGH, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_HIGH, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_HIGH, RREXP_BIC_INTF2);
sleep(SW_USB_HUB_DELAY);
return;
}
void
bic_close_cwc_usb(uint8_t slot) {
printf("Closing USB hubs...\n");
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_LOW, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_LOW, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_LOW, RREXP_BIC_INTF1);
sleep(SW_USB_HUB_DELAY);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_LOW, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_LOW, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_LOW, RREXP_BIC_INTF2);
sleep(SW_USB_HUB_DELAY);
remote_bic_set_gpio(slot, CWC_GPIO_RST_USB_HUB, GPIO_LOW, REXP_BIC_INTF);
sleep(SW_USB_HUB_DELAY);
bic_set_gpio(slot, RST_USB_HUB_N, GPIO_LOW);
sleep(SW_USB_HUB_DELAY);
//wait for usb devices to be released
remote_bic_set_gpio(slot, CWC_GPIO_RST_USB_HUB, GPIO_HIGH, REXP_BIC_INTF);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_HIGH, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_HIGH, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_HIGH, RREXP_BIC_INTF1);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB1, GPIO_HIGH, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB2, GPIO_HIGH, RREXP_BIC_INTF2);
remote_bic_set_gpio(slot, GPV3_GPIO_RST_USB_HUB3, GPIO_HIGH, RREXP_BIC_INTF2);
return;
}