common/recipes-lib/psu/files/psu.c (1,526 lines of code) (raw):
/*
* Copyright 2020-present Facebook. All Rights Reserved.
*
* 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 <signal.h>
#include <limits.h>
#include <openbmc/obmc-i2c.h>
#include <openbmc/fruid.h>
#include <openbmc/log.h>
#include <facebook/wedge_eeprom.h>
#include "psu.h"
#include "psu-platform.h"
static delta_hdr_t delta_hdr;
static murata_hdr_t murata_hdr;
static murata2k_hdr_t murata2k_hdr;
pmbus_info_t pmbus[] = {
{"MFR_ID", 0x99},
{"MFR_MODEL", 0x9a},
{"MFR_REVISION", 0x9b},
{"MFR_DATE", 0x9d},
{"MFR_SERIAL", 0x9e},
{"PRI_FW_VER", 0xdd},
{"SEC_FW_VER", 0xd7},
{"STATUS_WORD", 0x79},
{"STATUS_VOUT", 0x7a},
{"STATUS_IOUT", 0x7b},
{"STATUS_INPUT", 0x7c},
{"STATUS_TEMP", 0x7d},
{"STATUS_CML", 0x7e},
{"STATUS_FAN", 0x81},
{"STATUS_STBY_WORD", 0xd3},
{"STATUS_VSTBY", 0xd4},
{"STATUS_ISTBY", 0xd5},
{"OPTN_TIME_TOTAL", 0xd8},
{"OPTN_TIME_PRESENT", 0xd9},
};
static int g_fd = -1;
static void
exithandler(int signum) {
printf("\nPSU update abort!\n");
syslog(LOG_WARNING, "PSU update abort!");
close(g_fd);
run_command("rm /var/run/psu-util.pid");
exit(0);
}
static int
i2c_open(uint8_t bus, uint8_t addr) {
int fd = -1;
int rc = -1;
char fn[32];
snprintf(fn, sizeof(fn), "/dev/i2c-%d", bus);
fd = open(fn, O_RDWR);
if (fd == -1) {
syslog(LOG_WARNING, "Failed to open i2c device %s, errno=%d", fn, errno);
return -1;
}
rc = ioctl(fd, I2C_SLAVE_FORCE, addr);
if (rc < 0) {
syslog(LOG_WARNING,
"Failed to open slave @ address 0x%x, errno=%d", addr, errno);
close(fd);
return -1;
}
return fd;
}
/*
* PMBus Linear-11 Data Format
* X = Y*2^N
* X is the "real world" value;
* Y is an 11 bit, two's complement integer;
* N is a 5 bit, two's complement integer.
*/
static float
linear_convert(uint8_t value[]) {
uint16_t data = (value[1] << 8) | value[0];
int y = 0, n = 0;
float x = 0;
uint8_t sign_y = (data >> 10) & 0x1;
uint8_t sign_n = (data >> 15) & 0x1;
y = sign_y ? -1 * ((~data & 0x3ff) + 1) : data & 0x3ff;
n = sign_n ? -1 * ((~(data >> 11) & 0xf) + 1) : (data >> 11) & 0xf;
x = (float) y * pow(2, n);
return x;
}
static time_info_t
time_convert(uint32_t value) {
time_info_t record;
record.day = value / 86400;
record.hour = (value / 3600) % 24;
record.min = (value / 60) % 60;
record.sec = value % 60;
return record;
}
static int
ascii_to_hex(int ascii) {
ascii = ascii & 0xFF;
if (ascii >= 0x30 && ascii <= 0x39) {
return (ascii - 0x30); /* 0-9 */
} else if (ascii >= 0x41 && ascii <= 0x46) {
return (ascii - 0x41 + 10); /* A-F */
} else if (ascii >= 0x61 && ascii <= 0x66) {
return (ascii - 0x61 + 10); /* a-f */
} else {
return -1;
}
}
static uint8_t
hex_to_byte(uint8_t hbyte, uint8_t lbyte) {
return (ascii_to_hex(hbyte) << 4) | ascii_to_hex(lbyte);
}
static int
check_file_len(const char *file_path) {
struct stat st;
if (stat(file_path, &st) != 0) {
return -1;
}
if (st.st_size > INT_MAX) {
errno = EFBIG;
return -1; /* integer overflow */
}
return (int)st.st_size;
}
static int
check_file_line_cnt(const char *file_path) {
FILE *fp = fopen(file_path, "rb");
int c, cnt = 0;
while ((c = fgetc(fp)) != EOF) {
if (c == '\n') {
cnt++;
}
}
fclose(fp);
return cnt;
}
static int
check_psu_status(uint8_t num, uint8_t reg) {
uint8_t byte;
byte = i2c_smbus_read_byte_data(psu[num].fd, reg);
if (byte > 32) {
return byte;
}
return 0;
}
uint8_t
pec_calc(uint8_t incrc, uint8_t indata) {
uint8_t i, crc8;
crc8 = incrc ^ indata;
for (i = 0; i < 8; i++) {
if ((crc8 & 0x80) != 0) {
crc8 <<= 1;
crc8 ^= 0x07;
} else {
crc8 <<= 1;
}
}
return crc8;
}
static int
delta_img_hdr_parse(const char *file_path) {
int i, ret;
int fd_file = -1;
int index = 0;
uint8_t hdr_buf[DELTA_HDR_LENGTH];
fd_file = open(file_path, O_RDONLY, 0666);
if (fd_file < 0) {
ERR_PRINT("delta_img_hdr_parse()");
return -1;
}
if (read(fd_file, hdr_buf, DELTA_HDR_LENGTH) < 0) {
ERR_PRINT("delta_img_hdr_parse()");
close(fd_file);
return -1;
}
delta_hdr.crc[0] = hdr_buf[index++];
delta_hdr.crc[1] = hdr_buf[index++];
delta_hdr.page_start = hdr_buf[index++];
delta_hdr.page_start |= hdr_buf[index++] << 8;
delta_hdr.page_end = hdr_buf[index++];
delta_hdr.page_end |= hdr_buf[index++] << 8;
delta_hdr.byte_per_blk = hdr_buf[index++];
delta_hdr.byte_per_blk |= hdr_buf[index++] << 8;
delta_hdr.blk_per_page = hdr_buf[index++];
delta_hdr.blk_per_page |= hdr_buf[index++] << 8;
delta_hdr.uc = hdr_buf[index++];
delta_hdr.app_fw_major = hdr_buf[index++];
delta_hdr.app_fw_minor = hdr_buf[index++];
delta_hdr.bl_fw_major = hdr_buf[index++];
delta_hdr.bl_fw_minor = hdr_buf[index++];
delta_hdr.fw_id_len = hdr_buf[index++];
for (i = 0; i < delta_hdr.fw_id_len; i++) {
delta_hdr.fw_id[i] = hdr_buf[index++];
}
delta_hdr.compatibility = hdr_buf[index];
if (!strncmp((char *)delta_hdr.fw_id, DELTA_MODEL, strlen(DELTA_MODEL))) {
ret = DELTA_1500;
printf("Vendor: Delta\n");
} else if (!strncmp((char *)delta_hdr.fw_id, DELTA_MODEL_2K,
strlen(DELTA_MODEL_2K))) {
ret = DELTA_2000;
printf("Vendor: Delta\n");
} else if (!strncmp((char *)delta_hdr.fw_id, LITEON_MODEL,
strlen(LITEON_MODEL))) {
ret = LITEON_1500;
printf("Vendor: Liteon\n");
} else if (!strncmp((char *)delta_hdr.fw_id, LITEON_MODEL_DC,
strlen(LITEON_MODEL_DC))) {
ret = LITEON_DC_48;
printf("Vendor: Liteon\n");
} else if (!strncmp((char *)delta_hdr.fw_id, DELTA_MODEL_DC,
strlen(DELTA_MODEL_DC))) {
ret = DELTA_DC_48;
} else {
printf("Get Image Header Fail!\n");
close(fd_file);
return -1;
}
printf("Model: %s\n", delta_hdr.fw_id);
printf("HW Compatibility: %d\n", delta_hdr.compatibility);
if (delta_hdr.uc == 0x10) {
printf("MCU: primary\n");
} else if (delta_hdr.uc == 0x20) {
printf("MCU: secondary\n");
} else {
printf("MCU: unknown number 0x%x\n", delta_hdr.uc);
ret = -1;
}
printf("Ver: %d.%d\n", delta_hdr.app_fw_major, delta_hdr.app_fw_minor);
close(fd_file);
return ret;
}
static int
delta_unlock_upgrade(uint8_t num) {
uint8_t i, j;
uint8_t block[delta_hdr.fw_id_len + 2];
block[0] = delta_hdr.uc;
block[delta_hdr.fw_id_len + 1] = delta_hdr.compatibility;
for (i = 1, j = delta_hdr.fw_id_len-1; i <= delta_hdr.fw_id_len; i++, j--) {
block[i] = delta_hdr.fw_id[j];
}
i2c_smbus_write_block_data(psu[num].fd, UNLOCK_UPGRADE,
sizeof(block), block);
return 0;
}
static int
delta_boot_flag(uint8_t num, uint16_t mode, uint8_t op) {
uint16_t word = (mode << 8) | delta_hdr.uc;
if (op == WRITE) {
if (mode == BOOT_MODE) {
printf("-- Bootloader Mode --\n");
} else {
printf("-- Reset PSU --\n");
}
return i2c_smbus_write_word_data(psu[num].fd, BOOT_FLAG, word);
} else {
return i2c_smbus_read_byte_data(psu[num].fd, BOOT_FLAG);
}
}
static int
delta_fw_transmit(uint8_t num, const char *path) {
FILE* fp;
int fw_len = 0;
int block_total = 0;
int byte_index = 0;
uint16_t page_num_lo = delta_hdr.page_start;
uint16_t block_size = delta_hdr.blk_per_page;
uint16_t page_num_max = delta_hdr.page_end;
uint32_t fw_block = block_size * (page_num_max - page_num_lo + 1);
uint8_t block[I2C_SMBUS_BLOCK_MAX] = {0};
uint8_t fw_buf[16];
uint8_t *fw_data = NULL;
int ret = 0;
fw_len = check_file_len(path);
if (fw_len < 0) {
OBMC_ERROR(errno, "failed to get %s size", path);
return -1;
} else if (fw_len <= 32) {
OBMC_WARN("%s size is too small (%d < 32)\n", path, fw_len);
return -1;
}
fw_len -= 32;
fw_data = malloc(fw_len);
if (fw_data == NULL) {
OBMC_ERROR(errno, "failed to allocate %d bytes", fw_len);
return -1;
}
fp = fopen(path, "rb");
if (fp == NULL) {
OBMC_ERROR(errno, "failed to open %s", path);
ret = -1;
goto exit;
}
ret = fseek(fp, 32, SEEK_SET);
if (ret != 0) {
OBMC_ERROR(errno, "fseek %s failed", path);
goto exit;
}
ret = fread(fw_data, sizeof(*fw_data), fw_len, fp);
if (ret != fw_len) {
OBMC_WARN("failed to read %d items from %s\n", fw_len, path);
ret = -1;
goto exit;
}
if (delta_hdr.uc == 0x10) {
printf("-- Transmit Primary Firmware --\n");
} else if (delta_hdr.uc == 0x20){
printf("-- Transmit Secondary Firmware --\n");
}
while (block_total <= fw_block) {
block[0] = delta_hdr.uc;
/* block[1] - Block Num LO
block[2] - Block Num HI */
if (block[1] < block_size) {
memcpy(&fw_buf[0], &fw_data[byte_index], 16);
memcpy(&block[3], &fw_buf, 16);
i2c_smbus_write_block_data(psu[num].fd, DATA_TO_RAM,
19, block);
if (delta_hdr.uc == 0x10) {
msleep(25);
} else if (delta_hdr.uc == 0x20) {
msleep(5);
}
block[1]++;
block[2] = 0;
block_total++;
byte_index = byte_index + 16;
printf("-- (%d/%d) (%d%%/100%%) --\r",
block_total, fw_block, (100 * block_total) / fw_block);
#ifdef DEBUG
if (delta_boot_flag(num, BOOT_MODE, READ) & 0x20) {
printf("-- FW transmission error --\n");
ret = -1;
goto exit;
}
#endif
} else {
block[1] = (page_num_lo & 0xff);
block[2] = ((page_num_lo >> 8) & 0xff);
i2c_smbus_write_block_data(psu[num].fd, DATA_TO_FLASH,
3, block);
msleep(90);
if (page_num_lo == page_num_max) {
printf("\n");
goto exit;
} else {
page_num_lo++;
block[1] = 0;
block[2] = 0;
}
}
}
exit:
if (fp != NULL)
fclose(fp);
free(fw_data);
return ret;
}
static int
delta_crc_transmit(uint8_t num) {
uint8_t block[] = {delta_hdr.uc, delta_hdr.crc[0], delta_hdr.crc[1]};
printf("-- Transmit CRC --\n");
i2c_smbus_write_block_data(psu[num].fd, CRC_CHECK, sizeof(block), block);
return 0;
}
static int
update_delta_psu(uint8_t num, const char *file_path,
uint8_t model, const char *vendor) {
int ret = -1;
ret = delta_img_hdr_parse(file_path);
if (vendor == NULL) {
if (ret != model) {
printf("PSU and image doesn't match!\n");
return UPDATE_SKIP;
}
}
if (ret == DELTA_1500 || ret == LITEON_1500 || ret == DELTA_2000 ||
ret == LITEON_DC_48 || ret == DELTA_DC_48) {
if (delta_hdr.byte_per_blk != 16) {
printf("Image block size invalid!\n");
return UPDATE_SKIP;
}
if (ioctl(psu[num].fd, I2C_PEC, 1) < 0) {
ERR_PRINT("delta_img_hdr_parse()");
return UPDATE_SKIP;
}
delta_unlock_upgrade(num);
msleep(20);
delta_boot_flag(num, BOOT_MODE, WRITE);
msleep(2500);
#ifdef DEBUG
ret = delta_boot_flag(num, BOOT_MODE, READ) & 0xf;
if ((delta_hdr.uc == 0x10 && ret != 0x0c) ||
(delta_hdr.uc == 0x20 && ret != 0x0d)) {
printf("-- Set Bootloader Mode Error --\n");
return -1;
}
#endif
if (delta_fw_transmit(num, file_path) < 0) {
return -1;
}
delta_crc_transmit(num);
msleep(1500);
delta_boot_flag(num, NORMAL_MODE, WRITE);
if (delta_hdr.uc == 0x10) {
msleep(4000);
} else if (delta_hdr.uc == 0x20) {
msleep(2000);
}
#ifdef DEBUG
ret = delta_boot_flag(num, BOOT_MODE, READ);
if ((ret & 0x7) == 0x4) {
if (ret & 0x80) {
printf("-- Primary FW Identifier Error --\n");
return -1;
} else if (ret & 0x40) {
printf("-- Primary CRC16 Application Checksum Wrong --\n");
return -1;
}
} else if ((ret & 0x7) == 0x5) {
if (ret & 0x80) {
printf("-- Secondary FW Identifier Error --\n");
return -1;
} else if (ret & 0x40) {
printf("-- Secondary CRC16 Application Checksum Wrong --\n");
return -1;
}
}
#endif
printf("-- Upgrade Done --\n");
return 0;
} else {
return UPDATE_SKIP;
};
}
static int
belpower_img_hdr_parse(const char *file_path) {
FILE* fp;
int i = 1, j = 0;
uint8_t hdr_buf[128];
uint8_t hdr_str[128];
fp = fopen(file_path, "rb");
if (fp == NULL) {
OBMC_ERROR(errno, "%s open failed", file_path);
return -1;
}
if (fgets((char *)hdr_buf, sizeof(hdr_buf), fp) == NULL) {
OBMC_ERROR(errno, "fgets %s failed", file_path);
fclose(fp);
return -1;
}
fclose(fp);
if (hdr_buf[0] == 'H') {
while (i < strlen((char *)hdr_buf) - 4) {
hdr_str[j++] = hex_to_byte(hdr_buf[i], hdr_buf[i+1]);
i = i + 2;
}
hdr_str[j] = '\0';
}
if (strncmp(((char *)hdr_str)+8, BEL_MODEL, 16) != 0) {
printf("Get Image Header Fail!\n");
return -1;
}
printf("Vendor: Belpower\n");
printf("Model: %s\n", BEL_MODEL);
return BELPOWER_1500_NAC;
}
static int
belpower_fw_transmit(uint8_t num, const char *file_path) {
FILE* fp;
uint8_t file_buf[128];
uint8_t byte_buf[128];
uint8_t primary_cmd[3] = {0xC7, 0x00, 0x39};
uint8_t read_cmd[1] = {0xC7};
uint8_t word_receive[2];
uint8_t byte;
uint8_t command = 0;
uint8_t progress = 0;
uint8_t retry = 3;
uint16_t delay = 0;
char error_text[64] = {0};
int ret = 0, i = 0, j = 0;
bool success = true;
fp = fopen(file_path, "rb");
if (fp == NULL) {
OBMC_ERROR(errno, "%s open failed", file_path);
return -1;
}
printf("-- Transmit Firmware --\n");
while (!feof(fp)) {
if (fgets((char *)file_buf, sizeof(file_buf), fp) == NULL) {
OBMC_ERROR(errno, "fgets %s failed", file_path);
fclose(fp);
return -1;
}
while (i < strlen((char *)file_buf) - 4) {
if (i == 0) {
command = file_buf[i++];
}
byte_buf[j++] = hex_to_byte(file_buf[i], file_buf[i+1]);
i = i + 2;
}
byte_buf[j] = '\0';
switch (command) {
case 'H':
break;
case 'L':
/* Skip if previous command was unsuccessful */
if (!success) {
break;
}
/* Log text */
if (strstr((char *)byte_buf, "bootloader") ||
strstr((char *)byte_buf, "application")) {
printf("\n");
printf("%s", byte_buf);
}
break;
case 'T':
/* Skip if previous command was unsuccessful */
if (!success) {
break;
}
delay = ((uint16_t) byte_buf[1]) << 8 | (uint16_t) byte_buf[0];
break;
case 'X':
/* Skip if previous command was successful */
if (success) {
break;
}
/* Exit with error message */
if (strcmp((char *)byte_buf, error_text)) {
memcpy (error_text, byte_buf, sizeof(error_text));
printf("\n");
printf("%s\n", error_text);
};
if (strstr(error_text, "Could not enter primary bootloader")) {
while (retry) {
printf("Retry enter primary bootloader\n");
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
primary_cmd, sizeof(primary_cmd), NULL, 0);
sleep(5);
ret |= i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
read_cmd, 1, word_receive, 2);
if (ret == 0 && word_receive[0] == 0x0
&& word_receive[1] == 0x1) {
success = true;
retry = 0;
} else {
retry--;
}
}
}
break;
case 'M':
/* Check MD5, Skip...*/
break;
case 'W':
/* Skip if previous command was unsuccessful */
if (!success) {
break;
}
/* Send command and check result if necessary */
if (byte_buf[0] == 1) { /* Read */
if (byte_buf[1] == 1) { /* Read byte */
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
&byte_buf[2], byte_buf[0], &byte, byte_buf[1]);
printf("\n");
printf("read byte:0x%.2x\n", byte);
if (ret == 0 && byte == byte_buf[3]) {
success = true;
} else {
success = false;
}
} else if (byte_buf[1] == 2) { /* Read word */
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
&byte_buf[2], byte_buf[0], word_receive, byte_buf[1]);
if (ret == 0 && word_receive[0] == byte_buf[3]
&& word_receive[1] == byte_buf[4]) {
success = true;
} else {
success = false;
}
}
} else { /* Write */
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
&byte_buf[2], byte_buf[0], NULL, 0);
if (!ret) {
success = true;
} else {
success = false;
}
}
if (success && delay != 0) {
msleep(delay);
}
break;
case 'P':
/* Skip if previous command was unsuccessful */
if (!success) {
break;
}
progress = byte_buf[0];
break;
default:
/* Unrecognized command: exit */
break;
}
printf("-- (%d%%/100%%) --\r", progress);
i = 0;
j = 0;
retry = 3;
}
fclose(fp);
printf("\n");
printf("-- Upgrade Done --\n");
return 0;
}
static int
update_belpower_psu(uint8_t num, const char *file_path) {
int ret = -1;
if (belpower_img_hdr_parse(file_path) == BELPOWER_1500_NAC) {
ret = belpower_fw_transmit(num, file_path);
} else {
return UPDATE_SKIP;
};
return ret;
}
static int
murata_img_hdr_parse(const char *file_path) {
FILE* fp;
int line = 0;
uint8_t hdr_buf[128];
uint8_t model_shift = 8;
uint8_t revision_shift = 11;
uint8_t target_shift = 9;
uint8_t unlock_shift = 9;
uint32_t unlock = 0;
fp = fopen(file_path, "rb");
if (fp == NULL) {
OBMC_ERROR(errno, "%s open failed", file_path);
return -1;
}
for (line = 0; line < 6; line++) {
if (fgets((char *)hdr_buf, sizeof(hdr_buf), fp) == NULL) {
OBMC_ERROR(errno, "fgets %s failed", file_path);
fclose(fp);
return -1;
}
switch (line) {
case 1:
if (!strncmp(((char *)hdr_buf)+model_shift, MURATA_MODEL,
strlen(MURATA_MODEL))) {
printf("Vendor: Murata\n");
printf("Model: %s\n", MURATA_MODEL);
} else {
printf("Get Image Header Fail!\n");
fclose(fp);
return -1;
}
break;
case 2:
if (!strncmp((char *)hdr_buf, "revision = ", revision_shift)) {
printf("Ver: %c%c.%c%c\n",
hdr_buf[strlen((char *)hdr_buf) - 8],
hdr_buf[strlen((char *)hdr_buf) - 7],
hdr_buf[strlen((char *)hdr_buf) - 5],
hdr_buf[strlen((char *)hdr_buf) - 4]);
} else {
printf("Get Image Header Fail!\n");
fclose(fp);
return -1;
}
break;
case 3:
if (!strncmp(((char *)hdr_buf)+target_shift, "primary",
strlen("primary"))) {
murata_hdr.uc = 0x50;
} else if (!strncmp(((char *)hdr_buf)+target_shift,
"secondary", strlen("secondary"))) {
murata_hdr.uc = 0x53;
} else {
printf("Get Image Header Fail!\n");
fclose(fp);
return -1;
}
printf("MCU: %s", &hdr_buf[target_shift]);
break;
case 5:
if (!strncmp((char *)hdr_buf, "unlock = ", unlock_shift)) {
unlock = strtoul(((char *)hdr_buf)+unlock_shift, NULL, 0);
memcpy(&murata_hdr.unlock, &unlock, sizeof(murata_hdr.unlock));
} else {
printf("Get Image Header Fail!\n");
fclose(fp);
return -1;
}
break;
default:
break;
}
}
fclose(fp);
murata_hdr.boot_addr = 0x60;
return MURATA_1500;
}
static int
murata_bootload_mode(uint8_t num) {
int ret = -1, i;
uint8_t cmd[] = {psu[num].pmbus_addr << 1, 0xfa,
murata_hdr.unlock[3], murata_hdr.unlock[2],
murata_hdr.unlock[1], murata_hdr.unlock[0]};
uint8_t pec = 0;
for (i = 0; i < 6; i++) {
pec = pec_calc(pec, cmd[i]);
}
uint8_t block[] = {0xfa,
murata_hdr.unlock[3], murata_hdr.unlock[2],
murata_hdr.unlock[1], murata_hdr.unlock[0], pec};
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
block, sizeof(block), NULL, 0);
return ret;
}
static int
murata_upgrade_status(int fd_i2c, uint8_t num) {
uint8_t byte = 0xfa;
uint8_t byte_receive = 0;
i2c_rdwr_msg_transfer(fd_i2c, murata_hdr.boot_addr << 1,
&byte, 1, &byte_receive, 1);
return byte_receive;
}
static int
murata_end_of_file(int fd_i2c, uint8_t num) {
int ret = -1;
uint8_t block[] = {0xfa, 0x44, 0x00, 0x00, 0x00, 0x01, 0xff};
ret = i2c_rdwr_msg_transfer(fd_i2c, murata_hdr.boot_addr << 1,
block, sizeof(block), NULL, 0);
printf("-- Transmit EOF --\n");
return ret;
}
static int
murata_reset_psu(int fd_i2c, uint8_t num) {
int ret = -1;
uint8_t block[] = {0xf8, 0xaf};
ret = i2c_rdwr_msg_transfer(fd_i2c, murata_hdr.boot_addr << 1,
block, sizeof(block), NULL, 0);
printf("-- Reset PSU --\n");
return ret;
}
static int
murata_fw_transmit(uint8_t num, const char *file_path) {
int fd = -1, i = 0, j = 0;
int file_line_curr = 0, file_line_total = 0;
FILE* fp;
uint8_t file_buf[128];
uint8_t byte_buf[128];
uint8_t block[I2C_SMBUS_BLOCK_MAX] = {0xfa, 0x44};
int ret = 0;
fp = fopen(file_path, "rb");
if (fp == NULL) {
OBMC_ERROR(errno, "fopen %s failed", file_path);
return -1;
}
file_line_total = check_file_line_cnt(file_path);
/* When entering bootloader mode, Murata PSU PMBUS address change to 0x60 */
fd = i2c_open(psu[num].bus, murata_hdr.boot_addr);
if (fd < 0) {
OBMC_ERROR(errno, "failed to open i2c %u-00%02x",
psu[num].bus, murata_hdr.boot_addr);
ret = -1;
goto exit;
}
while (!feof(fp)) {
if (fgets((char *)file_buf, sizeof(file_buf), fp) == NULL) {
OBMC_ERROR(errno, "fgets %s failed", file_path);
ret = -1;
goto exit;
}
if (file_line_curr < 6) {
/* FW header information */
} else if (file_line_curr == 6) {
if (!strncmp((char *)file_buf, "[data]", strlen("[data]"))) {
if (murata_hdr.uc == 0x50) {
printf("-- Transmit Primary Firmware --\n");
} else if (murata_hdr.uc == 0x53){
printf("-- Transmit Secondary Firmware --\n");
}
}
} else {
printf("-- (%d/%d) (%d%%/100%%) --\r",
file_line_curr, file_line_total,
(100 * file_line_curr) / file_line_total);
while (i < strlen((char *)file_buf) - 2) {
/* Skip first character ":" */
if (i == 0) {
i++;
}
byte_buf[j++] = hex_to_byte(file_buf[i], file_buf[i+1]);
i = i + 2;
}
byte_buf[j] = '\0';
memcpy(&block[2], &byte_buf, byte_buf[0] + 5);
i2c_rdwr_msg_transfer(fd, murata_hdr.boot_addr << 1,
block, byte_buf[0] + 7, NULL, 0);
while (murata_upgrade_status(fd, num) == 0x55) {
msleep(300);
}
}
file_line_curr++;
i = 0;
j = 0;
}
printf("\n");
murata_end_of_file(fd, num);
sleep(1);
if (murata_upgrade_status(fd, num) == 0xaa) {
murata_reset_psu(fd, num);
}
printf("-- Upgrade Done --\n");
exit:
if (fd >= 0)
close(fd);
if (fp != NULL)
fclose(fp);
return ret;
}
int
update_murata_psu(uint8_t num, const char *file_path) {
int ret = -1;
if(murata_img_hdr_parse(file_path) == MURATA_1500) {
murata_bootload_mode(num);
sleep(1);
ret = murata_fw_transmit(num, file_path);
} else {
return UPDATE_SKIP;
};
return ret;
}
static int
murata2k_img_hdr_parse(const char *file_path) {
int i = 0, ret = 0;
int fd_file = -1;
int readnum = 0;
int index = 0;
uint8_t hdr_buf[MURATA2K_HDR_LENGTH];
fd_file = open(file_path, O_RDONLY, 0666);
if (fd_file < 0) {
OBMC_ERROR(errno, "Open file %s failed\n", file_path);
return -1;
}
readnum = read(fd_file, hdr_buf, sizeof(hdr_buf));
if (readnum < sizeof(hdr_buf)) {
OBMC_ERROR(errno, "Read file %d failed\n", fd_file);
close(fd_file);
return -1;
}
memset(&murata2k_hdr, 0, sizeof(murata2k_hdr));
murata2k_hdr.crc[0] = hdr_buf[index++];
murata2k_hdr.crc[1] = hdr_buf[index++];
murata2k_hdr.page_start = hdr_buf[index++];
murata2k_hdr.page_start |= hdr_buf[index++] << 8;
murata2k_hdr.page_end = hdr_buf[index++];
murata2k_hdr.page_end |= hdr_buf[index++] << 8;
murata2k_hdr.byte_per_blk = hdr_buf[index++];
murata2k_hdr.byte_per_blk |= hdr_buf[index++] << 8;
murata2k_hdr.blk_per_page = hdr_buf[index++];
murata2k_hdr.blk_per_page |= hdr_buf[index++] << 8;
murata2k_hdr.uc = hdr_buf[index++];
murata2k_hdr.app_fw_major = hdr_buf[index++];
murata2k_hdr.app_fw_minor = hdr_buf[index++];
murata2k_hdr.bl_fw_major = hdr_buf[index++];
murata2k_hdr.bl_fw_minor = hdr_buf[index++];
murata2k_hdr.fw_id_len = hdr_buf[index++];
if (MURATA2K_FWID_LENGTH != murata2k_hdr.fw_id_len) {
OBMC_WARN("Error FWID length: %d!\n", murata2k_hdr.fw_id_len);
close(fd_file);
return -1;
}
for (i = 0; i < murata2k_hdr.fw_id_len; i++) {
murata2k_hdr.fw_id[i] = hdr_buf[index++];
}
murata2k_hdr.compatibility = hdr_buf[index];
if (index >= sizeof(hdr_buf)) {
OBMC_WARN("Buffer hdr_buf overflow, index: %d, hdr_buf size: %d!\n",
index, sizeof(hdr_buf));
close(fd_file);
return -1;
}
if (!strncmp((char *)murata2k_hdr.fw_id,
MURATA_FWID_2K, strlen(MURATA_FWID_2K))) {
ret = MURATA_2000;
OBMC_INFO("Vendor: Murata\n");
} else {
OBMC_WARN("Get image header fail, error FW ID: %s!\n", murata2k_hdr.fw_id);
close(fd_file);
return -1;
}
OBMC_INFO("FW ID: %s\n", murata2k_hdr.fw_id);
OBMC_INFO("HW Compatibility: %d\n", murata2k_hdr.compatibility);
if (murata2k_hdr.uc == 0x10) {
OBMC_INFO("MCU: primary\n");
} else if (murata2k_hdr.uc == 0x20) {
OBMC_INFO("MCU: secondary\n");
} else {
OBMC_WARN("MCU: unknown number 0x%x\n", murata2k_hdr.uc);
ret = -1;
}
OBMC_INFO("Ver: %d.%d\n", murata2k_hdr.app_fw_major,
murata2k_hdr.app_fw_minor);
close(fd_file);
return ret;
}
static int
murata2k_unlock_upgrade(uint8_t num) {
uint8_t i = 0, j = 0;
uint8_t block[murata2k_hdr.fw_id_len + 2];
block[0] = murata2k_hdr.uc;
block[murata2k_hdr.fw_id_len + 1] = murata2k_hdr.compatibility;
for (i = 1, j = murata2k_hdr.fw_id_len - 1;
i <= murata2k_hdr.fw_id_len; i++, j--) {
block[i] = murata2k_hdr.fw_id[j];
}
i2c_smbus_write_block_data(psu[num].fd, UNLOCK_UPGRADE, sizeof(block), block);
return 0;
}
static int
murata2k_boot_flag(uint8_t num, uint16_t mode, uint8_t op) {
uint16_t word = (mode << 8) | murata2k_hdr.uc;
if (op == WRITE) {
if (mode == BOOT_MODE) {
OBMC_INFO("-- Bootloader Mode --\n");
} else {
OBMC_INFO("-- Reset PSU --\n");
}
return i2c_smbus_write_word_data(psu[num].fd, BOOT_FLAG, word);
} else {
return i2c_smbus_read_byte_data(psu[num].fd, BOOT_FLAG);
}
}
static int
murata2k_fw_transmit(uint8_t num, const char *path) {
FILE* fp = NULL;
int fw_len = 0;
int block_total = 0;
int byte_index = 0;
uint16_t page_num_lo = murata2k_hdr.page_start;
uint16_t block_size = murata2k_hdr.blk_per_page;
uint16_t page_num_max = murata2k_hdr.page_end;
uint32_t fw_block = block_size * (page_num_max - page_num_lo + 1);
uint8_t block[MURATA2K_BYTE_PER_BLK + 3] = {0};
uint8_t fw_buf[MURATA2K_BYTE_PER_BLK];
uint8_t *fw_data = NULL;
int ret = 0;
fw_len = check_file_len(path);
if (fw_len < 0) {
OBMC_ERROR(errno, "failed to get %s size\n", path);
return -1;
} else if (fw_len <= MURATA2K_HDR_LENGTH) {
OBMC_WARN("%s size is too small (%d < 32)\n", path, fw_len);
return -1;
}
fw_len -= MURATA2K_HDR_LENGTH;
fw_data = malloc(fw_len);
if (fw_data == NULL) {
OBMC_ERROR(errno, "failed to allocate %d bytes\n", fw_len);
return -1;
}
fp = fopen(path, "rb");
if (fp == NULL) {
OBMC_ERROR(errno, "failed to open %s\n", path);
ret = -1;
goto exit;
}
ret = fseek(fp, MURATA2K_HDR_LENGTH, SEEK_SET);
if (ret != 0) {
OBMC_ERROR(errno, "fseek %s failed\n", path);
goto exit;
}
ret = fread(fw_data, sizeof(*fw_data), fw_len, fp);
if (ret != fw_len) {
OBMC_WARN("failed to read %d items from %s\n", fw_len, path);
ret = -1;
goto exit;
}
if (murata2k_hdr.uc == 0x10) {
OBMC_INFO("-- Transmit Primary Firmware --\n");
} else if (murata2k_hdr.uc == 0x20) {
OBMC_INFO("-- Transmit Secondary Firmware --\n");
}
while (block_total <= fw_block) {
block[0] = murata2k_hdr.uc;
/* block[1] - Block Num LO
block[2] - Block Num HI */
if (block[1] < block_size) {
memcpy(&fw_buf[0], &fw_data[byte_index], MURATA2K_BYTE_PER_BLK);
memcpy(&block[3], &fw_buf, MURATA2K_BYTE_PER_BLK);
i2c_smbus_write_block_data(psu[num].fd, DATA_TO_RAM,
sizeof(block), block);
if (murata2k_hdr.uc == 0x10) {
msleep(60);
} else if (murata2k_hdr.uc == 0x20) {
msleep(10);
}
block[1]++;
block[2] = 0;
block_total++;
byte_index = byte_index + MURATA2K_BYTE_PER_BLK;
/* This printf can not be replaced by OBMC_INFO
because OBMC_INFO treats the \r as \n */
printf("-- (%d/%d) (%d%%/100%%) --\r",
block_total, fw_block, (100 * block_total) / fw_block);
} else {
block[1] = (page_num_lo & 0xff);
block[2] = ((page_num_lo >> 8) & 0xff);
i2c_smbus_write_block_data(psu[num].fd, DATA_TO_FLASH, 3, block);
msleep(90);
if (page_num_lo == page_num_max) {
OBMC_INFO("\n");
goto exit;
} else {
page_num_lo++;
block[1] = 0;
block[2] = 0;
}
}
}
exit:
if (fp != NULL)
fclose(fp);
free(fw_data);
return ret;
}
static int
murata2k_crc_transmit(uint8_t num) {
uint8_t block[] = {murata2k_hdr.uc,
murata2k_hdr.crc[0],
murata2k_hdr.crc[1]};
OBMC_INFO("-- Transmit CRC --\n");
i2c_smbus_write_block_data(psu[num].fd, CRC_CHECK, sizeof(block), block);
return 0;
}
static int
update_murata2k_psu(uint8_t num, const char *file_path) {
int ret = -1;
ret = murata2k_img_hdr_parse(file_path);
if (ret == MURATA_2000) {
if (murata2k_hdr.byte_per_blk != MURATA2K_BYTE_PER_BLK) {
OBMC_WARN("Image block size %d invalid!\n", murata2k_hdr.byte_per_blk);
return UPDATE_SKIP;
}
if (ioctl(psu[num].fd, I2C_PEC, 1) < 0) {
OBMC_ERROR(errno, "psu%d ioctl error!\n", num);
return UPDATE_SKIP;
}
murata2k_unlock_upgrade(num);
msleep(20);
murata2k_boot_flag(num, BOOT_MODE, WRITE);
msleep(2500);
if (murata2k_fw_transmit(num, file_path) < 0) {
return -1;
}
murata2k_crc_transmit(num);
msleep(1500);
murata2k_boot_flag(num, NORMAL_MODE, WRITE);
if (murata2k_hdr.uc == 0x10) {
msleep(4000);
} else if (murata2k_hdr.uc == 0x20) {
msleep(2000);
}
OBMC_INFO("-- Upgrade Done --\n");
return 0;
} else {
return UPDATE_SKIP;
};
}
int
is_psu_prsnt(uint8_t num, uint8_t *status) {
return pal_is_fru_prsnt(num + FRU_PSU1, status);
}
int
get_mfr_model(uint8_t num, uint8_t *block) {
int rc = -1;
uint8_t psu_num = num + 1;
if (check_psu_status(num, pmbus[MFR_MODEL].reg)) {
printf("PSU%d get status fail!\n", psu_num);
return -1;
}
rc = i2c_smbus_read_block_data(psu[num].fd, pmbus[MFR_MODEL].reg, block);
if (rc < 0) {
ERR_PRINT("get_mfr_model()");
return -1;
}
return 0;
}
int
do_update_psu(uint8_t num, const char *file_path, const char *vendor) {
int ret = -1;
uint8_t block[I2C_SMBUS_BLOCK_MAX + 1] = {0};
signal(SIGHUP, exithandler);
signal(SIGINT, exithandler);
signal(SIGTERM, exithandler);
signal(SIGQUIT, exithandler);
psu[num].fd = i2c_open(psu[num].bus, psu[num].pmbus_addr);
g_fd = psu[num].fd;
if (psu[num].fd < 0) {
ERR_PRINT("Fail to open i2c");
ret = UPDATE_SKIP;
goto update_exit;
}
sensord_operation(num, STOP);
if (vendor == NULL) {
ret = get_mfr_model(num, block);
if (ret < 0) {
printf("Cannot Get PSU Model\n");
ret = UPDATE_SKIP;
goto update_exit;
}
if (!strncmp((char *)block, DELTA_MODEL, strlen(DELTA_MODEL))) {
ret = update_delta_psu(num, file_path, DELTA_1500, vendor);
} else if (!strncmp((char *)block, DELTA_MODEL_2K,
strlen(DELTA_MODEL_2K))) {
ret = update_delta_psu(num, file_path, DELTA_2000, vendor);
} else if (!strncmp((char *)block, LITEON_MODEL, strlen(LITEON_MODEL))) {
ret = update_delta_psu(num, file_path, LITEON_1500, vendor);
} else if (!strncmp((char *)block, LITEON_MODEL_DC,
strlen(LITEON_MODEL_DC))) {
ret = update_delta_psu(num, file_path, LITEON_DC_48, vendor);
} else if (!strncmp((char *)block, DELTA_MODEL_DC,
strlen(DELTA_MODEL_DC))) {
ret = update_delta_psu(num, file_path, DELTA_DC_48, vendor);
} else if (!strncmp((char *)block, BEL_MODEL, strlen(BEL_MODEL))) {
ret = update_belpower_psu(num, file_path);
} else if (!strncmp((char *)block, MURATA_MODEL, strlen(MURATA_MODEL))) {
ret = update_murata_psu(num, file_path);
} else if (!strncmp((char *)block, MURATA_MODEL_2K,
strlen(MURATA_MODEL_2K))) {
ret = update_murata2k_psu(num, file_path);
} else {
printf("Unsupported device: %s\n", block);
ret = UPDATE_SKIP;
}
} else {
if (!strncasecmp(vendor, "delta", strlen("delta"))) {
ret = update_delta_psu(num, file_path, DELTA_1500, vendor);
} else if (!strncasecmp(vendor, "2k-delta", strlen("2k-delta"))){
ret = update_delta_psu(num, file_path, DELTA_2000, vendor);
} else if (!strncasecmp(vendor, "liteon", strlen("liteon"))){
ret = update_delta_psu(num, file_path, LITEON_1500, vendor);
} else if (!strncasecmp(vendor, "belpower", strlen("belpower"))) {
ret = update_belpower_psu(num, file_path);
} else if (!strncasecmp(vendor, "murata", strlen("murata"))) {
ret = update_murata_psu(num ,file_path);
} else if (!strncasecmp(vendor, "2k-murata", strlen("2k-murata"))) {
ret = update_murata2k_psu(num ,file_path);
} else if (!strncasecmp(vendor, "48-liteon", strlen("48-liteon"))) {
ret = update_delta_psu(num, file_path, LITEON_DC_48, vendor);
} else if (!strncasecmp(vendor, "48-delta", strlen("48-delta"))) {
ret = update_delta_psu(num, file_path, DELTA_DC_48, vendor);
} else {
printf("Unsupported vendor: %s\n", vendor);
ret = UPDATE_SKIP;
}
}
update_exit:
if (ret == 0 || ret == UPDATE_SKIP) {
sensord_operation(num, START);
}
close(psu[num].fd);
run_command("rm /var/run/psu-util.pid");
return ret;
}
/* Print the FRUID in detail */
static void
print_fruid_info(fruid_info_t *fruid, uint8_t num) {
/* Print format */
printf("%-27s: PSU%d (Bus:%d Addr:0x%x)", "\nFRU Information",
num + 1, psu[num].bus, psu[num].eeprom_addr);
printf("%-27s: %s", "\n---------------", "-----------------------");
if (fruid->chassis.flag) {
printf("%-27s: %s", "\nChassis Type",fruid->chassis.type_str);
printf("%-27s: %s", "\nChassis Part Number",fruid->chassis.part);
printf("%-27s: %s", "\nChassis Serial Number",fruid->chassis.serial);
if (fruid->chassis.custom1 != NULL)
printf("%-27s: %s", "\nChassis Custom Data 1",fruid->chassis.custom1);
if (fruid->chassis.custom2 != NULL)
printf("%-27s: %s", "\nChassis Custom Data 2",fruid->chassis.custom2);
if (fruid->chassis.custom3 != NULL)
printf("%-27s: %s", "\nChassis Custom Data 3",fruid->chassis.custom3);
if (fruid->chassis.custom4 != NULL)
printf("%-27s: %s", "\nChassis Custom Data 4",fruid->chassis.custom4);
}
if (fruid->board.flag) {
printf("%-27s: %s", "\nBoard Mfg Date",fruid->board.mfg_time_str);
printf("%-27s: %s", "\nBoard Mfg",fruid->board.mfg);
printf("%-27s: %s", "\nBoard Product",fruid->board.name);
printf("%-27s: %s", "\nBoard Serial",fruid->board.serial);
printf("%-27s: %s", "\nBoard Part Number",fruid->board.part);
printf("%-27s: %s", "\nBoard FRU ID",fruid->board.fruid);
if (fruid->board.custom1 != NULL)
printf("%-27s: %s", "\nBoard Custom Data 1",fruid->board.custom1);
if (fruid->board.custom2 != NULL)
printf("%-27s: %s", "\nBoard Custom Data 2",fruid->board.custom2);
if (fruid->board.custom3 != NULL)
printf("%-27s: %s", "\nBoard Custom Data 3",fruid->board.custom3);
if (fruid->board.custom4 != NULL)
printf("%-27s: %s", "\nBoard Custom Data 4",fruid->board.custom4);
}
if (fruid->product.flag) {
printf("%-27s: %s", "\nProduct Manufacturer",fruid->product.mfg);
printf("%-27s: %s", "\nProduct Name",fruid->product.name);
printf("%-27s: %s", "\nProduct Part Number",fruid->product.part);
printf("%-27s: %s", "\nProduct Version",fruid->product.version);
printf("%-27s: %s", "\nProduct Serial",fruid->product.serial);
printf("%-27s: %s", "\nProduct Asset Tag",fruid->product.asset_tag);
printf("%-27s: %s", "\nProduct FRU ID",fruid->product.fruid);
if (fruid->product.custom1 != NULL)
printf("%-27s: %s", "\nProduct Custom Data 1",fruid->product.custom1);
if (fruid->product.custom2 != NULL)
printf("%-27s: %s", "\nProduct Custom Data 2",fruid->product.custom2);
if (fruid->product.custom3 != NULL)
printf("%-27s: %s", "\nProduct Custom Data 3",fruid->product.custom3);
if (fruid->product.custom4 != NULL)
printf("%-27s: %s", "\nProduct Custom Data 4",fruid->product.custom4);
}
printf("\n");
}
static int
get_ac_psu_eeprom_info(uint8_t num) {
int ret = -1;
char eeprom[16];
fruid_info_t fruid;
snprintf(eeprom, sizeof(eeprom), "%s", "24c02");
i2c_add_device(psu[num].bus, psu[num].eeprom_addr, eeprom);
ret = fruid_parse(psu[num].eeprom_file, &fruid);
i2c_delete_device(psu[num].bus, psu[num].eeprom_addr);
if (ret) {
snprintf(eeprom, sizeof(eeprom), "%s", "24c64");
i2c_add_device(psu[num].bus, psu[num].eeprom_addr, eeprom);
ret = fruid_parse(psu[num].eeprom_file, &fruid);
i2c_delete_device(psu[num].bus, psu[num].eeprom_addr);
if (ret) {
printf("Failed print EEPROM info!\n");
return -1;
}
}
print_fruid_info(&fruid, num);
free_fruid_info(&fruid);
return 0;
}
static void
print_dc_psu_fru_eeprom(i2c_info_t *psu_info,
struct wedge_eeprom_st fruid, uint8_t num) {
/* Print format */
printf("%-27s: PSU%d (Bus:%d Addr:0x%x)", "\nFRU Information",
num + 1, (psu_info+num)->bus,
(psu_info+num)->eeprom_addr);
printf("%-27s: %s", "\n---------------", "-----------------------");
printf("\n%-32s: %d", "Version", fruid.fbw_version);
printf("\n%-32s: %s", "Product Name", fruid.fbw_product_name);
printf("\n%-32s: %s", "Product Part Number", fruid.fbw_product_number);
printf("\n%-32s: %s", "System Assembly Part Number",
fruid.fbw_assembly_number);
printf("\n%-32s: %s", "Facebook PCBA Part Number",
fruid.fbw_facebook_pcba_number);
printf("\n%-32s: %s", "Facebook PCB Part Number",
fruid.fbw_facebook_pcb_number);
printf("\n%-32s: %s", "ODM PCBA Part Number",
fruid.fbw_odm_pcba_number);
printf("\n%-32s: %s", "ODM PCBA Serial Number", fruid.fbw_odm_pcba_serial);
printf("\n%-32s: %d", "Product Production State", fruid.fbw_production_state);
printf("\n%-32s: %d", "Product Version", fruid.fbw_product_version);
printf("\n%-32s: %d", "Product Sub-Version", fruid.fbw_product_subversion);
printf("\n%-32s: %s", "Product Serial Number", fruid.fbw_product_serial);
printf("\n%-32s: %s", "Product Asset Tag", fruid.fbw_product_asset);
printf("\n%-32s: %s", "System Manufacturer", fruid.fbw_system_manufacturer);
printf("\n%-32s: %s", "System Manufacturing Date",
fruid.fbw_system_manufacturing_date);
printf("\n%-32s: %s", "PCB Manufacturer", fruid.fbw_pcb_manufacturer);
printf("\n%-32s: %s", "Assembled At", fruid.fbw_assembled);
printf("\n%-32s: %02X:%02X:%02X:%02X:%02X:%02X", "Local MAC",
fruid.fbw_local_mac[0], fruid.fbw_local_mac[1],
fruid.fbw_local_mac[2], fruid.fbw_local_mac[3],
fruid.fbw_local_mac[4], fruid.fbw_local_mac[5]);
printf("\n%-32s: %02X:%02X:%02X:%02X:%02X:%02X", "Extended MAC Base",
fruid.fbw_mac_base[0], fruid.fbw_mac_base[1],
fruid.fbw_mac_base[2], fruid.fbw_mac_base[3],
fruid.fbw_mac_base[4], fruid.fbw_mac_base[5]);
printf("\n%-32s: %d", "Extended MAC Address Size", fruid.fbw_mac_size);
printf("\n%-32s: %s", "Location on Fabric", fruid.fbw_location);
printf("\n%-32s: 0x%x", "CRC8", fruid.fbw_crc8);
printf("\n");
}
static int
get_dc_psu_eeprom_info(i2c_info_t *psu_info,uint8_t num) {
int ret = -1;
char eeprom[16];
struct wedge_eeprom_st fruid_pem;
snprintf(eeprom, sizeof(eeprom), "%s", "24c02");
i2c_add_device((psu_info+num)->bus, (psu_info+num)->eeprom_addr, eeprom);
ret = wedge_eeprom_parse((psu_info+num)->eeprom_file, &fruid_pem);
i2c_delete_device((psu_info+num)->bus, (psu_info+num)->eeprom_addr);
printf("print EEPROM info ret = 0x%x!\n", ret);
if (ret) {
snprintf(eeprom, sizeof(eeprom), "%s", "24c64");
i2c_add_device((psu_info+num)->bus, (psu_info+num)->eeprom_addr, eeprom);
ret = wedge_eeprom_parse((psu_info+num)->eeprom_file, &fruid_pem);
i2c_delete_device((psu_info+num)->bus, (psu_info+num)->eeprom_addr);
if (ret) {
printf("Failed print EEPROM info ret = 0x%x!\n", ret);
return -1;
}
}
if(strncmp(fruid_pem.fbw_location, "PEM", 3)){
return -1;
}
print_dc_psu_fru_eeprom(psu_info, fruid_pem, num);
return 0;
}
/* Populate and print fruid_info by parsing the fru's binary dump */
int
get_eeprom_info(uint8_t num) {
int ret = -1;
uint8_t block[I2C_SMBUS_BLOCK_MAX + 1];
psu[num].fd = i2c_open(psu[num].bus, psu[num].pmbus_addr);
g_fd = psu[num].fd;
if (psu[num].fd < 0) {
ERR_PRINT("Fail to open i2c");
return -1;
}
if (get_mfr_model(num, block)) {
close(psu[num].fd);
return -1;
}
if (!strncmp((char *)block, LITEON_MODEL_DC, strlen(LITEON_MODEL_DC)) ||
!strncmp((char *)block, DELTA_MODEL_DC, strlen(DELTA_MODEL_DC))) {
ret = get_dc_psu_eeprom_info(psu, num);
}
else {
ret = get_ac_psu_eeprom_info(num);
}
close(psu[num].fd);
return ret;
}
int
get_psu_info(uint8_t num) {
int rc = -1;
int i = 0, size = 0;
uint8_t block[I2C_SMBUS_BLOCK_MAX + 1];
uint8_t byte;
uint16_t word = 0;
uint32_t optn_time = 0;
time_info_t optn;
psu[num].fd = i2c_open(psu[num].bus, psu[num].pmbus_addr);
g_fd = psu[num].fd;
if (psu[num].fd < 0) {
ERR_PRINT("Fail to open i2c");
return -1;
}
if (get_mfr_model(num, block)) {
close(psu[num].fd);
return -1;
}
if (!strncmp((char *)block, DELTA_MODEL, strlen(DELTA_MODEL)) ||
!strncmp((char *)block, DELTA_MODEL_2K, strlen(DELTA_MODEL_2K)) ||
!strncmp((char *)block, LITEON_MODEL, strlen(LITEON_MODEL)) ||
!strncmp((char *)block, MURATA_MODEL, strlen(MURATA_MODEL)) ||
!strncmp((char *)block, MURATA_MODEL_2K, strlen(MURATA_MODEL_2K)) ||
!strncmp((char *)block, LITEON_MODEL_DC, strlen(LITEON_MODEL_DC)) ||
!strncmp((char *)block, DELTA_MODEL_DC, strlen(DELTA_MODEL_DC))) {
size = OPTN_TIME_PRESENT;
} else {
size = STATUS_FAN;
}
printf("\n%-26s: PSU%d (Bus:%d Addr:0x%x)", "PSU Information",
num + 1, psu[num].bus, psu[num].pmbus_addr);
printf("\n%-26s: %s", "---------------", "-----------------------");
for (i = MFR_ID; i <= size; i++) {
switch (i) {
case MFR_ID:
case MFR_MODEL:
case MFR_REVISION:
case MFR_DATE:
case MFR_SERIAL:
printf("\n%-18s (0x%X) : ", pmbus[i].item, pmbus[i].reg);
if (check_psu_status(num, pmbus[i].reg)) {
printf("NA");
} else {
memset(block, 0, sizeof(block));
rc = i2c_smbus_read_block_data(psu[num].fd, pmbus[i].reg, block);
if (rc < 0) {
printf("NA");
} else {
printf("%s", block);
}
}
break;
case PRI_FW_VER:
case SEC_FW_VER:
word = i2c_smbus_read_word_data(psu[num].fd, pmbus[i].reg);
printf("\n%-18s (0x%X) : %d.%d", pmbus[i].item, pmbus[i].reg,
(word & 0xff), ((word >> 8) & 0xff));
break;
case STATUS_WORD:
case STATUS_STBY_WORD:
word = i2c_smbus_read_word_data(psu[num].fd, pmbus[i].reg);
printf("\n%-18s (0x%X) : 0x%04x", pmbus[i].item, pmbus[i].reg, word);
break;
case STATUS_VOUT:
case STATUS_IOUT:
case STATUS_INPUT:
case STATUS_TEMP:
case STATUS_CML:
case STATUS_FAN:
case STATUS_VSTBY:
case STATUS_ISTBY:
byte = i2c_smbus_read_byte_data(psu[num].fd, pmbus[i].reg);
printf("\n%-18s (0x%X) : 0x%02x", pmbus[i].item, pmbus[i].reg, byte);
break;
case OPTN_TIME_TOTAL:
case OPTN_TIME_PRESENT:
printf("\n%-18s (0x%X) : ", pmbus[i].item, pmbus[i].reg);
if (check_psu_status(num, pmbus[i].reg)) {
printf("NA");
} else {
memset(block, 0, sizeof(block));
rc = i2c_smbus_read_block_data(psu[num].fd, pmbus[i].reg, block);
if (rc != 4) {
printf("NA");
} else {
optn_time = block[0] | block[1] << 8 |
block[2] << 16 | block[3] << 24;
optn = time_convert(optn_time);
printf("%dD:%dH:%dM:%dS", optn.day, optn.hour, optn.min, optn.sec);
}
}
break;
}
}
printf("\n");
close(psu[num].fd);
return 0;
}
int
get_blackbox_info(uint8_t num, const char *option) {
int ret = 0;
uint8_t psu_num = num + 1;
uint8_t read_cmd[3] = {0xfb, 1};
uint8_t clear_cmd[3] = {0xfb, 0xaa, 0x55};
uint32_t time_total = 0, time_present = 0;
uint8_t block[I2C_SMBUS_BLOCK_MAX + 1];
uint8_t byte_buf[42];
blackbox_info_t blackbox;
time_info_t total;
time_info_t present;
psu[num].fd = i2c_open(psu[num].bus, psu[num].pmbus_addr);
g_fd = psu[num].fd;
if (psu[num].fd < 0) {
ERR_PRINT("Fail to open i2c");
return -1;
}
if (get_mfr_model(num, block)) {
close(psu[num].fd);
return -1;
}
if (strncmp((char *)block, DELTA_MODEL, strlen(DELTA_MODEL)) &&
strncmp((char *)block, DELTA_MODEL_2K, strlen(DELTA_MODEL_2K)) &&
strncmp((char *)block, LITEON_MODEL, strlen(LITEON_MODEL)) &&
strncmp((char *)block, MURATA_MODEL, strlen(MURATA_MODEL)) &&
strncmp((char *)block, MURATA_MODEL_2K, strlen(MURATA_MODEL_2K)) &&
strncmp((char *)block, LITEON_MODEL_DC, strlen(LITEON_MODEL_DC)) &&
strncmp((char *)block, DELTA_MODEL_DC, strlen(DELTA_MODEL_DC))) {
printf("PSU%d not support blackbox!\n", psu_num);
close(psu[num].fd);
return -1;
}
/*
* FIXME: LITEON & DELTA 48V DC EVT1 hardware doesn't report accurate data for
* these fields, and we will fix them step by step.
*/
if ((!strncmp(option, "--print", strlen("--print")))) {
for (read_cmd[2] = 0; read_cmd[2] < 5; read_cmd[2]++) {
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
read_cmd, 3, byte_buf, 44);
if (ret) {
printf("PSU%d blackbox page %d read fail!\n", psu_num, read_cmd[2]);
close(psu[num].fd);
return -1;
}
memcpy(&blackbox, byte_buf, 42);
time_total = blackbox.optn_time_total[0] |
blackbox.optn_time_total[1] << 8 |
blackbox.optn_time_total[2] << 16 |
blackbox.optn_time_total[3] << 24;
time_present = blackbox.optn_time_present[0] |
blackbox.optn_time_present[1] << 8 |
blackbox.optn_time_present[2] << 16 |
blackbox.optn_time_present[3] << 24;
total = time_convert(time_total);
present = time_convert(time_present);
printf("%-27s: PSU%d (Bus:%d Addr:0x%x)", "\nBlackbox Information",
psu_num, psu[num].bus, psu[num].pmbus_addr);
printf("%-27s: %s", "\n--------------------", "-----------------------");
printf("%-27s: %d", "\nPAGE", blackbox.page);
printf("%-19s (0xDD) : %d.%d", "\nPRI_FW_VER", blackbox.pri_code_ver[0],
blackbox.pri_code_ver[1]);
printf("%-19s (0xD7) : %d.%d", "\nSEC_FW_VER", blackbox.sec_code_ver[0],
blackbox.sec_code_ver[1]);
printf("%-19s (0x79) : 0x%04x", "\nSTATUS_WORD",
(blackbox.v1_status[1] << 8) | blackbox.v1_status[0]);
printf("%-19s (0x7A) : 0x%02x", "\nSTATUS_VOUT", blackbox.v1_status_vout);
printf("%-19s (0x7B) : 0x%02x", "\nSTATUS_IOUT", blackbox.v1_status_iout);
printf("%-19s (0x7C) : 0x%02x", "\nSTATUS_INPUT", blackbox.input_status);
printf("%-19s (0x7D) : 0x%02x", "\nSTATUS_TEMP", blackbox.temp_status);
printf("%-19s (0x7E) : 0x%02x", "\nSTATUS_CML", blackbox.cml_status);
printf("%-19s (0x81) : 0x%02x", "\nSTATUS_FAN", blackbox.fan_status);
printf("%-19s (0xD3) : 0x%04x", "\nSTATUS_STBY_WORD",
(blackbox.vsb_status[1] << 8) | blackbox.vsb_status[0]);
printf("%-19s (0xD4) : 0x%02x", "\nSTATUS_VSTBY",
blackbox.vsb_status_vout);
printf("%-19s (0xD5) : 0x%02x", "\nSTATUS_ISTBY",
blackbox.vsb_status_iout);
printf("%-19s (0xD8) : %dD:%dH:%dM:%dS", "\nOPTN_TIME_TOTAL",
total.day, total.hour, total.min, total.sec);
printf("%-19s (0xD9) : %dD:%dH:%dM:%dS", "\nOPTN_TIME_PRESENT",
present.day, present.hour, present.min, present.sec);
printf("%-19s (0x88) : %.2f V", "\nIN_VOLT",
linear_convert(blackbox.vin));
printf("%-19s (0x89) : %.2f V", "\n12V_VOLT",
linear_convert(blackbox.vout));
printf("%-19s (0x8B) : %.2f A", "\nIN_CURR",
linear_convert(blackbox.iin));
printf("%-19s (0x8C) : %.2f A", "\n12V_CURR",
linear_convert(blackbox.iout));
printf("%-19s (0x8D) : %.2f C", "\nTEMP1",
linear_convert(blackbox.temp1));
printf("%-19s (0x8E) : %.2f C", "\nTEMP2",
linear_convert(blackbox.temp2));
printf("%-19s (0x8F) : %.2f C", "\nTEMP3",
linear_convert(blackbox.temp3));
if (!strncmp((char *)block, LITEON_MODEL_DC, strlen(LITEON_MODEL_DC)) ||
!strncmp((char *)block, DELTA_MODEL_DC, strlen(DELTA_MODEL_DC))) {
printf("%-19s (0x90) : %.2f RPM", "\nFAN_SPEED",
linear_convert(blackbox.fan_speed));
printf("%-19s (0x91) : %.2f RPM\n", "\nFAN_SPEED2",
linear_convert(blackbox.fan2_speed));
} else {
printf("%-19s (0x90) : %.2f RPM\n", "\nFAN_SPEED",
linear_convert(blackbox.fan_speed));
}
}
} else if ((!strncmp(option, "--clear", strlen("--clear")))) {
ret = i2c_rdwr_msg_transfer(psu[num].fd, psu[num].pmbus_addr << 1,
clear_cmd, 3, NULL, 0);
if (ret) {
printf("PSU%d blackbox clear fail!\n", psu_num);
close(psu[num].fd);
return -1;
}
} else {
printf("Invalid option!\n");
close(psu[num].fd);
return -1;
}
close(psu[num].fd);
return 0;
}