meta-facebook/meta-grandcanyon/recipes-grandcanyon/plat-libs/files/bic/bic_ipmi.c (864 lines of code) (raw):
/*
*
* Copyright 2020-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 <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_xfer.h"
#define MAX_VER_STR_LEN 80
//FRU
#define FRUID_READ_COUNT_MAX 0x20
#define FRUID_WRITE_COUNT_MAX 0x20
#define FRUID_SIZE 256
//SDR
#define SDR_READ_COUNT_MAX 0x1A
#pragma pack(push, 1)
#define MASTER_WRITE_READ_HEADER_LEN 3
#define MASTER_WRITE_READ_MAX_WRITE_BUF_SIZE (MAX_IPMB_BUFFER - MASTER_WRITE_READ_HEADER_LEN)
#define GET_BIC_GPIO_CFG_CMD_LEN 13
#define SET_BIC_GPIO_CFG_CMD_LEN 14
#define GET_SYS_FW_VER_CMD_LEN 4
#define SYS_FW_VER_PARAM_SEL 0x01
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)
//BIC and BIC bootloader firmware version
typedef struct _bic_get_fw_ver_req {
uint8_t IANA[SIZE_IANA_ID];
uint8_t component;
} bic_get_fw_ver_req;
typedef struct _bic_get_fw_ver_resp {
uint8_t IANA[SIZE_IANA_ID];
uint8_t ver_response[MAX_BIC_VER_STR_LEN];
} bic_get_fw_ver_resp;
typedef struct {
uint8_t IANA[SIZE_IANA_ID];
uint8_t postcode_response[MAX_POSTCODE_LEN];
} bic_get_post_code_resp;
typedef struct {
uint8_t bus_id;
uint8_t slave_addr;
uint8_t read_count;
uint8_t write_buffer[MASTER_WRITE_READ_MAX_WRITE_BUF_SIZE];
} bic_master_write_read_req;
typedef struct {
uint8_t param_revision;
uint8_t set_selector;
uint8_t encoding;
uint8_t str_len;
uint8_t str_data[SIZE_SYSFW_VER];
} bic_get_sys_fw_ver_resp;
int
bic_get_fw_ver(uint8_t slot_id, uint8_t comp, uint8_t *ver) {
uint8_t rbuf[MAX_IPMB_BUFFER] = {0x00};
uint8_t rlen = 0;
int ret = BIC_STATUS_FAILURE;
bic_get_fw_ver_req ver_req;
bic_get_fw_ver_resp ver_resp;
if (ver == NULL) {
syslog(LOG_ERR, "%s: pointer is NULL\n", __func__);
return BIC_STATUS_FAILURE;
}
memset(&ver_req, 0, sizeof(ver_req));
memset(&ver_resp, 0, sizeof(ver_resp));
// Fill the IANA ID
memcpy(&ver_req, (uint8_t *)&IANA_ID, SIZE_IANA_ID);
// Fill the component for which firmware is requested
ver_req.component = comp;
ret = bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_FW_VER, (uint8_t *)&ver_req, sizeof(ver_req), rbuf, &rlen);
// rlen should be greater than or equal to 4 (IANA + Data1 +...+ DataN)
if ((ret < 0) || (rlen < 4) || (rlen > (MAX_BIC_VER_STR_LEN + SIZE_IANA_ID))) {
syslog(LOG_ERR, "%s: ret: %d, rlen: %d, comp: %d\n", __func__, ret, rlen, comp);
ret = BIC_STATUS_FAILURE;
} else {
memcpy(&ver_resp, rbuf, rlen);
//Ignore IANA ID
memcpy(ver, &(ver_resp.ver_response), sizeof(ver_resp.ver_response));
}
return ret;
}
int
bic_me_recovery(uint8_t command) {
uint8_t tbuf[MAX_IPMB_BUFFER] = {0x00};
uint8_t rbuf[MAX_IPMB_BUFFER] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = 0;
int retry = 0;
while (retry <= MAX_RETRY) {
tbuf[0] = 0xB8;
tbuf[1] = 0xDF;
tbuf[2] = 0x57;
tbuf[3] = 0x01;
tbuf[4] = 0x00;
tbuf[5] = command;
tlen = 6;
ret = bic_me_xmit(tbuf, tlen, rbuf, &rlen);
if (ret != 0) {
retry++;
sleep(1);
continue;
}
else {
break;
}
}
if (retry == MAX_RETRY + 1) { //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, sizeof(tbuf));
memset(&rbuf, 0, sizeof(rbuf));
/*
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 <= MAX_RETRY) {
tbuf[0] = 0x18;
tbuf[1] = 0x04;
tlen = 2;
ret = bic_me_xmit(tbuf, tlen, rbuf, &rlen);
if (ret != 0) {
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 == MAX_RETRY + 1) { //if the third retry still failed, return -1
syslog(LOG_CRIT, "%s: Restore Factory Default failed..., retried: %d", __func__, retry);
return -1;
}
return 0;
}
// Custom Command for getting vr version/device id
int
bic_get_vr_device_id(uint8_t *rbuf, uint8_t *rlen, uint8_t bus, uint8_t addr) {
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t tlen = 0;
int ret = 0;
// set VR page
tbuf[0] = (bus << 1) + 1;
tbuf[1] = addr;
tbuf[2] = 0x00; //read cnt
tbuf[3] = CMD_INF_VR_SET_PAGE; //command code
tbuf[4] = 0x01;
tlen = 5;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, rlen);
if (ret < 0) {
syslog(LOG_WARNING, "%s():%d Failed to send command code to switch VR page. ret=%d", __func__,__LINE__, ret);
return ret;
}
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_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, rlen);
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;
}
//Refer "AN001-XDPE122xx-V3.0_XDPE122xx Programming Guide" 9
int
bic_get_ifx_vr_remaining_writes(uint8_t bus, uint8_t addr, uint8_t *writes) {
// The data residing in bit11~bit6 is the number of the remaining writes.
#define REMAINING_TIMES(x) (((x[1] << 8) + x[0]) & 0xFC0) >> 6
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t rbuf[MAX_IPMB_BUFFER] = {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_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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;
}
// Refer "isl69259_ds_Aug_21_2019" 10.71 & 10.73
int
bic_get_isl_vr_remaining_writes(uint8_t bus, uint8_t addr, uint8_t *writes) {
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t rbuf[MAX_IPMB_BUFFER] = {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] = CMD_ISL_VR_DMAADDR; //command code
tbuf[4] = 0xC2; //data1
tbuf[5] = 0x00; //data2
tlen = 6;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to send command and data...", __func__);
goto error_exit;
}
tbuf[2] = 0x04; //read cnt
tbuf[3] = CMD_ISL_VR_DMAFIX; //command code
tlen = 4;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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_switch_mux_for_bios_spi(uint8_t mux) {
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t rbuf[MAX_IPMB_BUFFER] = {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(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
if (ret < 0) {
return -1;
}
return 0;
}
int
bic_get_vr_ver(uint8_t bus, uint8_t addr, char *key, char *ver_str) {
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t tlen = 0;
uint8_t rbuf[MAX_IPMB_BUFFER] = {0};
uint8_t rlen = 0;
uint8_t remaining_writes = 0;
int fd = 0;
int ret = 0;
ret = bic_get_vr_device_id(rbuf, &rlen, bus, addr);
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
fd = open(SERVER_SENSOR_LOCK, O_CREAT | O_RDWR, 0666);
ret = flock(fd, LOCK_EX | LOCK_NB);
if (ret != 0) {
if (EWOULDBLOCK == errno) {
syslog(LOG_WARNING, "%s():%d Failed to lock VR sensor reading", __func__,__LINE__);
remove(SERVER_SENSOR_LOCK);
close(fd);
return -1;
}
}
//get the remaining writes of VRs
ret = bic_get_ifx_vr_remaining_writes(bus, addr, &remaining_writes);
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
//Refer "AN001-XDPE122xx-V3.0_XDPE122xx Programming Guide" 8.2.1
tbuf[2] = 0x00; //read cnt
tbuf[3] = CMD_INF_VR_SET_PAGE; //command code
tbuf[4] = 0x62;
tlen = 5;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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] = CMD_INF_VR_READ_DATA_LOW; //command code
tlen = 4;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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] = CMD_INF_VR_READ_DATA_HIGH; //command code
tlen = 4;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, &rbuf[2], &rlen);
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:
ret = flock(fd, LOCK_UN);
if (ret == -1) {
syslog(LOG_WARNING, "%s: failed to unflock on %s", __func__, SERVER_SENSOR_LOCK);
}
close(fd);
remove(SERVER_SENSOR_LOCK);
return ret;
} else if (rlen > 4) {
//TI
tbuf[2] = 0x02; //read cnt
tbuf[3] = CMD_TI_VR_NVM_CHECKSUM; //command code
tlen = 4;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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
// Refer "isl69259_ds_Aug_21_2019" 10.71 & 10.73
ret = bic_get_isl_vr_remaining_writes(bus, addr, &remaining_writes);
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] = CMD_ISL_VR_DMAADDR; //command code
tbuf[4] = 0x3F; //reg
tbuf[5] = 0x00; //dummy data
tlen = 6;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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] = CMD_ISL_VR_DMAFIX; //command code
tlen = 4;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen);
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 bus, uint8_t addr, char *ver_str) {
char key[MAX_KEY_LEN] = {0};
char tmp_str[MAX_VALUE_LEN] = {0};
memset(key, 0, MAX_KEY_LEN);
memset(tmp_str, 0, MAX_VALUE_LEN);
snprintf(key, sizeof(key), "vr_%02xh_crc", addr);
if (kv_get(key, tmp_str, NULL, 0) != 0) {
if (bic_get_vr_ver(bus, addr, key, tmp_str) != 0) {
return -1;
}
}
if (snprintf(ver_str, MAX_VER_STR_LEN, "%s", tmp_str) > (MAX_VER_STR_LEN - 1)) {
return -1;
}
return 0;
}
static int
_read_fruid(uint8_t fru_id, uint32_t offset, uint8_t count, uint8_t *rbuf, uint8_t *rlen) {
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t tlen = 0;
tbuf[0] = fru_id;
tbuf[1] = offset & 0xFF;
tbuf[2] = (offset >> 8) & 0xFF;
tbuf[3] = count;
tlen = 4;
return bic_ipmb_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_READ_FRUID_DATA, tbuf, tlen, rbuf, rlen);
}
// Storage - Get FRUID info
// Netfn: 0x0A, Cmd: 0x10
int
bic_get_fruid_info(uint8_t fru_id, ipmi_fruid_info_t *info) {
uint8_t rlen = 0;
uint8_t fruid = 0;
return bic_ipmb_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_GET_FRUID_INFO, &fruid, 1, (uint8_t *) info, &rlen);
}
int
bic_read_fruid(uint8_t fru_id, char *path, int *fru_size) {
int ret = 0;
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;
ssize_t bytes_wr = 0;
ipmi_fruid_info_t info = {0};
// 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, "%s open fails for path: %s\n", __func__, path);
goto error_exit;
}
// Read the FRUID information
ret = bic_get_fruid_info(fru_id, &info);
if (ret) {
syslog(LOG_ERR, "%s bic_read_fruid_info returns %d\n", __func__, ret);
goto error_exit;
}
// Indicates the size of the FRUID
nread = (info.size_msb << 8) | info.size_lsb;
if (nread > FRUID_SIZE) {
nread = FRUID_SIZE;
}
*fru_size = nread;
if (*fru_size == 0) {
goto error_exit;
}
// Read chunks of FRUID binary data in a loop
offset = 0;
while (nread > 0) {
if (nread > FRUID_READ_COUNT_MAX) {
count = FRUID_READ_COUNT_MAX;
} else {
count = nread;
}
ret = _read_fruid(fru_id, offset, count, rbuf, &rlen);
if (ret) {
syslog(LOG_ERR, "%s _read_fruid failed, ret: %d\n", __func__, ret);
goto error_exit;
}
// Ignore the first byte as it indicates length of response
bytes_wr = write(fd, &rbuf[1], rlen-1);
if (bytes_wr != rlen-1) {
syslog(LOG_ERR, "%s write fruid failed, write bytes: %d\n", __func__, bytes_wr);
return -1;
}
// Update offset
offset += (rlen-1);
nread -= (rlen-1);
}
error_exit:
if (fd >= 0 ) {
close(fd);
}
return ret;
}
static int
_write_fruid(uint8_t fru_id, uint32_t offset, uint8_t count, uint8_t *buf) {
int ret = 0;
uint8_t tbuf[MAX_IPMB_BUFFER] = {0};
uint8_t rbuf[MAX_IPMB_BUFFER] = {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_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_WRITE_FRUID_DATA, tbuf, tlen, rbuf, &rlen);
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 fru_id, const char *path) {
int ret = -1;
uint32_t offset = 0;
uint8_t count = 0;
uint8_t buf[64] = {0};
int fd = 0;
// 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(fru_id, offset, count, buf);
if (ret) {
break;
}
// Update counter
offset += count;
}
error_exit:
if (fd >= 0 ) {
close(fd);
}
return ret;
}
static int
_get_sdr_rsv(uint8_t *rsv) {
uint8_t rlen = 0;
return bic_ipmb_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_RSV_SDR, NULL, 0, (uint8_t *) rsv, &rlen);
}
static int
_get_sdr(ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen) {
return bic_ipmb_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_GET_SDR, (uint8_t *)req, sizeof(ipmi_sel_sdr_req_t), (uint8_t*)res, rlen);
}
int
bic_get_sdr(ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen) {
int ret = 0;
uint8_t tbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
uint8_t tlen = 0;
uint8_t len = 0;
ipmi_sel_sdr_res_t *tres = NULL;
sdr_rec_hdr_t *hdr = NULL;
tres = (ipmi_sel_sdr_res_t *) tbuf;
// Get SDR reservation ID for the given record
ret = _get_sdr_rsv(rbuf);
if (ret != 0) {
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(req, (ipmi_sel_sdr_res_t *)tbuf, &tlen);
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(req, (ipmi_sel_sdr_res_t *)tbuf, &tlen);
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 0;
}
int
bic_get_sensor_reading(uint8_t sensor_num, ipmi_sensor_reading_t *sensor) {
uint8_t rlen = 0;
return bic_ipmb_wrapper(NETFN_SENSOR_REQ, CMD_SENSOR_GET_SENSOR_READING, &sensor_num, 1, (uint8_t *)sensor, &rlen);
}
int
bic_get_self_test_result(uint8_t *self_test_result) {
uint8_t rlen = 0;
int ret = 0;
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_GET_SELFTEST_RESULTS, NULL, 0, rbuf, &rlen);
if (ret == 0 && rlen == 2) {
memcpy(self_test_result, rbuf, rlen);
}
return ret;
}
int
bic_get_sys_guid(uint8_t slot_id, uint8_t *guid, uint8_t guid_size) {
int ret = 0;
uint8_t rlen = 0;
uint8_t rbuf[MAX_IPMB_BUFFER] = {0x00};
if (guid == NULL) {
syslog(LOG_ERR, "%s: get pointer guid failed\n", __func__);
return BIC_STATUS_FAILURE;
}
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_GET_SYSTEM_GUID, NULL, 0, rbuf, &rlen);
if ((ret < 0) || (rlen != guid_size)) {
syslog(LOG_ERR, "%s: ret: %d, rlen: %d\n", __func__, ret, rlen);
ret = BIC_STATUS_FAILURE;
} else {
memcpy(guid, rbuf, guid_size);
}
return ret;
}
int
bic_set_sys_guid(uint8_t slot_id, uint8_t *guid, uint8_t guid_size) {
int ret = 0;
uint8_t rlen = 0;
uint8_t rbuf[MAX_IPMB_BUFFER] = {0x00};
if (guid == NULL) {
syslog(LOG_ERR, "%s: get pointer guid failed\n", __func__);
return BIC_STATUS_FAILURE;
}
ret = bic_ipmb_wrapper(NETFN_OEM_REQ, CMD_OEM_SET_SYSTEM_GUID, guid, guid_size, rbuf, &rlen);
if (ret < 0) {
syslog(LOG_ERR, "%s: ret: %d\n", __func__, ret);
ret = BIC_STATUS_FAILURE;
}
return ret;
}
// OEM - Get Post Code buffer
// Netfn: 0x38, Cmd: 0x12
int
bic_get_80port_record(uint16_t max_len, uint8_t *rbuf, uint8_t *rlen) {
int ret = 0;
bic_get_post_code_resp postcode_resp;
if ((rbuf == NULL) || (rlen == NULL)) {
syslog(LOG_WARNING, "%s Cannot get the postcode buffer from server because of NULL parameters of response buffer and response length", __func__);
return -1;
}
memset(&postcode_resp, 0, sizeof(postcode_resp));
ret = bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_POST_BUF, (uint8_t *)&IANA_ID, SIZE_IANA_ID, (uint8_t *)&postcode_resp, rlen);
if (ret < 0) {
syslog(LOG_WARNING, "%s Cannot get the postcode buffer from server", __func__);
} else if (*rlen < SIZE_IANA_ID) {
syslog(LOG_WARNING, "%s Cannot get the postcode buffer from server because the response length: %d should greater or equal to length: %d.", __func__, *rlen, SIZE_IANA_ID);
return -1;
} else if ((*rlen - SIZE_IANA_ID) > max_len) {
syslog(LOG_WARNING, "%s Cannot get the postcode buffer from server because the response length: %d is larger than max length: %d.", __func__, (*rlen - SIZE_IANA_ID), max_len);
return -1;
} else {
*rlen -= SIZE_IANA_ID;
memcpy(rbuf, &(postcode_resp.postcode_response), MIN(*rlen, sizeof(postcode_resp.postcode_response)));
}
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 tlen = MASTER_WRITE_READ_HEADER_LEN, rlen = 0;
int ret = 0;
bic_master_write_read_req tbuf;
if ((wbuf == NULL) || (rbuf == NULL)) {
syslog(LOG_ERR, "%s: failed to send ipmb wrapper because parameters are NULL\n", __func__);
return BIC_STATUS_FAILURE;
}
memset(&tbuf, 0, sizeof(tbuf));
tbuf.bus_id = bus;
tbuf.slave_addr = addr;
tbuf.read_count = rcnt;
if ((wcnt != 0) && (wcnt <= sizeof(tbuf.write_buffer))) {
memcpy(&tbuf.write_buffer, wbuf, wcnt);
tlen += wcnt;
} else {
syslog(LOG_ERR, "%s: failed to set write buffer because write buffer length: %d is wrong, max write buffer length: %d\n", __func__, wcnt, sizeof(tbuf.write_buffer));
return BIC_STATUS_FAILURE;
}
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, (uint8_t *)&tbuf, tlen, rbuf, &rlen);
if ((ret < 0) || (rlen != rcnt)) {
syslog(LOG_ERR, "%s: failed to send ipmb wrapper. ret: %d, response length: %d, expected length: %d\n", __func__, ret, rlen, rcnt);
return BIC_STATUS_FAILURE;
}
return ret;
}
int
bic_asd_init(uint8_t cmd) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x00};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t tlen = 4;
uint8_t rlen = 0;
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = cmd;
return bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_ASD_INIT, tbuf, tlen, rbuf, &rlen);
}
// Get one GPIO pin status
int
bic_get_one_gpio_status(uint8_t gpio_num, uint8_t *value){
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x00};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t tlen = 5;
uint8_t rlen = 0;
int ret = 0;
if (value == NULL) {
syslog(LOG_ERR, "%s(): gpio value should not be NULL", __func__);
return -1;
}
// File the IANA ID
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = 0x00;
tbuf[4] = gpio_num;
ret = bic_ipmb_wrapper(NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_SET_GPIO, tbuf, tlen, rbuf, &rlen);
*value = rbuf[4] & 0x01;
return ret;
}
int
bic_set_gpio(uint8_t gpio_num, uint8_t value) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x9c, 0x9c, 0x00};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {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(NETFN_OEM_1S_REQ, BIC_CMD_OEM_GET_SET_GPIO, tbuf, tlen, rbuf, &rlen);
if (ret < 0) {
return -1;
}
return 0;
}
// APP - Get Device ID
// Netfn: 0x06, Cmd: 0x01
int
bic_get_dev_id(ipmi_dev_id_t *dev_id) {
uint8_t rlen = 0;
if (dev_id == NULL) {
syslog(LOG_ERR, "%s(): device ID is missing", __func__);
}
return bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_GET_DEVICE_ID, NULL, 0, (uint8_t *) dev_id, &rlen);
}
int
bic_reset() {
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t rlen = 0;
int ret;
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_COLD_RESET, NULL, 0, rbuf, &rlen);
return ret;
}
int
bic_clear_cmos() {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t rlen = 0;
return bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_CLEAR_CMOS, tbuf, 3, rbuf, &rlen);
}
int
bic_get_gpio_config(uint8_t gpio, uint8_t *data) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x00};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t rlen = 0;
uint8_t tlen = GET_BIC_GPIO_CFG_CMD_LEN;
uint8_t index = 0;
uint8_t pin = 0;
int ret = 0;
if (data == NULL) {
syslog(LOG_ERR, "%s(): data is missing", __func__);
}
// 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(NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO_CONFIG, tbuf, tlen, rbuf, &rlen);
if (rlen < 4) {
syslog(LOG_ERR, "%s(): Wrong response length: %d", __func__, rlen);
return -1;
}
*data = rbuf[3];
return ret;
}
int
bic_set_gpio_config(uint8_t gpio, uint8_t data) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x00};
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t rlen = 0;
uint8_t tlen = SET_BIC_GPIO_CFG_CMD_LEN;
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[13] = data & 0x1f;
ret = bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_SET_GPIO_CONFIG, tbuf, tlen, rbuf, &rlen);
return ret;
}
// Get all GPIO pin status
int
bic_get_gpio(bic_gpio_t *gpio) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t rlen = 0;
int ret = 0;
if (gpio == NULL) {
syslog(LOG_WARNING, "%s(): gpio status is missing", __func__);
return -1;
}
memset(gpio, 0, sizeof(*gpio));
ret = bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_GPIO, tbuf, 3, rbuf, &rlen);
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);
return ret;
}
// Get BIC Configuration
int
bic_get_config(bic_config_t *cfg) {
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x9c, 0x9c, 0x00}; // IANA ID
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0x00};
uint8_t rlen = 0;
int ret = 0;
if (cfg == NULL) {
syslog(LOG_ERR, "%s(): Configuration is missing", __func__);
return -1;
}
ret = bic_ipmb_wrapper(NETFN_OEM_1S_REQ, CMD_OEM_1S_GET_CONFIG, tbuf, 3, rbuf, &rlen);
// Ignore IANA ID
if (rlen < 4) {
syslog(LOG_ERR, "%s(): Get BIC config failed, rlen: %d", __func__, rlen);
return -1;
}
*(uint8_t *) cfg = rbuf[3];
return ret;
}
// Read Sensor Data Records (SDR)
int
bic_get_sdr_info(ipmi_sel_sdr_info_t *info) {
int ret = 0;
uint8_t rlen = 0;
if (info == NULL) {
syslog(LOG_ERR, "%s(): SEL information is missing", __func__);
return -1;
}
ret = bic_ipmb_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_GET_SDR_INFO, NULL, 0, (uint8_t *) info, &rlen);
return ret;
}
int
bic_get_sel(ipmi_sel_sdr_req_t *req, ipmi_sel_sdr_res_t *res, uint8_t *rlen) {
int ret = 0;
if (req == NULL) {
syslog(LOG_ERR, "%s(): requset is missing", __func__);
return -1;
}
if (res == NULL) {
syslog(LOG_ERR, "%s(): response is missing", __func__);
return -1;
}
if (rlen == NULL) {
syslog(LOG_ERR, "%s(): requset length is missing", __func__);
return -1;
}
ret = bic_ipmb_wrapper(NETFN_STORAGE_REQ, CMD_STORAGE_GET_SEL, (uint8_t *)req, sizeof(ipmi_sel_sdr_req_t), (uint8_t*)res, rlen);
return ret;
}
int
bic_get_sys_fw_ver(uint8_t *ver) {
int ret = 0;
int ver_len = 0, data_index = 0;
uint8_t tlen = 0, rlen = 0;
uint8_t tbuf[MAX_IPMB_REQ_LEN] = {0x00};
uint8_t rbuf[MAX_IPMB_BUFFER] = {0x00};
bic_get_sys_fw_ver_resp sys_fw_resp;
if (ver == NULL) {
syslog(LOG_ERR, "%s: failed to get system firmware version due to NULL pointer\n", __func__);
return BIC_STATUS_FAILURE;
}
memset(&sys_fw_resp, 0, sizeof(sys_fw_resp));
tlen = GET_SYS_FW_VER_CMD_LEN;
tbuf[0] = 0x00; // parameter revision
tbuf[1] = SYS_FW_VER_PARAM_SEL; // parameter selector
tbuf[2] = 0x00; // set selector
tbuf[3] = 0x00; // block selector
ret = bic_ipmb_wrapper(NETFN_APP_REQ, CMD_APP_GET_SYS_INFO_PARAMS, tbuf, tlen, (uint8_t *)&sys_fw_resp, &rlen);
if ((ret < 0) || ((rlen - 1) != SIZE_SYSFW_VER)) {
syslog(LOG_ERR, "%s: ret: %d, rlen: %d\n", __func__, ret, rlen);
ret = BIC_STATUS_FAILURE;
} else {
// set remaining data byte to 0x00
if ((SIZE_SYSFW_VER - sys_fw_resp.str_len - 3) > 0) {
data_index = (int) sys_fw_resp.str_len;
memset(&sys_fw_resp.str_data[data_index], 0x00, (SIZE_SYSFW_VER - sys_fw_resp.str_len - 3));
}
memcpy(ver, &(sys_fw_resp.set_selector), (rlen-1));
}
return ret;
}