meta-facebook/meta-fby3/recipes-fby3/plat-libs/files/bic/bic_fwupdate.c (1,504 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 <openbmc/obmc-i2c.h>
#include "bic_fwupdate.h"
#include "bic_cpld_altera_fwupdate.h"
#include "bic_cpld_lattice_fwupdate.h"
#include "bic_vr_fwupdate.h"
#include "bic_bios_fwupdate.h"
#include "bic_mchp_pciesw_fwupdate.h"
#include "bic_m2_fwupdate.h"
//#define DEBUG
/****************************/
/* BIC fw update */
/****************************/
#define BIC_CMD_DOWNLOAD 0x21
#define BIC_CMD_DOWNLOAD_SIZE 11
#define BIC_CMD_RUN 0x22
#define BIC_CMD_RUN_SIZE 7
#define BIC_CMD_STS 0x23
#define BIC_CMD_STS_SIZE 3
#define BIC_CMD_DATA 0x24
#define BIC_CMD_DATA_SIZE 0xFF
#define BIC_FLASH_START 0x8000
#define IPMB_BIC_RETRY 3
#define SELF_TEST_RESP_LEN 2
#define IPMB_BRIDGE_OVERHEAD 9
enum {
FEXP_BIC_I2C_WRITE = 0x20,
FEXP_BIC_I2C_READ = 0x21,
FEXP_BIC_I2C_UPDATE = 0x22,
FEXP_BIC_IPMI_I2C_SW = 0x23,
REXP_BIC_I2C_WRITE = 0x24,
REXP_BIC_I2C_READ = 0x25,
REXP_BIC_I2C_UPDATE = 0x26,
REXP_BIC_IPMI_I2C_SW = 0x27,
BB_BIC_I2C_WRITE = 0x28,
BB_BIC_I2C_READ = 0x29,
BB_BIC_I2C_UPDATE = 0x2A,
BB_BIC_IPMI_I2C_SW = 0x2B,
RREXP2_BIC_I2C_WRITE = 0x41,
RREXP2_BIC_I2C_READ = 0x42,
RREXP2_BIC_I2C_UPDATE = 0x43,
RREXP2_BIC_IPMI_I2C_SW = 0x44,
RREXP1_BIC_I2C_WRITE = 0x46,
RREXP1_BIC_I2C_READ = 0x47,
RREXP1_BIC_I2C_UPDATE = 0x48,
RREXP1_BIC_IPMI_I2C_SW = 0x49,
};
enum {
I2C_100K = 0x0,
I2C_1M
};
#ifdef DEBUG
static void print_data(const char *name, uint8_t netfn, uint8_t cmd, uint8_t *buf, uint8_t len) {
int i;
printf("[%s][%d]send: 0x%x 0x%x ", name, len, netfn, cmd);
for ( i = 0; i < len; i++) {
printf("0x%x ", buf[i]);
}
printf("\n");
}
#endif
static uint8_t
get_checksum(uint8_t *buf, uint8_t len) {
int i;
uint8_t result = 0;
for ( i = 0; i < len; i++ ) {
result += buf[i];
}
return result;
}
static int
enable_bic_update_with_param(uint8_t slot_id, uint8_t intf) {
uint8_t tbuf[16] = {0x00};
uint8_t rbuf[20] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
uint8_t netfn = 0;
uint8_t cmd = 0;
int ret = -1;
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
switch (intf) {
case FEXP_BIC_INTF:
case BB_BIC_INTF:
case REXP_BIC_INTF:
netfn = NETFN_OEM_1S_REQ;
cmd = CMD_OEM_1S_MSG_OUT;
tbuf[3] = intf;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_ENABLE_BIC_UPDATE;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = 0x01; //Update bic via i2c
tlen = 10;
break;
case NONE_INTF:
netfn = NETFN_OEM_1S_REQ;
cmd = CMD_OEM_1S_ENABLE_BIC_UPDATE;
tbuf[3] = 0x1; //Update bic via i2c
tlen = 4;
break;
case RREXP_BIC_INTF1:
case RREXP_BIC_INTF2:
netfn = NETFN_OEM_1S_REQ;
cmd = CMD_OEM_1S_MSG_OUT;
tbuf[3] = REXP_BIC_INTF;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_MSG_OUT;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = intf;
tbuf[10] = NETFN_OEM_1S_REQ << 2;
tbuf[11] = CMD_OEM_1S_ENABLE_BIC_UPDATE;
memcpy(&tbuf[12], (uint8_t *)&IANA_ID, 3);
tbuf[15] = 0x01; //Update bic via i2c
tlen = 16;
break;
}
#ifdef DEBUG
print_data(__func__, netfn, cmd, tbuf, tlen);
#endif
ret = bic_ipmb_wrapper(slot_id, netfn, cmd, tbuf, tlen, rbuf, &rlen);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot enable bic fw update, slot id:%d, intf: 0x%X", __func__, slot_id, intf);
return ret;
}
#ifdef DEBUG
print_data(__func__, netfn, cmd, rbuf, rlen);
#endif
if ( (intf != NONE_INTF) && (rbuf[6] != CC_SUCCESS)) {
syslog(LOG_WARNING, "%s() Cannot enable bic fw update, slot id:%d, intf: 0x%X, cc: 0x%X", __func__, slot_id, intf, rbuf[6]);
return -1;
}
if ((intf == RREXP_BIC_INTF1 || intf == RREXP_BIC_INTF2) && rbuf[13] != CC_SUCCESS) {
syslog(LOG_WARNING, "%s() Cannot enable bic fw update, slot id:%d, intf: 0x%X, cc: 0x%X", __func__, slot_id, intf, rbuf[13]);
return -1;
}
return ret;
}
static int
enable_bic_update(uint8_t slot_id) {
return enable_bic_update_with_param(slot_id, NONE_INTF);
}
static int
enable_remote_bic_update(uint8_t slot_id, uint8_t intf) {
return enable_bic_update_with_param(slot_id, intf);
}
static int
setup_remote_bic_i2c_speed(uint8_t slot_id, uint8_t speed, uint8_t intf) {
uint8_t tbuf[16] = {0x00};
uint8_t rbuf[20] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = -1;
switch (intf) {
case RREXP1_BIC_IPMI_I2C_SW:
case RREXP2_BIC_IPMI_I2C_SW:
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = REXP_BIC_INTF;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_MSG_OUT;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = intf;
tbuf[10] = speed;
tlen = 11;
break;
default:
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = intf;
tbuf[4] = speed;
tlen = 5;
}
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, sizeof(tbuf));
#endif
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, rbuf, rlen);
#endif
if ((intf == RREXP1_BIC_IPMI_I2C_SW || intf == RREXP2_BIC_IPMI_I2C_SW) && rbuf[6] != CC_SUCCESS) {
return -1;
}
return ret;
}
static int
send_start_bic_update(uint8_t slot_id, int i2cfd, int size, uint8_t intf) {
uint8_t data[11] = { BIC_CMD_DOWNLOAD_SIZE,
BIC_CMD_DOWNLOAD_SIZE,
BIC_CMD_DOWNLOAD,
(BIC_FLASH_START >> 24) & 0xff,
(BIC_FLASH_START >> 16) & 0xff,
(BIC_FLASH_START >> 8) & 0xff,
(BIC_FLASH_START) & 0xff,
(size >> 24) & 0xff,
(size >> 16) & 0xff,
(size >> 8) & 0xff,
(size) & 0xff};
uint8_t tbuf[32] = {0x00};
uint8_t rbuf[32] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = -1;
if ( intf == NONE_INTF ) {
memcpy(tbuf, data, sizeof(data));
tbuf[1] = get_checksum(&tbuf[2], BIC_CMD_DOWNLOAD_SIZE);
tlen = BIC_CMD_DOWNLOAD_SIZE;
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
} else if ( intf == RREXP1_BIC_I2C_WRITE || intf == RREXP2_BIC_I2C_WRITE ) {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = REXP_BIC_INTF;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_MSG_OUT;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = intf;
memcpy(&tbuf[10], data, sizeof(data));
tbuf[11] = get_checksum(&tbuf[12], BIC_CMD_DOWNLOAD_SIZE);
tlen = 21;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
} else {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = intf;
memcpy(&tbuf[4], data, sizeof(data));
tbuf[5] = get_checksum(&tbuf[6], BIC_CMD_DOWNLOAD_SIZE);
tlen = 15;
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen);
#endif
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, rbuf, rlen);
#endif
}
if ((intf == RREXP1_BIC_I2C_WRITE || intf == RREXP2_BIC_I2C_WRITE) && rbuf[6] != CC_SUCCESS) {
return -1;
}
return ret;
}
static int
read_bic_update_ack_status(uint8_t slot_id, int i2cfd, uint8_t intf) {
uint8_t tbuf[32] = {0x00};
uint8_t rbuf[32] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = -1;
if ( intf == NONE_INTF ) {
uint8_t exp_data[2] = {0x00, 0xCC};
tlen = 0;
rlen = 2;
msleep(10);
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
if ( ret || (memcmp(rbuf, exp_data, sizeof(exp_data)) != 0) ) {
printf("%s() response %x:%x, ret=%d\n", __func__, rbuf[0], rbuf[1], ret);
ret = -1;
}
} else if (intf == RREXP1_BIC_I2C_READ || intf == RREXP2_BIC_I2C_READ) {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = REXP_BIC_INTF;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_MSG_OUT;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = intf;
tlen = 12;
rlen = 0;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
if ( rlen <= 0 ) {
printf("%s() invalid lenth %d", __func__, rlen);
ret = -1;
}
} else {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = intf;
tlen = 6;
rlen = 0;
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen);
#endif
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
if ( rlen <= 0 ) {
printf("%s() invalid lenth %d", __func__, rlen);
ret = -1;
}
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, rbuf, rlen);
#endif
}
return ret;
}
static int
send_complete_signal(uint8_t slot_id, int i2cfd, uint8_t intf) {
uint8_t data[7] = { BIC_CMD_RUN_SIZE,
BIC_CMD_RUN_SIZE,
BIC_CMD_RUN,
(BIC_FLASH_START >> 24) & 0xff,
(BIC_FLASH_START >> 16) & 0xff,
(BIC_FLASH_START >> 8) & 0xff,
(BIC_FLASH_START) & 0xff};
uint8_t tbuf[32] = {0x00};
uint8_t rbuf[32] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = -1;
if ( intf == NONE_INTF ) {
memcpy(tbuf, data, sizeof(data));
tbuf[1] = get_checksum(&tbuf[2], BIC_CMD_DOWNLOAD_SIZE);
tlen = BIC_CMD_RUN_SIZE;
rlen = 0;
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
} else if ( intf == RREXP1_BIC_I2C_WRITE || intf == RREXP2_BIC_I2C_WRITE ) {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = REXP_BIC_INTF;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_MSG_OUT;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = intf;
memcpy(&tbuf[10], data, sizeof(data));
//calculate the checksum
tbuf[11] = get_checksum(&tbuf[12], BIC_CMD_DOWNLOAD_SIZE);
tlen = BIC_CMD_RUN_SIZE + 4 + 6;
rlen = 0;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
} else {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = intf;
memcpy(&tbuf[4], data, sizeof(data));
//calculate the checksum
tbuf[5] = get_checksum(&tbuf[6], BIC_CMD_DOWNLOAD_SIZE);
tlen = BIC_CMD_RUN_SIZE + 4;
rlen = 0;
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen);
#endif
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, rbuf, rlen);
#endif
}
if ( ret < 0 ) {
printf("Failed to run the new image\n");
}
if ((intf == RREXP1_BIC_I2C_WRITE || intf == RREXP2_BIC_I2C_WRITE) && rbuf[6] != CC_SUCCESS) {
return -1;
}
return ret;
}
static int
read_bic_update_status(int i2cfd) {
const uint8_t exp_data[5] = {0x00, 0xCC, 0x03, 0x40, 0x40};
uint8_t tbuf[16] = {0};
uint8_t rbuf[16] = {0};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = -1;
tbuf[0] = BIC_CMD_STS_SIZE;
tbuf[1] = BIC_CMD_STS;
tbuf[2] = BIC_CMD_STS;
tlen = BIC_CMD_STS_SIZE;
rlen = 0;
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
if ( ret < 0 ) {
printf("%s() failed to get status\n", __func__);
goto exit;
}
tlen = 0;
rlen = 5;
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
if ( ret < 0 ) {
printf("%s() failed to get status ack\n", __func__);
goto exit;
}
if ( memcmp(rbuf, exp_data, sizeof(exp_data)) != 0 ) {
printf("%s() status: %x:%x:%x:%x:%x\n", __func__, rbuf[0], rbuf[1], rbuf[2], rbuf[3], rbuf[4]);
goto exit;
}
tbuf[0] = 0xCC;
tlen = 1;
rlen = 0;
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
if ( ret < 0) {
printf("%s() failed to send an ack\n", __func__);
goto exit;
}
exit:
return ret;
}
static int
send_bic_image_data(uint8_t slot_id, int i2cfd, uint16_t len, uint8_t *buf, uint8_t intf) {
uint8_t data[3] = {0x00};
uint8_t tbuf[256] = {0x00};
uint8_t rbuf[16] = {0x00};
uint8_t tlen = 0;
uint8_t rlen = 0;
int ret = -1;
data[0] = len + 3;
data[1] = get_checksum(buf, len) + BIC_CMD_DATA;
data[2] = BIC_CMD_DATA;
if ( intf == NONE_INTF ) {
memcpy(tbuf, data, sizeof(data));
memcpy(&tbuf[3], buf, len);
tlen = data[0];
rlen = 0;
ret = i2c_io(i2cfd, tbuf, tlen, rbuf, rlen);
} else if ( intf == RREXP1_BIC_I2C_UPDATE || intf == RREXP2_BIC_I2C_UPDATE ) {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = REXP_BIC_INTF;
tbuf[4] = NETFN_OEM_1S_REQ << 2;
tbuf[5] = CMD_OEM_1S_MSG_OUT;
memcpy(&tbuf[6], (uint8_t *)&IANA_ID, 3);
tbuf[9] = intf;
memcpy(&tbuf[10], data, sizeof(data));
memcpy(&tbuf[13], buf, len);
tlen = data[0] + 4 + 6; //IANA_ID + intf
rlen = 0;
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
if ( rbuf[10] == 0x0 ) {
syslog(LOG_WARNING, "%s() unexpected rbuf[4]=0x%x", __func__, rbuf[4]);
ret = -1;
}
} else {
memcpy(tbuf, (uint8_t *)&IANA_ID, 3);
tbuf[3] = intf;
memcpy(&tbuf[4], data, sizeof(data));
memcpy(&tbuf[7], buf, len);
tlen = data[0] + 4; //IANA_ID + intf
rlen = 0;
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen);
#endif
ret = bic_ipmb_wrapper(slot_id, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, tbuf, tlen, rbuf, &rlen);
if ( rbuf[4] == 0x0 ) {
syslog(LOG_WARNING, "%s() unexpected rbuf[4]=0x%x", __func__, rbuf[4]);
ret = -1;
}
#ifdef DEBUG
print_data(__func__, NETFN_OEM_1S_REQ, CMD_OEM_1S_MSG_OUT, rbuf, rlen);
#endif
}
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Cannot send data of the image, slot id:%d, update intf: 0x%X", __func__, slot_id, intf);
}
if ((intf == RREXP1_BIC_I2C_UPDATE || intf == RREXP2_BIC_I2C_UPDATE) && rbuf[6] != CC_SUCCESS) {
return -1;
}
return ret;
}
static int
send_bic_runtime_image_data(uint8_t slot_id, int fd, int i2cfd, int file_size, uint8_t bytes_per_read, uint8_t intf) {
uint8_t buf[256] = {0};
uint8_t read_bytes = 0;
int ret = -1;
int dsize = 0;
int last_offset = 0;
int offset = 0;;
dsize = file_size / 20;
//reinit the fd to the beginning
if ( lseek(fd, 0, SEEK_SET) != 0 ) {
syslog(LOG_WARNING, "%s() Cannot reinit the fd to the beginning. errstr=%s", __func__, strerror(errno));
return -1;
}
while (1) {
memset(buf, 0, sizeof(buf));
read_bytes = read(fd, buf, bytes_per_read);
if ( read_bytes <= 0 ) {
//no more bytes can be read
break;
}
offset += read_bytes;
if ( (last_offset + dsize) <= offset) {
printf("updated bic: %d %%\n", (offset/dsize)*5);
fflush(stdout);
last_offset += dsize;
}
if ( intf != NONE_INTF ) {
ret = send_bic_image_data(slot_id, i2cfd, read_bytes, buf, intf);
if ( ret < 0 ) {
return ret;
}
} else {
ret = read_bic_update_status(i2cfd);
if ( ret < 0 ) {
return ret;
}
ret = send_bic_image_data(slot_id, i2cfd, read_bytes, buf, NONE_INTF);
if ( ret < 0 ) {
return ret;
}
ret = read_bic_update_ack_status(slot_id, i2cfd, NONE_INTF);
if ( ret < 0 ) {
return ret;
}
}
}
return ret;
}
static int
update_bic(uint8_t slot_id, int fd, int file_size) {
int ret = -1;
int i2cfd;
char cmd[100] = {0};
size_t cmd_size = sizeof(cmd);
uint8_t bus_num;
const uint8_t I2CBASE = 0x40;
uint8_t bytes_per_read = 252;
struct rlimit mqlim;
//step1 -get the bus number and open the dev of i2c
bus_num = fby3_common_get_bus_id(slot_id);
i2cfd = i2c_open(bus_num, BRIDGE_SLAVE_ADDR);
if ( i2cfd < 0 ) {
printf("Cannot open /dev/i2c-%d\n", bus_num);
goto exit;
}
//step2 - kill ipmbd
snprintf(cmd, cmd_size, "sv stop ipmbd_%d", bus_num);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return BIC_STATUS_FAILURE;
}
printf("stop ipmbd for slot %x..\n", slot_id);
//step3 - adjust the i2c speed and set properties of mqlim
snprintf(cmd, cmd_size, "devmem 0x1e78a%03X w 0xFFFFE303", I2CBASE + (I2CBASE * bus_num) + 4);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return BIC_STATUS_FAILURE;
}
sleep(1);
printf("stopped ipmbd for slot %x..\n", slot_id);
if ( is_bic_ready(slot_id, NONE_INTF) < 0 ) {
printf("BIC is not ready after sleep 1s\n");
goto exit;
}
mqlim.rlim_cur = RLIM_INFINITY;
mqlim.rlim_max = RLIM_INFINITY;
if ( setrlimit(RLIMIT_MSGQUEUE, &mqlim) < 0) {
goto exit;
}
snprintf(cmd, cmd_size, "/usr/local/bin/ipmbd -u %d %d > /dev/null 2>&1 &", bus_num, slot_id);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return BIC_STATUS_FAILURE;
}
printf("start ipmbd -u for this slot %x..\n", slot_id);
//assume ipmbd that it will be ready in 2s
sleep(2);
//step4 - enable bic update
ret = enable_bic_update(slot_id);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() Failed to enable the bic update", __func__);
//goto exit;
}
//step5 - kill ipmbd
snprintf(cmd, cmd_size, "ps -w | grep -v 'grep' | grep 'ipmbd -u %d' |awk '{print $1}'| xargs kill", bus_num);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return BIC_STATUS_FAILURE;
}
printf("stop ipmbd -u for slot %x..\n", slot_id);
//make sure that BIC enters bootloader
sleep(3);
//step6 - send cmd 0x21 to notice BIC the update will start
ret = send_start_bic_update(slot_id, i2cfd, file_size, NONE_INTF);
if ( ret < 0 ) {
printf("Failed to send a signal to start the update of BIC\n");
goto exit;
}
msleep(600);
//step7 - check the response
ret = read_bic_update_ack_status(slot_id, i2cfd, NONE_INTF);
if ( ret < 0 ) {
printf("Failed to get the response of the command\n");
goto exit;
}
//step8 - loop to send all the image data
ret = send_bic_runtime_image_data(slot_id, fd, i2cfd, file_size, bytes_per_read, NONE_INTF);
if ( ret < 0 ) {
printf("Failed to send image data\n");
goto exit;
}
msleep(500);
//step9 - run the new image
ret = send_complete_signal(slot_id, i2cfd, NONE_INTF);
if ( ret < 0 ) {
printf("Failed to send a complete signal\n");
}
//step10 - check the response
ret = read_bic_update_ack_status(slot_id, i2cfd, NONE_INTF);
if ( ret < 0 ) {
printf("Failed to get the response of the command\n");
goto exit;
}
exit:
//step11 - recover the i2c speed
snprintf(cmd, cmd_size, "devmem 0x1e78a%03X w 0xFFFCB300", I2CBASE + (I2CBASE * bus_num) + 4);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return BIC_STATUS_FAILURE;
}
msleep(500);
//step12 - restart the ipmbd
snprintf(cmd, cmd_size, "sv start ipmbd_%d", bus_num);
if (system(cmd) != 0) {
syslog(LOG_WARNING, "[%s] %s failed\n", __func__, cmd);
return BIC_STATUS_FAILURE;
}
sleep(3);
if ( i2cfd > 0 ) {
close(i2cfd);
}
return ret;
}
// Wait for warm reset finished
void
wait_bic_warm_reset(uint8_t slot_id, uint8_t intf) {
int retry = IPMB_BIC_RETRY;
int ret;
uint8_t self_test_result[SELF_TEST_RESP_LEN] = {0};
sleep(3);
while (retry > 0){
ret = bic_get_self_test_result(slot_id, (uint8_t *)&self_test_result, intf);
if (ret == 0) {
break;
} else {
retry--;
}
sleep(1);
}
if (retry == 0) {
syslog(LOG_WARNING, "%s: BIC IPMB is not ready after %d retry, intf: %x\n", __func__, IPMB_BIC_RETRY, intf);
}
}
static int
update_remote_bic(uint8_t slot_id, uint8_t intf, int fd, int file_size) {
int ret = 0;
uint8_t is_fail = 0;
uint8_t bytes_per_read = 244;
uint8_t bic_read = 0xff;
uint8_t bic_write = 0xff;
uint8_t bic_update = 0xff;
uint8_t bic_i2c = 0xff;
uint8_t bmc_location = 0;
if (fby3_common_get_bmc_location(&bmc_location) != 0) {
printf("Cannot get the location of BMC");
return -1;
}
switch (intf) {
case FEXP_BIC_INTF:
bic_read = FEXP_BIC_I2C_READ;
bic_write = FEXP_BIC_I2C_WRITE;
bic_update = FEXP_BIC_I2C_UPDATE;
bic_i2c = FEXP_BIC_IPMI_I2C_SW;
break;
case BB_BIC_INTF:
bic_read = BB_BIC_I2C_READ;
bic_write = BB_BIC_I2C_WRITE;
bic_update = BB_BIC_I2C_UPDATE;
bic_i2c = BB_BIC_IPMI_I2C_SW;
break;
case REXP_BIC_INTF:
bic_read = REXP_BIC_I2C_READ;
bic_write = REXP_BIC_I2C_WRITE;
bic_update = REXP_BIC_I2C_UPDATE;
bic_i2c = REXP_BIC_IPMI_I2C_SW;
break;
case RREXP_BIC_INTF1:
bic_read = RREXP1_BIC_I2C_READ;
bic_write = RREXP1_BIC_I2C_WRITE;
bic_update = RREXP1_BIC_I2C_UPDATE;
bic_i2c = RREXP1_BIC_IPMI_I2C_SW;
bytes_per_read = 224;
break;
case RREXP_BIC_INTF2:
bic_read = RREXP2_BIC_I2C_READ;
bic_write = RREXP2_BIC_I2C_WRITE;
bic_update = RREXP2_BIC_I2C_UPDATE;
bic_i2c = RREXP2_BIC_IPMI_I2C_SW;
bytes_per_read = 224;
break;
default:
syslog(LOG_WARNING, "%s() unknown information, slot id:%d, intf: 0x%X", __func__, slot_id, intf);
return -1;
}
printf("bytes/per read = %d\n", bytes_per_read);
//step1 - make the remote bic enter bootloader
ret = enable_remote_bic_update(slot_id, intf);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Enable the remote bic update, Fail, ret = %d\n", ret);
// goto exit;
}
//step2 - adjust the bus of i2c speed of bridge BIC
ret = setup_remote_bic_i2c_speed(slot_id, I2C_100K, bic_i2c);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Set the speed of the remote bic to 100K, Fail, ret = %d\n", ret);
goto exit;
}
//wait for it ready
sleep(5);
//step3 - send a signal to notice it that starts the update process
ret = send_start_bic_update(slot_id, 0, file_size, bic_write);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Send start remote bic update, Fail, ret = %d\n", ret);
goto exit;
}
//wait for it ready
msleep(500);
//step4 - check the response of the signal
ret = read_bic_update_ack_status(slot_id, 0, bic_read);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Check remote bic update status, Fail, ret = %d\n", ret);
goto exit;
}
//step5 - send the pieces data of the image till the end
ret = send_bic_runtime_image_data(slot_id, fd, 0, file_size, bytes_per_read, bic_update);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Send image data, Fail, ret = %d\n", ret);
goto exit;
}
//step6 - send a signal to complete it
ret = send_complete_signal(slot_id, 0, bic_write);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Send complete signal, Fail, ret = %d\n", ret);
goto exit;
}
//step7 - check the response of the signal
ret = read_bic_update_ack_status(slot_id, 0, bic_read);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Get the bic status, Fail, ret = %d\n", ret);
}
exit:
//record the value
is_fail = ret;
//step8 - recover the bus of the i2c speed
ret = setup_remote_bic_i2c_speed(slot_id, I2C_1M, bic_i2c);
if ( ret < 0 ) {
syslog(LOG_WARNING, "Set the speed of the remote bic to 1M, Fail, ret = %d\n", ret);
}
if ((intf == BB_BIC_INTF) && (bmc_location == NIC_BMC)) {
wait_bic_warm_reset(slot_id, intf);
}
if ( ret == 0 ) ret = is_fail;
return ret;
}
static int
is_valid_bic_image(uint8_t slot_id, uint8_t comp, uint8_t intf, int fd, int file_size){
#define BICBL_TAG 0x00
#define BICBR_TAG 0x01
#define BICBL_OFFSET 0x3f00
#define BICBR_OFFSET 0x8000
int ret = BIC_STATUS_FAILURE;
uint8_t rbuf[2] = {0};
uint8_t signed_bytes[2] = {0};
uint8_t rlen = sizeof(rbuf);
uint8_t sel_comp = 0xff;
uint8_t sel_tag = 0xff;
uint32_t sel_offset = 0xffffffff;
uint8_t board_type = 0;
uint8_t board_revision_id = 0xff;
uint8_t tbuf[4] = {0};
uint8_t tlen = 0;
int ret_val = 0 , retry = 0;
int board_type_index = 0;
bool board_rev_is_invalid = false;
bool check_board_revision = true;
bic_gpio_t gpio = {0};
uint8_t hsc_det = 0;
switch (comp) {
case UPDATE_BIC:
sel_tag = BICBR_TAG;
sel_offset = BICBR_OFFSET;
break;
case UPDATE_BIC_BOOTLOADER:
sel_tag = BICBL_TAG;
sel_offset = BICBL_OFFSET;
break;
}
switch (intf) {
case FEXP_BIC_INTF:
check_board_revision = false;
bic_get_1ou_type(slot_id, &board_type);
if (board_type == EDSFF_1U) {
sel_comp = BIC1OU_E1S;
} else {
sel_comp = BIC1OU;
}
break;
case BB_BIC_INTF:
sel_comp = BICBB;
break;
case REXP_BIC_INTF:
check_board_revision = false;
if ( fby3_common_get_2ou_board_type(slot_id, &board_type) < 0 ) {
syslog(LOG_ERR, "%s() Cannot get board_type", __func__);
goto error_exit;
}
if ( board_type == M2_BOARD ) {
sel_comp = BIC2OU;
} else if ( board_type == E1S_BOARD ) {
sel_comp = BICSPE;
} else if ( board_type == CWC_MCHP_BOARD ) {
sel_comp = BICCWC;
} else {
sel_comp = BICGPV3;
}
break;
case RREXP_BIC_INTF1:
case RREXP_BIC_INTF2:
check_board_revision = false;
sel_comp = BICGPV3;
break;
case NONE_INTF:
sel_comp = BICDL;
break;
}
if ( lseek(fd, sel_offset, SEEK_SET) != (off_t)sel_offset ) {
goto error_exit;
}
rlen = sizeof(rbuf);
if ( read(fd, rbuf, rlen) != (off_t)rlen ) {
goto error_exit;
}
memcpy(signed_bytes, rbuf, sizeof(signed_bytes));
if ( signed_bytes[0] != sel_tag || COMPONENT_ID(signed_bytes[1]) != COMPONENT_ID(sel_comp) ) {
goto error_exit;
}
if (check_board_revision) {
switch (intf) {
/* need to Get the corresponding Board Revision */
case BB_BIC_INTF:
// Read Board Revision from BB CPLD
tbuf[0] = CPLD_BB_BUS;
tbuf[1] = CPLD_FLAG_REG_ADDR;
tbuf[2] = 0x01;
tbuf[3] = BB_CPLD_BOARD_REV_ID_REGISTER;
tlen = 4;
retry = 0;
while (retry < RETRY_TIME) {
ret_val = bic_ipmb_send(slot_id, NETFN_APP_REQ, CMD_APP_MASTER_WRITE_READ, tbuf, tlen, rbuf, &rlen, BB_BIC_INTF);
if ( ret_val < 0 ) {
retry++;
msleep(100);
} else {
break;
}
}
if (retry == RETRY_TIME) {
syslog(LOG_WARNING, "%s() Failed to get board revision via BB CPLD, tlen=%d", __func__, tlen);
goto error_exit;
}
board_revision_id = rbuf[0];
break;
case NONE_INTF:
// Read Board Revision from SB CPLD
if ( fby3_common_get_sb_board_rev(slot_id, &board_revision_id) ) {
syslog(LOG_WARNING, "Failed to get sb board rev");
goto error_exit;
}
// respin board, Need to process BOARD_REV through HSC_DETECT, keeping the original logic work
ret = bic_get_gpio(slot_id, &gpio, NONE_INTF);
if ( ret < 0 ) {
syslog(LOG_WARNING, "%s() bic_get_gpio returns %d\n", __func__, ret);
goto error_exit;
}
hsc_det |= ((BIT_VALUE(gpio, 77)) << 0); // 77 HSC_DETECT0
hsc_det |= ((BIT_VALUE(gpio, 78)) << 1); // 78 HSC_DETECT1
hsc_det |= ((BIT_VALUE(gpio, 79)) << 2); // 79 HSC_DETECT2
if ( hsc_det == HSC_DET_ADM1278 ) {
// old board, BOARD_REV_ID3 is floating.
board_revision_id &= 0x7;
} else {
// new respin board is the MP stage,
// rise bit3 to keep "if (board_type_index < CPLD_BOARD_PVT_REV)" work.
board_revision_id |= 0x8;
}
break;
case FEXP_BIC_INTF:
case REXP_BIC_INTF:
case RREXP_BIC_INTF1:
case RREXP_BIC_INTF2:
//TBD : get the Board Revision of expansion board ?
break;
}
board_type_index = board_revision_id - 1;
if (board_type_index < 0) {
board_type_index = 0;
}
// PVT & MP firmware could be used in common
if (board_type_index < CPLD_BOARD_PVT_REV) {
if (REVISION_ID(signed_bytes[1]) != board_type_index) {
board_rev_is_invalid = true;
}
} else {
if (REVISION_ID(signed_bytes[1]) < CPLD_BOARD_PVT_REV) {
board_rev_is_invalid = true;
}
}
if ( board_rev_is_invalid) {
printf("To prevent this update on slot%d , please use the f/w of %s on the %s system\n",
slot_id, board_stage[board_type_index], board_stage[board_type_index]);
printf("To force the update, please use the --force option.\n");
goto error_exit;
}
}
ret = BIC_STATUS_SUCCESS;
error_exit:
if ( ret == BIC_STATUS_FAILURE) {
printf("This file cannot be updated to this component!\n");
}
return ret;
}
static int
update_bic_runtime_fw(uint8_t slot_id, uint8_t comp,uint8_t intf, char *path, uint8_t force) {
int ret = BIC_STATUS_FAILURE;
int fd = 0;
int file_size;
//get fd and file size
fd = open_and_get_size(path, &file_size);
if ( fd < 0 ) {
syslog(LOG_WARNING, "%s() cannot open the file: %s, fd=%d\n", __func__, path, fd);
goto exit;
}
printf("file size = %d bytes, slot = %d, intf = 0x%x\n", file_size, slot_id, intf);
//check the content of the image
if ( !force && ( is_valid_bic_image(slot_id, comp, intf, fd, file_size) < 0) ) {
printf("Invalid BIC file!\n");
goto exit;
}
//run into the different function based on the interface
switch (intf) {
case FEXP_BIC_INTF:
case BB_BIC_INTF:
case REXP_BIC_INTF:
case RREXP_BIC_INTF1:
case RREXP_BIC_INTF2:
ret = update_remote_bic(slot_id, intf, fd, file_size);
break;
case NONE_INTF:
ret = update_bic(slot_id, fd, file_size);
break;
}
exit:
if ( fd > 0 ) {
close(fd);
}
return ret;
}
#define IPMB_MAX_SEND 224
static int
update_fw_bic_bootloader(uint8_t slot_id, uint8_t comp, uint8_t intf, int fd, int file_size) {
uint8_t bytes_per_read = IPMB_MAX_SEND;
uint8_t buf[256] = {0};
uint16_t buf_size = sizeof(buf);
uint16_t read_bytes = 0;
uint32_t offset = 0;
uint32_t last_offset = 0;
uint32_t dsize = 0;
int ret = -1, retry = IPMB_BIC_RETRY;
uint8_t self_test_result[2] = {0};
uint8_t bmc_location = 0;
ret = fby3_common_get_bmc_location(&bmc_location);
if (ret < 0) {
syslog(LOG_WARNING, "%s() Cannot get the location of BMC", __func__);
return -1;
}
dsize = file_size / 20;
if ( lseek(fd, 0, SEEK_SET) != 0 ) {
syslog(LOG_WARNING, "%s() Cannot reinit the fd to the beginning. errstr=%s", __func__, strerror(errno));
return -1;
}
if (intf == RREXP_BIC_INTF1 || intf == RREXP_BIC_INTF2) {
bytes_per_read -= IPMB_BRIDGE_OVERHEAD;
}
printf("Update BIC bootloader\n");
while (1) {
memset(buf, 0, buf_size);
read_bytes = read(fd, buf, bytes_per_read);
if ( read_bytes <= 0 ) {
//no more bytes can be read
break;
}
if ((offset + read_bytes) >= file_size) {
comp |= 0x80;
}
ret = send_image_data_via_bic(slot_id, comp, intf, offset, read_bytes, 0x0, buf);
if (ret != BIC_STATUS_SUCCESS)
break;
offset += read_bytes;
if ((last_offset + dsize) <= offset) {
printf("updated bic bootloader: %d %%\n", (offset/dsize)*5);
fflush(stdout);
last_offset += dsize;
}
}
// Wait for warm reset finished
sleep(3);
while (retry > 0){
sleep(1);
ret = bic_get_self_test_result(slot_id, (uint8_t *)&self_test_result, NONE_INTF);
if (ret == 0) {
break;
} else {
retry--;
}
}
return ret;
}
static int
update_bic_bootloader_fw(uint8_t slot_id, uint8_t comp, uint8_t intf, char *path, uint8_t force) {
int fd = 0;
int ret = BIC_STATUS_FAILURE;
int file_size = 0;
fd = open_and_get_size(path, &file_size);
if (fd < 0) {
syslog(LOG_WARNING, "%s() cannot open the file: %s, fd=%d", __func__, path, fd);
goto exit;
}
printf("file size = %d bytes, slot = %d, comp = 0x%x\n", file_size, slot_id, comp);
//check the content of the image
if ( !force && (is_valid_bic_image(slot_id, comp, intf, fd, file_size) < 0) ) {
printf("Invalid BIC bootloader file!\n");
goto exit;
}
ret = update_fw_bic_bootloader(slot_id, comp, intf, fd, file_size);
exit:
if (fd > 0) {
close(fd);
}
return ret;
}
static int
ctrl_bic_sensor_monitor(uint8_t slot_id, uint8_t intf, bool stop_bic_montr_en) {
int ret = 0;
printf("* Turning %s BIC sensor monitor...\n", (stop_bic_montr_en == true)?"off":"on");
ret = bic_enable_ssd_sensor_monitor(slot_id, !stop_bic_montr_en, intf);
if ( ret < 0 ) {
printf("* Failed to %s bic sensor monitor aborted!\n", (stop_bic_montr_en == true)?"stop":"start");
} else sleep(2);
return ret;
}
static int
ctrl_pesw_error_monitor(uint8_t slot_id, uint8_t intf, bool stop_bic_montr_en) {
uint8_t tbuf[4] = {0x9c, 0x9c, 0x00, (stop_bic_montr_en == true)?0x00:0x01};
uint8_t rbuf[16] = {0};
uint8_t rlen = 0;
int ret = BIC_STATUS_SUCCESS;
printf("* Turning %s PESW error monitor...\n", (stop_bic_montr_en == true)?"off":"on");
ret = bic_ipmb_send(slot_id, NETFN_OEM_1S_REQ, BIC_CMD_OEM_PESW_ERR_MONITOR, tbuf, 4, rbuf, &rlen, intf);
if ( ret < 0 ) {
printf("Failed to %s PESW error monitor, is the BIC firmware too old(<= D02)? aborted!\n", (stop_bic_montr_en == true)?"stop":"start");
} else sleep(2);
return ret;
}
static char*
get_component_name(uint8_t comp) {
switch (comp) {
case FW_CPLD:
return "SB CPLD";
case FW_BIC:
return "SB BIC";
case FW_BIC_BOOTLOADER:
return "SB BIC Bootloader";
case FW_VR:
return "VR";
case FW_BIOS:
return "BIOS";
case FW_1OU_BIC:
return "1OU BIC";
case FW_1OU_BIC_BOOTLOADER:
return "1OU BIC Bootloader";
case FW_1OU_CPLD:
return "1OU CPLD";
case FW_2OU_BIC:
return "2OU BIC";
case FW_2OU_BIC_BOOTLOADER:
return "2OU BIC Bootloader";
case FW_2OU_CPLD:
return "2OU CPLD";
case FW_BB_BIC:
return "BB BIC";
case FW_BB_BIC_BOOTLOADER:
return "BB BIC Bootloader";
case FW_BB_CPLD:
return "BB CPLD";
case FW_BIOS_CAPSULE:
return "BIOS Capsule, Target to Active Region";
case FW_BIOS_RCVY_CAPSULE:
return "BIOS Capsule, Target to Recovery Region";
case FW_CPLD_CAPSULE:
return "CPLD Capsule, Target to Active Region";
case FW_CPLD_RCVY_CAPSULE:
return "CPLD Capsule, Target to Recovery Region";
case FW_2OU_PESW:
return "2OU PCIe Switch";
case FW_2OU_PESW_VR:
return "2OU PCIe VR";
case FW_2OU_3V3_VR1:
return "2OU VR_P3V3_STBY1";
case FW_2OU_3V3_VR2:
return "2OU VR_P3V3_STBY2";
case FW_2OU_3V3_VR3:
return "2OU VR_P3V3_STBY3";
case FW_2OU_1V8_VR:
return "2OU VR_P1V8";
case FW_2OU_M2_DEV0:
return "2OU M2 Dev0";
case FW_2OU_M2_DEV1:
return "2OU M2 Dev1";
case FW_2OU_M2_DEV2:
return "2OU M2 Dev2";
case FW_2OU_M2_DEV3:
return "2OU M2 Dev3";
case FW_2OU_M2_DEV4:
return "2OU M2 Dev4";
case FW_2OU_M2_DEV5:
return "2OU M2 Dev5";
case FW_2OU_M2_DEV6:
return "2OU M2 Dev6";
case FW_2OU_M2_DEV7:
return "2OU M2 Dev7";
case FW_2OU_M2_DEV8:
return "2OU M2 Dev8";
case FW_2OU_M2_DEV9:
return "2OU M2 Dev9";
case FW_2OU_M2_DEV10:
return "2OU M2 Dev10";
case FW_2OU_M2_DEV11:
return "2OU M2 Dev11";
case FW_CWC_BIC:
return "CWC BIC";
case FW_CWC_BIC_BL:
return "CWC BIC Bootloader";
case FW_CWC_CPLD:
return "CWC CPLD";
case FW_CWC_PESW:
return "CWC PCIe Switch";
case FW_GPV3_TOP_BIC:
return "2U Top BIC";
case FW_GPV3_TOP_BIC_BL:
return "2U Top BIC Bootloader";
case FW_GPV3_TOP_CPLD:
return "2U Top CPLD";
case FW_GPV3_TOP_PESW:
return "2U Top PCIe Switch";
case FW_GPV3_BOT_BIC:
return "2U Bottom BIC";
case FW_GPV3_BOT_BIC_BL:
return "2U Bottom BIC Bootloader";
case FW_GPV3_BOT_CPLD:
return "2U Bottom CPLD";
case FW_GPV3_BOT_PESW:
return "2U Bottom PCIe Switch";
case FW_CWC_PESW_VR:
return "CWC PCIe VR";
case FW_GPV3_TOP_PESW_VR:
return "2U Top PCIe VR";
case FW_GPV3_BOT_PESW_VR:
return "2U Bottom PCIe VR";
case FW_2U_TOP_3V3_VR1:
return "2U Top VR_P3V3_STBY1";
case FW_2U_TOP_3V3_VR2:
return "2U Top VR_P3V3_STBY2";
case FW_2U_TOP_3V3_VR3:
return "2U Top VR_P3V3_STBY3";
case FW_2U_TOP_1V8_VR:
return "2U Top VR_P1V8";
case FW_2U_BOT_3V3_VR1:
return "2U Bottom VR_P3V3_STBY1";
case FW_2U_BOT_3V3_VR2:
return "2U Bottom VR_P3V3_STBY2";
case FW_2U_BOT_3V3_VR3:
return "2U Bottom VR_P3V3_STBY3";
case FW_2U_BOT_1V8_VR:
return "2U Bottom VR_P1V8";
case FW_TOP_M2_DEV0:
return "2U Top M2 Dev0";
case FW_TOP_M2_DEV1:
return "2U Top M2 Dev1";
case FW_TOP_M2_DEV2:
return "2U Top M2 Dev2";
case FW_TOP_M2_DEV3:
return "2U Top M2 Dev3";
case FW_TOP_M2_DEV4:
return "2U Top M2 Dev4";
case FW_TOP_M2_DEV5:
return "2U Top M2 Dev5";
case FW_TOP_M2_DEV6:
return "2U Top M2 Dev6";
case FW_TOP_M2_DEV7:
return "2U Top M2 Dev7";
case FW_TOP_M2_DEV8:
return "2U Top M2 Dev8";
case FW_TOP_M2_DEV9:
return "2U Top M2 Dev9";
case FW_TOP_M2_DEV10:
return "2U Top M2 Dev10";
case FW_TOP_M2_DEV11:
return "2U Top M2 Dev11";
case FW_BOT_M2_DEV0:
return "2U Bottom M2 Dev0";
case FW_BOT_M2_DEV1:
return "2U Bottom M2 Dev1";
case FW_BOT_M2_DEV2:
return "2U Bottom M2 Dev2";
case FW_BOT_M2_DEV3:
return "2U Bottom M2 Dev3";
case FW_BOT_M2_DEV4:
return "2U Bottom M2 Dev4";
case FW_BOT_M2_DEV5:
return "2U Bottom M2 Dev5";
case FW_BOT_M2_DEV6:
return "2U Bottom M2 Dev6";
case FW_BOT_M2_DEV7:
return "2U Bottom M2 Dev7";
case FW_BOT_M2_DEV8:
return "2U Bottom M2 Dev8";
case FW_BOT_M2_DEV9:
return "2U Bottom M2 Dev9";
case FW_BOT_M2_DEV10:
return "2U Bottom M2 Dev10";
case FW_BOT_M2_DEV11:
return "2U Bottom M2 Dev11";
default:
return "Unknown";
}
return "NULL";
}
static int
bic_update_fw_path_or_fd(uint8_t slot_id, uint8_t comp, char *path, int fd, uint8_t force) {
int ret = BIC_STATUS_SUCCESS;
uint8_t intf = 0x0;
char ipmb_content[] = "ipmb";
char* loc = NULL;
bool stop_bic_monitoring = false;
bool reset_usbhub = false;
char fdstr[32] = {0};
bool fd_opened = false;
if (path == NULL) {
if (fd < 0) {
syslog(LOG_ERR, "%s(): Update aborted due to NULL pointer: *path", __func__);
return -1;
}
snprintf(fdstr, sizeof(fdstr) - 1, "<%d>", fd);
path = fdstr;
} else {
fd = open(path, O_RDONLY, 0);
if (fd < 0) {
syslog(LOG_ERR, "%s(): Unable to open %s: %d", __func__, path, errno);
return -1;
}
fd_opened = true;
}
loc = strstr(path, ipmb_content);
fprintf(stderr, "slot_id: %x, comp: %x, intf: %x, img: %s, force: %x\n", slot_id, comp, intf, path, force);
syslog(LOG_CRIT, "Updating %s on slot%d. File: %s", get_component_name(comp), slot_id, path);
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");
} else if ( board_type == GPV3_MCHP_BOARD ||
board_type == GPV3_BRCM_BOARD ||
board_type == CWC_MCHP_BOARD ) {
stop_bic_monitoring = true;
}
//get the intf
switch (comp) {
case FW_CPLD:
case FW_ME:
case FW_BIC:
case FW_BIC_BOOTLOADER:
case FW_VR:
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_PESW:
case FW_2OU_PESW_VR:
case FW_2OU_3V3_VR1:
case FW_2OU_3V3_VR2:
case FW_2OU_3V3_VR3:
case FW_2OU_1V8_VR:
case FW_2OU_M2_DEV0:
case FW_2OU_M2_DEV1:
case FW_2OU_M2_DEV2:
case FW_2OU_M2_DEV3:
case FW_2OU_M2_DEV4:
case FW_2OU_M2_DEV5:
case FW_2OU_M2_DEV6:
case FW_2OU_M2_DEV7:
case FW_2OU_M2_DEV8:
case FW_2OU_M2_DEV9:
case FW_2OU_M2_DEV10:
case FW_2OU_M2_DEV11:
case FW_CWC_BIC:
case FW_CWC_BIC_BL:
case FW_CWC_CPLD:
case FW_CWC_PESW:
case FW_CWC_PESW_VR:
reset_usbhub = true;
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_3V3_VR1:
case FW_2U_TOP_3V3_VR2:
case FW_2U_TOP_3V3_VR3:
case FW_2U_TOP_1V8_VR:
case FW_TOP_M2_DEV0:
case FW_TOP_M2_DEV1:
case FW_TOP_M2_DEV2:
case FW_TOP_M2_DEV3:
case FW_TOP_M2_DEV4:
case FW_TOP_M2_DEV5:
case FW_TOP_M2_DEV6:
case FW_TOP_M2_DEV7:
case FW_TOP_M2_DEV8:
case FW_TOP_M2_DEV9:
case FW_TOP_M2_DEV10:
case FW_TOP_M2_DEV11:
reset_usbhub = true;
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_3V3_VR1:
case FW_2U_BOT_3V3_VR2:
case FW_2U_BOT_3V3_VR3:
case FW_2U_BOT_1V8_VR:
case FW_BOT_M2_DEV0:
case FW_BOT_M2_DEV1:
case FW_BOT_M2_DEV2:
case FW_BOT_M2_DEV3:
case FW_BOT_M2_DEV4:
case FW_BOT_M2_DEV5:
case FW_BOT_M2_DEV6:
case FW_BOT_M2_DEV7:
case FW_BOT_M2_DEV8:
case FW_BOT_M2_DEV9:
case FW_BOT_M2_DEV10:
case FW_BOT_M2_DEV11:
reset_usbhub = true;
intf = RREXP_BIC_INTF2;
break;
}
// if intf is BB_BIC_INTF and the critical activity bit is asserted
if ( (intf == BB_BIC_INTF) && (bic_is_crit_act_ongoing(slot_id) == true) ) {
printf("A critical activity is ongoing on the sled, exit.\n");
ret = BIC_STATUS_FAILURE;
goto error_exit;
}
if (intf == BB_BIC_INTF) {
if (bb_fw_update_prepare(slot_id) < 0) {
printf("Please check another slot BMC is not updating BB firmware\n");
ret = BIC_STATUS_FAILURE;
goto error_exit;
}
}
// reset HUB if needed
// because many devices are attached to the USB HUB,
// perform the reset to make sure the HUB can work normally with the power change
if ( reset_usbhub == true ) {
uint8_t status = 0;
ret = bic_get_server_power_status(slot_id, &status);
if ( ret < 0 ) {
printf("Failed to get the power status\n");
goto error_exit;
} else if ( status == 0/*SERVER_POWER_OFF*/ ) {
// run reset
ret = bic_usb_hub_reset(slot_id, board_type, intf);
if ( ret < 0 ) {
goto error_exit;
}
}
}
//run cmd
switch (comp) {
case FW_BIC:
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:
ret = update_bic_runtime_fw(slot_id, UPDATE_BIC, intf, path, force);
break;
case FW_BIC_BOOTLOADER:
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:
ret = update_bic_bootloader_fw(slot_id, UPDATE_BIC_BOOTLOADER, intf , path, force);
break;
case FW_1OU_CPLD:
case FW_2OU_CPLD:
case FW_CWC_CPLD:
case FW_GPV3_TOP_CPLD:
case FW_GPV3_BOT_CPLD:
if ( stop_bic_monitoring && (ret = ctrl_bic_sensor_monitor(slot_id, intf, stop_bic_monitoring)) < 0 ) {
break;
}
ret = (loc != NULL)?update_bic_cpld_lattice(slot_id, path, intf, force): \
update_bic_cpld_lattice_usb(slot_id, path, intf, force);
if ( (ret == BIC_STATUS_SUCCESS && stop_bic_monitoring) && \
(ret = ctrl_bic_sensor_monitor(slot_id, intf, !stop_bic_monitoring)) < 0 );
break;
case FW_BB_CPLD:
case FW_CPLD:
ret = update_bic_cpld_altera(slot_id, path, intf, force);
break;
case FW_BIOS:
case FW_BIOS_CAPSULE:
case FW_CPLD_CAPSULE:
case FW_BIOS_RCVY_CAPSULE:
case FW_CPLD_RCVY_CAPSULE:
if (loc != NULL) {
ret = update_bic_bios(slot_id, comp, path, FORCE_UPDATE_SET);
} else {
ret = update_bic_usb_bios(slot_id, comp, fd);
}
break;
case FW_VR:
ret = update_bic_vr(slot_id, comp, path, intf, force, false/*usb update?*/);
break;
case FW_2OU_3V3_VR1:
case FW_2OU_3V3_VR2:
case FW_2OU_3V3_VR3:
case FW_2OU_1V8_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 = update_bic_vr(slot_id, comp, path, intf, force, true/*usb update*/);
break;
case FW_2OU_PESW_VR:
case FW_CWC_PESW_VR:
case FW_GPV3_TOP_PESW_VR:
case FW_GPV3_BOT_PESW_VR:
ret = (loc != NULL)?update_bic_vr(slot_id, comp, path, intf, force, false/*usb update*/): \
update_bic_vr(slot_id, comp, path, intf, force, true/*usb update*/);
break;
case FW_2OU_PESW:
case FW_CWC_PESW:
case FW_GPV3_TOP_PESW:
case FW_GPV3_BOT_PESW:
// we should stop polling sensors while updating PESW
if ( (stop_bic_monitoring && (ret = ctrl_bic_sensor_monitor(slot_id, intf, stop_bic_monitoring)) < 0) || \
(stop_bic_monitoring && (ret = ctrl_pesw_error_monitor(slot_id, intf, stop_bic_monitoring)) < 0) ) {
break;
}
// run the update
if (board_type == GPV3_BRCM_BOARD) {
ret = BIC_STATUS_FAILURE; /*not supported*/
} else {
ret = update_bic_mchp(slot_id, comp, path, intf, force, (loc != NULL)?false:true);
}
// start polling again
if ( (ret == BIC_STATUS_SUCCESS && stop_bic_monitoring) && \
(((ret = ctrl_bic_sensor_monitor(slot_id, intf, !stop_bic_monitoring)) < 0) || \
((ret = ctrl_pesw_error_monitor(slot_id, intf, !stop_bic_monitoring)) < 0)) );
break;
case FW_2OU_M2_DEV0:
case FW_2OU_M2_DEV1:
case FW_2OU_M2_DEV2:
case FW_2OU_M2_DEV3:
case FW_2OU_M2_DEV4:
case FW_2OU_M2_DEV5:
case FW_2OU_M2_DEV6:
case FW_2OU_M2_DEV7:
case FW_2OU_M2_DEV8:
case FW_2OU_M2_DEV9:
case FW_2OU_M2_DEV10:
case FW_2OU_M2_DEV11:
case FW_TOP_M2_DEV0:
case FW_TOP_M2_DEV1:
case FW_TOP_M2_DEV2:
case FW_TOP_M2_DEV3:
case FW_TOP_M2_DEV4:
case FW_TOP_M2_DEV5:
case FW_TOP_M2_DEV6:
case FW_TOP_M2_DEV7:
case FW_TOP_M2_DEV8:
case FW_TOP_M2_DEV9:
case FW_TOP_M2_DEV10:
case FW_TOP_M2_DEV11:
case FW_BOT_M2_DEV0:
case FW_BOT_M2_DEV1:
case FW_BOT_M2_DEV2:
case FW_BOT_M2_DEV3:
case FW_BOT_M2_DEV4:
case FW_BOT_M2_DEV5:
case FW_BOT_M2_DEV6:
case FW_BOT_M2_DEV7:
case FW_BOT_M2_DEV8:
case FW_BOT_M2_DEV9:
case FW_BOT_M2_DEV10:
case FW_BOT_M2_DEV11:
if ( stop_bic_monitoring && (ret = ctrl_bic_sensor_monitor(slot_id, intf, stop_bic_monitoring)) < 0 ) {
break;
}
uint8_t nvme_ready = 0, status = 0, type = 0, m2_dev = 0;
if (comp >= FW_TOP_M2_DEV0 && comp <= FW_TOP_M2_DEV11) {
m2_dev = (comp - FW_TOP_M2_DEV0) + FW_2OU_M2_DEV0;
ret = bic_get_dev_info(FRU_2U_TOP, (comp - FW_TOP_M2_DEV0) + 1, &nvme_ready ,&status, &type);
} else if (comp >= FW_BOT_M2_DEV0 && comp <= FW_BOT_M2_DEV11) {
m2_dev = (comp - FW_BOT_M2_DEV0) + FW_2OU_M2_DEV0;
ret = bic_get_dev_info(FRU_2U_BOT, (comp - FW_BOT_M2_DEV0) + 1, &nvme_ready ,&status, &type);
} else {
m2_dev = comp;
ret = bic_get_dev_info(slot_id, (comp - FW_2OU_M2_DEV0) + 1, &nvme_ready ,&status, &type);
}
if (ret) {
printf("* Failed to read m.2 device's info\n");
ret = BIC_STATUS_FAILURE;
break;
} else {
ret = update_bic_m2_fw(slot_id, m2_dev, path, intf, force, type);
}
if ( (ret == BIC_STATUS_SUCCESS && stop_bic_monitoring) && \
(ret = ctrl_bic_sensor_monitor(slot_id, intf, !stop_bic_monitoring)) < 0 );
break;
} /*end of switch*/
if (intf == BB_BIC_INTF) {
if (bb_fw_update_finish(slot_id) < 0) {
printf("Failed to clear BB update register\n");
}
}
error_exit:
syslog(LOG_CRIT, "Updated %s on slot%d. File: %s. Result: %s", get_component_name(comp), slot_id, path, (ret != 0)?"Fail":"Success");
if (fd_opened) {
close(fd);
}
return ret;
}
int
bic_update_fw(uint8_t slot_id, uint8_t comp, char *path, uint8_t force) {
return bic_update_fw_path_or_fd(slot_id, comp, path, -1, force);
}
int
bic_update_fw_fd(uint8_t slot_id, uint8_t comp, int fd, uint8_t force) {
return bic_update_fw_path_or_fd(slot_id, comp, NULL, fd, force);
}