meta-facebook/meta-yosemite/recipes-yosemite/bic-cached/files/bic-cached.c (167 lines of code) (raw):
/*
*
* Copyright 2015-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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <openbmc/ipmi.h>
#include <openbmc/ipmb.h>
#include <facebook/bic.h>
#define LAST_RECORD_ID 0xFFFF
#define MAX_SENSOR_NUM 0xFF
#define BYTES_ENTIRE_RECORD 0xFF
static int
_fruid_check(const char *bin) {
FILE *fruid_fp;
int fruid_len, ret = -1;
uint16_t area_offs, area_len;
uint8_t sum, i, area;
uint8_t *fruid_data, *p_buf;
/* Open the FRUID binary file */
fruid_fp = fopen(bin, "rb");
if (!fruid_fp) {
return ENOENT;
}
/* Get the size of the binary file */
fseek(fruid_fp, 0, SEEK_END);
fruid_len = ftell(fruid_fp);
if (fruid_len <= 0) {
fclose(fruid_fp);
return -1;
}
fseek(fruid_fp, 0, SEEK_SET);
fruid_data = (uint8_t *)malloc(fruid_len);
if (!fruid_data) {
fclose(fruid_fp);
return ENOMEM;
}
/* Read the binary file */
fread(fruid_data, sizeof(uint8_t), fruid_len, fruid_fp);
fclose(fruid_fp);
/* Check Common Header */
sum = 0;
for (i = 0; i < 8; i++) {
sum += fruid_data[i];
}
if (sum || (fruid_data[0] != 0x01)) {
free(fruid_data);
return -1;
}
/* Check Chassis/Board/Product Info Area */
for (area = 2; area <= 4; area++) {
if (fruid_data[area]) {
area_offs = fruid_data[area] * 8;
if (area_offs >= fruid_len) {
break;
}
area_len = fruid_data[area_offs + 1] * 8;
if ((area_offs + area_len) >= fruid_len) {
break;
}
sum = 0;
p_buf = fruid_data + area_offs;
for (i = 0; i < area_len; i++) {
sum += p_buf[i];
}
if (sum || (p_buf[0] != 0x01)) {
break;
}
}
}
if (area > 4) {
ret = 0;
}
free(fruid_data);
return ret;
}
int
fruid_cache_init(uint8_t slot_id) {
// Initialize Slot0's fruid
int ret=0;
int fru_size=0;
char fruid_temp_path[64] = {0};
char fruid_path[64] = {0};
sprintf(fruid_temp_path, "/tmp/tfruid_slot%d.bin", slot_id);
sprintf(fruid_path, "/tmp/fruid_slot%d.bin", slot_id);
ret = bic_read_fruid(slot_id, 0, fruid_temp_path, &fru_size);
if (ret) {
syslog(LOG_WARNING, "fruid_cache_init: bic_read_fruid returns %d, fru_size: %d\n", ret, fru_size);
}
if (!ret) {
ret = _fruid_check(fruid_temp_path);
if (ret) {
syslog(LOG_WARNING, "fruid_cache_init: _fruid_check returns %d, fru_size: %d\n", ret, fru_size);
}
}
rename(fruid_temp_path, fruid_path);
return ret;
}
void
sdr_cache_init(uint8_t slot_id) {
int ret;
int fd;
uint8_t rlen;
uint8_t rbuf[MAX_IPMB_RES_LEN] = {0};
char *path = NULL;
char sdr_temp_path[64] = {0};
char sdr_path[64] = {0};
sprintf(sdr_temp_path, "/tmp/tsdr_slot%d.bin", slot_id);
sprintf(sdr_path, "/tmp/sdr_slot%d.bin", slot_id);
ipmi_sel_sdr_req_t req;
ipmi_sel_sdr_res_t *res = (ipmi_sel_sdr_res_t *) rbuf;
req.rsv_id = 0;
req.rec_id = 0;
req.offset = 0;
req.nbytes = BYTES_ENTIRE_RECORD;
// Read Slot0's SDR records and store
path = sdr_temp_path;
unlink(path);
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd < 0) {
syslog(LOG_WARNING, "sdr_cache_init: open fails for path: %s\n", path);
return;
}
while (1) {
ret = bic_get_sdr(slot_id, &req, res, &rlen);
if (ret) {
syslog(LOG_WARNING, "sdr_cache_init:bic_get_sdr returns %d\n", ret);
continue;
}
sdr_full_t *sdr = (sdr_full_t *) res->data;
write(fd, sdr, sizeof(sdr_full_t));
req.rec_id = res->next_rec_id;
if (req.rec_id == LAST_RECORD_ID) {
// syslog(LOG_INFO, "This record is LAST record\n");
break;
}
}
rename(sdr_temp_path, sdr_path);
}
int
main (int argc, char * const argv[])
{
int ret;
uint8_t slot_id;
uint8_t self_test_result[2]={0};
int retry = 0;
int max_retry = 3;
if (argc != 2) {
return -1;
}
slot_id = atoi(argv[1]);
// Check BIC Self Test Result
do {
ret = bic_get_self_test_result(slot_id, self_test_result);
if (ret == 0) {
syslog(LOG_INFO, "bic_get_self_test_result: %X %X\n", self_test_result[0], self_test_result[1]);
break;
}
sleep(5);
} while (ret != 0);
// Get Server FRU
do {
if (fruid_cache_init(slot_id) == 0)
break;
retry++;
sleep(1);
} while (retry < max_retry);
if (retry == max_retry)
syslog(LOG_CRIT, "Fail on getting Server FRU.");
sdr_cache_init(slot_id);
return 0;
}