in meta-facebook/meta-yamp/recipes-utils/wedge-eeprom/files/utils/yamp_eeprom.c [269:497]
int yamp_eeprom_parse(const char *target, struct wedge_eeprom_st *eeprom)
{
int rc = 0;
int read_pointer = 0;
uint32_t len;
FILE *fin;
int field_type;
int field_len;
int ver_major = 0;
int ver_minor = 0;
int dot_location = 0;
int parse_sup_eeprom = 0;
char local_target[256];
char field_value[YAMP_EEPROM_SIZE]; // Will never overflow
char fn[64];
char buf[YAMP_EEPROM_SIZE];
char bus_name[32];
char sup_eeprom_filename[YAMP_FILE_NAME_SIZE];
bool mfgtime2 = false; // set to True if MFGTIME2 field is detected
if (!eeprom) {
return -EINVAL;
}
if (!target)
return -EINVAL;
snprintf(local_target, sizeof(local_target), "%s", target);
yamp_str_toupper((char *)local_target);
if (!strcmp(local_target, YAMP_EEPROM_CHS_OBJ)) {
sprintf(fn, "%s%s/eeprom", YAMP_EEPROM_PATH_BASE,
YAMP_EEPROM_CHASSIS);
} else if (!strcmp(local_target, YAMP_EEPROM_SCD_OBJ)) {
sprintf(fn, "%s%s/eeprom", YAMP_EEPROM_PATH_BASE,
YAMP_EEPROM_SWITCH_CARD);
} else if (!strcmp(local_target, YAMP_EEPROM_SUP_OBJ)) {
rc = yamp_prepare_sup_eeprom_cache();
if (rc != 0) {
OBMC_ERROR(ENOSPC, "Unable to dump the SUP EEPROM contents to ramdisk."
" Likely due to the lack of disk space. rc = %d\n", rc);
return -ENOSPC;
}
yamp_get_eeprom_filename(sup_eeprom_filename);
sprintf(fn, "%s", sup_eeprom_filename);
// Note that SUP's EEPROM format is a bit different from others,
// in that it doesn't start with eeprom header.
// Instead, it starts from prefdl field.
parse_sup_eeprom = 1;
} else if (yamp_get_lc_bus_name((const char *)local_target, bus_name) == 0) {
sprintf(fn, "%s%s/eeprom", YAMP_EEPROM_PATH_BASE, bus_name);
} else {
return -EINVAL;
}
fin = fopen(fn, "r");
if (fin == NULL) {
rc = errno;
OBMC_ERROR(rc, "Failed to open %s", fn);
goto out;
}
/* Read the file into buffer */
rc = fread(buf, 1, sizeof(buf), fin);
if (rc <= 0) {
OBMC_ERROR(ENOSPC, "Failed to complete the read. Error code %d", rc);
rc = ENOSPC;
goto out;
}
/*
* There are many fields in FB standard eeprom, that doesn't exist in
* YAMP eeprom. Start with all fields filled up as NULL or 0x0,
* then overwrite the values as we get the information from eeprom
*/
memset(eeprom, 0, sizeof(struct wedge_eeprom_st));
/*
* The following check is only for NON-SUP eeproms, which
* has all these fields.
*/
if (parse_sup_eeprom != 1) {
/* First, make sure the eeprom header is correct */
if ((buf[read_pointer] != YAMP_EEPROM_HEADER_B1) ||
(buf[read_pointer + 1] != YAMP_EEPROM_HEADER_B2) ||
(buf[read_pointer + 2] != YAMP_EEPROM_HEADER_B3) ||
(buf[read_pointer + 3] != YAMP_EEPROM_HEADER_B4)) {
OBMC_ERROR(EINVAL, "Wrong EEPROM header! expected %02x %02x %02x %02x, \
got %02x %02x %02x %02x",
YAMP_EEPROM_HEADER_B1, YAMP_EEPROM_HEADER_B2,
YAMP_EEPROM_HEADER_B3, YAMP_EEPROM_HEADER_B4,
buf[read_pointer], buf[read_pointer+1],
buf[read_pointer + 2], buf[read_pointer+3]);
rc = -EINVAL;
}
/* As we read the first four bytes, advance the read pointer */
read_pointer += YAMP_EEPROM_TYPE_SIZE;
/* Bypass the eeprom size field */
read_pointer += YAMP_EEPROM_TYPE_SIZE;
}
/* Bypass prefdl symbol and PCA */
read_pointer += YAMP_EEPROM_TYPE_SIZE + YAMP_EEPROM_PCA_SIZE;
/* Parse serial number. If there is additional serial TLV,
* this value will be overwritten */
yamp_parse_string(&read_pointer, (char *)&eeprom->fbw_product_serial,
buf, YAMP_EEPROM_SERIAL_SIZE);
read_pointer += YAMP_EEPROM_KVN_SIZE;
/* Product type is hardcoded to YAMP */
sprintf(eeprom->fbw_product_name, "YAMP");
rc = 0;
/* Now go though EEPROM contents to fill out the fields */
while ((rc == 0) && (read_pointer < YAMP_EEPROM_SIZE)) {
rc = yamp_parse_hexadecimal(&read_pointer, &field_type, buf, 2);
if (rc < 0)
goto out;
rc = yamp_parse_hexadecimal(&read_pointer, &field_len, buf, 4);
if (rc < 0)
goto out;
/*
* If this is the end of EEPROM (specified as "END" TLV),
* do not read any value, but just bail out
*/
if (field_type == YAMP_EEPROM_FIELD_END)
break;
/* Otherwise, read the field */
memcpy(field_value, &buf[read_pointer], field_len);
read_pointer += field_len;
/* Now, map the value into similar field in FB EEPROM */
switch(field_type)
{
case YAMP_EEPROM_FIELD_MFGTIME:
if (!mfgtime2)
memcpy(eeprom->fbw_system_manufacturing_date, field_value, 10);
break;
case YAMP_EEPROM_FIELD_MFGTIME2:
mfgtime2 = true; // Do not allow MFGTIME to override MFGTIME2
memcpy(eeprom->fbw_system_manufacturing_date, field_value, 10);
break;
case YAMP_EEPROM_FIELD_ASY:
memcpy(eeprom->fbw_assembly_number, field_value,
FBW_EEPROM_F_ASSEMBLY_NUMBER);
eeprom->fbw_assembly_number[FBW_EEPROM_F_ASSEMBLY_NUMBER -1] = 0;
break;
case YAMP_EEPROM_FIELD_SKU:
memcpy(eeprom->fbw_product_number, field_value,
FBW_EEPROM_F_PRODUCT_NUMBER);
eeprom->fbw_assembly_number[FBW_EEPROM_F_PRODUCT_NUMBER -1] = 0;
break;
case YAMP_EEPROM_FIELD_MACBASE:
for (int i = 0; i < 6; i++)
eeprom->fbw_mac_base[i] = yamp_htoi(field_value[2*i]) * 16 +
yamp_htoi(field_value[2*i + 1]);
/* Also hardcade mac size as the same value as Minipack */
eeprom->fbw_mac_size = 139;
break;
case YAMP_EEPROM_FIELD_HWREV:
/* Scan for period character */
dot_location = field_len;
for (int i = 0; i < field_len; i++)
if (field_value[i] == '.')
dot_location = i;
/* Parse the number before dot, and fit it into uint8_t */
for (int i = 0; i < dot_location; i++) {
ver_major *= 10;
ver_major += yamp_htoi(field_value[i]);
}
/* Parse the number after dot, and fit it into uint8_t */
ver_major = ver_major % 256;
for (int i = dot_location + 1; i < field_len; i++) {
ver_minor *= 10;
ver_minor += yamp_htoi(field_value[i]);
}
/* Fit the value into uint8_t */
ver_minor = ver_minor % 256;
eeprom->fbw_product_version = ver_major;
eeprom->fbw_product_subversion = ver_minor;
break;
case YAMP_EEPROM_FIELD_SERIAL:
memcpy(&eeprom->fbw_product_serial, field_value,
YAMP_EEPROM_SERIAL_SIZE);
eeprom->fbw_product_serial[YAMP_EEPROM_SERIAL_SIZE] = '\0';
break;
case YAMP_EEPROM_FIELD_RESERVED1:
case YAMP_EEPROM_FIELD_RESERVED2:
case YAMP_EEPROM_FIELD_RESERVED3:
case YAMP_EEPROM_FIELD_RESERVED4:
case YAMP_EEPROM_FIELD_RESERVED5:
case YAMP_EEPROM_FIELD_RESERVED6:
case YAMP_EEPROM_FIELD_RESERVED7:
case YAMP_EEPROM_FIELD_FLDVAR:
case YAMP_EEPROM_FIELD_HWAPI:
case YAMP_EEPROM_FIELD_SID:
case YAMP_EEPROM_FIELD_PCA:
/* These fields are not really useful. Do nothing (discard) */
break;
default:
/* unregonize field type. Bail out and print warning log*/
OBMC_WARN("unrecognize fied type of 0x%02x\n", field_type);
break;
}
}
out:
if (fin) {
fclose(fin);
}
if (parse_sup_eeprom == 1) {
// Remove temporary file created for SUP EEPROM read
remove(sup_eeprom_filename);
}
// rc > 0 means success here.
// (it will usually have the number of bytes read)
return (rc >= 0) ? 0 : -rc;
}