int yamp_eeprom_parse()

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;
}