All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ipmi-fru-parser v2 0/3] Checking in the basic IPMI FRU Parser Library.
@ 2015-10-16 12:20 OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 1/3] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: OpenBMC Patches @ 2015-10-16 12:20 UTC (permalink / raw)
  To: openbmc

Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version.
This parser is a stripped down version of the parser in the FreeIPMI distribution.

https://github.com/openbmc/ipmi-fru-parser/pull/2

Hariharasubramanian R (3):
  Checking in the basic IPMI FRU Parser Library.     Parser has just
    enough intelligence to parse Chassis, Board & Product info areas. No
    support for multi-record in this version.     This parser is a
    stripped down version of the parser in the FreeIPMI distribution.
  IPMI FRU Parser Interface.
  Added interface function to parse wirte fru data message into a
    dictionary.

 Makefile |  19 ++
 frup.c   | 823 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 frup.h   |   7 +
 3 files changed, 849 insertions(+)
 create mode 100644 Makefile
 create mode 100644 frup.c
 create mode 100644 frup.h

-- 
2.6.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH ipmi-fru-parser v2 1/3] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution.
  2015-10-16 12:20 [PATCH ipmi-fru-parser v2 0/3] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
@ 2015-10-16 12:20 ` OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 2/3] IPMI FRU Parser Interface OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 3/3] Added interface function to parse wirte fru data message into a dictionary OpenBMC Patches
  2 siblings, 0 replies; 4+ messages in thread
From: OpenBMC Patches @ 2015-10-16 12:20 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 Makefile |  19 ++
 frup.c   | 599 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 618 insertions(+)
 create mode 100644 Makefile
 create mode 100644 frup.c

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cf75af3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,19 @@
+CXX ?= $(CROSS_COMPILE)g++
+
+IPMI_FRU_PARSER_LIB = libifp.so
+IPMI_FRU_PARSER_OBJS = frup.o
+
+INC_FLAGS += $(shell pkg-config --cflags --libs libsystemd) -I. -O2 --std=gnu++11
+LIB_FLAGS += $(shell pkg-config  --libs libsystemd) -rdynamic
+#IPMID_PATH ?= -DHOST_IPMI_LIB_PATH=\"/usr/lib/host-ipmid/\" 
+
+all: $(IPMI_FRU_PARSER_LIB)
+
+%.o: %.c
+	$(CXX) -fpic -c $< $(CXXFLAGS) $(INC_FLAG) $(IPMID_PATH) -o $@
+
+$(IPMI_FRU_PARSER_LIB): $(IPMI_FRU_PARSER_OBJS)
+	$(CXX) $^ -shared $(LDFLAGS) $(LIB_FLAGS) -o $@
+
+clean:
+	rm -f $(IPMI_FRU_PARSER_OBJS) $(IPMI_FRU_PARSER_LIB)
diff --git a/frup.c b/frup.c
new file mode 100644
index 0000000..d3471ff
--- /dev/null
+++ b/frup.c
@@ -0,0 +1,599 @@
+/*
+ * Copyright (C) 2003-2014 FreeIPMI Core Team
+ * 
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ * 
+ */
+/*****************************************************************************\
+ *  Copyright (C) 2007-2014 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Albert Chu <chu11@llnl.gov>
+ *  UCRL-CODE-232183
+ *
+ *  This file is part of Ipmi-fru, a tool used for retrieving
+ *  motherboard field replaceable unit (FRU) information. For details,
+ *  see http://www.llnl.gov/linux/.
+ *
+ *  Ipmi-fru 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 3 of the License, or (at your
+ *  option) any later version.
+ *
+ *  Ipmi-fru 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 Ipmi-fru.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#define uint8_t unsigned char
+#define uint32_t unsigned int
+
+#define ASSERT(x) if(!(x)) return -1;
+
+
+#define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX            512
+#define IPMI_FRU_SENTINEL_VALUE                        0xC1
+#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK            0xC0
+#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT           0x06
+#define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F
+#define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE   0x03
+
+
+struct ipmi_fru_field
+{
+  uint8_t type_length_field[IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX];
+  /* store length of data stored in buffer */
+  unsigned int type_length_field_length;
+};
+
+typedef struct ipmi_fru_field ipmi_fru_field_t;
+
+static int
+_parse_type_length (const void *areabuf,
+                    unsigned int areabuflen,
+                    unsigned int current_area_offset,
+                    uint8_t *number_of_data_bytes,
+                    ipmi_fru_field_t *field)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  uint8_t type_length;
+  uint8_t type_code;
+
+  ASSERT (areabuf);
+  ASSERT (areabuflen);
+  ASSERT (number_of_data_bytes);
+  
+  type_length = areabufptr[current_area_offset];
+
+  /* IPMI Workaround 
+   *
+   * Dell P weredge R610
+   *
+   * My reading of the FRU Spec is that all non-custom fields are
+   * required to be listed by the vendor.  However, on this
+   * motherboard, some areas list this, indicating that there is
+   * no more data to be parsed.  So now, for "required" fields, I
+   * check to see if the type-length field is a sentinel before
+   * calling this function.
+   */
+
+  ASSERT (type_length != IPMI_FRU_SENTINEL_VALUE);
+
+  type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
+  (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
+
+  /* Special Case: This shouldn't be a length of 0x01 (see type/length
+   * byte format in FRU Information Storage Definition).
+   */
+  if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
+      && (*number_of_data_bytes) == 0x01)
+    {
+      return (-1);
+    }
+
+  if ((current_area_offset + 1 + (*number_of_data_bytes)) > areabuflen)
+    {
+      return (-1);
+    }
+
+  if (field)
+    {
+      memset (field->type_length_field,
+              '\0',
+              IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX);
+      memcpy (field->type_length_field,
+              &areabufptr[current_area_offset],
+              1 + (*number_of_data_bytes));
+      field->type_length_field_length = 1 + (*number_of_data_bytes);
+    }
+      
+  return (0);
+}
+                    
+int
+ipmi_fru_chassis_info_area (const void *areabuf,
+			    unsigned int areabuflen,
+			    uint8_t *chassis_type,
+			    ipmi_fru_field_t *chassis_part_number,
+			    ipmi_fru_field_t *chassis_serial_number,
+			    ipmi_fru_field_t *chassis_custom_fields,
+			    unsigned int chassis_custom_fields_len)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  unsigned int area_offset = 0;
+  unsigned int custom_fields_index = 0;
+  uint8_t number_of_data_bytes;
+  int rv = -1;
+
+  if (!areabuf || !areabuflen)
+    {
+      return (-1);
+    }
+
+  if (chassis_part_number)
+    memset (chassis_part_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (chassis_serial_number)
+    memset (chassis_serial_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (chassis_custom_fields && chassis_custom_fields_len)
+    memset (chassis_custom_fields,
+            '\0',
+            sizeof (ipmi_fru_field_t) * chassis_custom_fields_len);
+
+  if (chassis_type)
+    (*chassis_type) = areabufptr[area_offset];
+  area_offset++;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          chassis_part_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          chassis_serial_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  while (area_offset < areabuflen
+         && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
+    {
+      ipmi_fru_field_t *field_ptr = NULL;
+
+      if (chassis_custom_fields && chassis_custom_fields_len)
+        {
+          if (custom_fields_index < chassis_custom_fields_len)
+            field_ptr = &chassis_custom_fields[custom_fields_index];
+          else
+            {
+              goto cleanup;
+            }
+        }
+
+      if (_parse_type_length (areabufptr,
+                              areabuflen,
+                              area_offset,
+                              &number_of_data_bytes,
+                              field_ptr) < 0)
+        goto cleanup;
+
+      area_offset += 1;          /* type/length byte */
+      area_offset += number_of_data_bytes;
+      custom_fields_index++;
+    }
+
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
+
+int
+ipmi_fru_board_info_area (const void *areabuf,
+			  unsigned int areabuflen,
+			  uint8_t *language_code,
+			  uint32_t *mfg_date_time,
+			  ipmi_fru_field_t *board_manufacturer,
+			  ipmi_fru_field_t *board_product_name,
+			  ipmi_fru_field_t *board_serial_number,
+			  ipmi_fru_field_t *board_part_number,
+			  ipmi_fru_field_t *board_fru_file_id,
+			  ipmi_fru_field_t *board_custom_fields,
+			  unsigned int board_custom_fields_len)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  uint32_t mfg_date_time_tmp = 0;
+  unsigned int area_offset = 0;
+  unsigned int custom_fields_index = 0;
+  uint8_t number_of_data_bytes;
+  int rv = -1;
+
+  if (!areabuf || !areabuflen)
+    {
+      return (-1);
+    }
+
+  if (board_manufacturer)
+    memset (board_manufacturer,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_product_name)
+    memset (board_product_name,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_serial_number)
+    memset (board_serial_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_part_number)
+    memset (board_part_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_fru_file_id)
+    memset (board_fru_file_id,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (board_custom_fields && board_custom_fields_len)
+    memset (board_custom_fields,
+            '\0',
+            sizeof (ipmi_fru_field_t) * board_custom_fields_len);
+
+  if (language_code)
+    (*language_code) = areabufptr[area_offset];
+  area_offset++;
+
+  if (mfg_date_time)
+    {
+      struct tm tm;
+      time_t t;
+
+      /* mfg_date_time is little endian - see spec */
+      mfg_date_time_tmp |= areabufptr[area_offset];
+      area_offset++;
+      mfg_date_time_tmp |= (areabufptr[area_offset] << 8);
+      area_offset++;
+      mfg_date_time_tmp |= (areabufptr[area_offset] << 16);
+      area_offset++;
+      
+      /* mfg_date_time is in minutes, so multiple by 60 to get seconds */
+      mfg_date_time_tmp *= 60;
+
+      /* Posix says individual calls need not clear/set all portions of
+       * 'struct tm', thus passing 'struct tm' between functions could
+       * have issues.  So we need to memset.
+       */
+      memset (&tm, '\0', sizeof(struct tm));
+
+      /* In FRU, epoch is 0:00 hrs 1/1/96
+       *
+       * So convert into ansi epoch
+       */
+
+      tm.tm_year = 96;          /* years since 1900 */
+      tm.tm_mon = 0;            /* months since January */
+      tm.tm_mday = 1;           /* 1-31 */
+      tm.tm_hour = 0;
+      tm.tm_min = 0;
+      tm.tm_sec = 0;
+      tm.tm_isdst = -1;
+
+      if ((t = mktime (&tm)) == (time_t)-1)
+        {
+          goto cleanup;
+        }
+
+      mfg_date_time_tmp += (uint32_t)t;
+      (*mfg_date_time) = mfg_date_time_tmp;
+    }
+  else
+    area_offset += 3;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_manufacturer) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_product_name) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_serial_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (
+                          areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_part_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          board_fru_file_id) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  while (area_offset < areabuflen
+         && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
+    {
+      ipmi_fru_field_t *field_ptr = NULL;
+
+      if (board_custom_fields && board_custom_fields_len)
+        {
+          if (custom_fields_index < board_custom_fields_len)
+            field_ptr = &board_custom_fields[custom_fields_index];
+          else
+            {
+              goto cleanup;
+            }
+        }
+
+      if (_parse_type_length (areabufptr,
+                              areabuflen,
+                              area_offset,
+                              &number_of_data_bytes,
+                              field_ptr) < 0)
+        goto cleanup;
+
+      area_offset += 1;          /* type/length byte */
+      area_offset += number_of_data_bytes;
+      custom_fields_index++;
+    }
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
+
+int
+ipmi_fru_product_info_area (const void *areabuf,
+			    unsigned int areabuflen,
+			    uint8_t *language_code,
+			    ipmi_fru_field_t *product_manufacturer_name,
+			    ipmi_fru_field_t *product_name,
+			    ipmi_fru_field_t *product_part_model_number,
+			    ipmi_fru_field_t *product_version,
+			    ipmi_fru_field_t *product_serial_number,
+			    ipmi_fru_field_t *product_asset_tag,
+			    ipmi_fru_field_t *product_fru_file_id,
+			    ipmi_fru_field_t *product_custom_fields,
+			    unsigned int product_custom_fields_len)
+{
+  const uint8_t *areabufptr = (const uint8_t*) areabuf;
+  unsigned int area_offset = 0;
+  unsigned int custom_fields_index = 0;
+  uint8_t number_of_data_bytes;
+  int rv = -1;
+
+  if (!areabuf || !areabuflen)
+    {
+      return (-1);
+    }
+
+  if (product_manufacturer_name)
+    memset (product_manufacturer_name,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_name)
+    memset (product_name,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_part_model_number)
+    memset (product_part_model_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_version)
+    memset (product_version,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_serial_number)
+    memset (product_serial_number,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_asset_tag)
+    memset (product_asset_tag,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_fru_file_id)
+    memset (product_fru_file_id,
+            '\0',
+            sizeof (ipmi_fru_field_t));
+  if (product_custom_fields && product_custom_fields_len)
+    memset (product_custom_fields,
+            '\0',
+            sizeof (ipmi_fru_field_t) * product_custom_fields_len);
+
+  if (language_code)
+    (*language_code) = areabufptr[area_offset];
+  area_offset++;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_manufacturer_name) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_name) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_part_model_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_version) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_serial_number) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_asset_tag) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  if (areabufptr[area_offset] == IPMI_FRU_SENTINEL_VALUE)
+    goto out;
+
+  if (_parse_type_length (areabufptr,
+                          areabuflen,
+                          area_offset,
+                          &number_of_data_bytes,
+                          product_fru_file_id) < 0)
+    goto cleanup;
+  area_offset += 1;          /* type/length byte */
+  area_offset += number_of_data_bytes;
+
+  while (area_offset < areabuflen
+         && areabufptr[area_offset] != IPMI_FRU_SENTINEL_VALUE)
+    {
+      ipmi_fru_field_t *field_ptr = NULL;
+
+      if (product_custom_fields && product_custom_fields_len)
+        {
+          if (custom_fields_index < product_custom_fields_len)
+            field_ptr = &product_custom_fields[custom_fields_index];
+          else
+            {
+              goto cleanup;
+            }
+        }
+
+      if (_parse_type_length (areabufptr,
+                              areabuflen,
+                              area_offset,
+                              &number_of_data_bytes,
+                              field_ptr) < 0)
+        goto cleanup;
+
+      area_offset += 1;          /* type/length byte */
+      area_offset += number_of_data_bytes;
+      custom_fields_index++;
+    }
+
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH ipmi-fru-parser v2 2/3] IPMI FRU Parser Interface.
  2015-10-16 12:20 [PATCH ipmi-fru-parser v2 0/3] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 1/3] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
@ 2015-10-16 12:20 ` OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 3/3] Added interface function to parse wirte fru data message into a dictionary OpenBMC Patches
  2 siblings, 0 replies; 4+ messages in thread
From: OpenBMC Patches @ 2015-10-16 12:20 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.h | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100644 frup.h

diff --git a/frup.h b/frup.h
new file mode 100644
index 0000000..2270470
--- /dev/null
+++ b/frup.h
@@ -0,0 +1,7 @@
+#ifndef OPENBMC_IPMI_FRU_PARSER_H
+#define OPENBMC_IPMI_FRU_PARSER_H
+
+/* Parse an IPMI write fru data message into a dictionary containing name value pair of VPD entries.*/
+int parse_fru (const void* msgbuf, sd_bus_message* vpdtbl);
+
+#endif
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH ipmi-fru-parser v2 3/3] Added interface function to parse wirte fru data message into a dictionary.
  2015-10-16 12:20 [PATCH ipmi-fru-parser v2 0/3] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 1/3] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
  2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 2/3] IPMI FRU Parser Interface OpenBMC Patches
@ 2015-10-16 12:20 ` OpenBMC Patches
  2 siblings, 0 replies; 4+ messages in thread
From: OpenBMC Patches @ 2015-10-16 12:20 UTC (permalink / raw)
  To: openbmc

From: Hariharasubramanian R <hramasub@in.ibm.com>

---
 frup.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 237 insertions(+), 13 deletions(-)

diff --git a/frup.c b/frup.c
index d3471ff..9711645 100644
--- a/frup.c
+++ b/frup.c
@@ -47,7 +47,19 @@
 #define uint8_t unsigned char
 #define uint32_t unsigned int
 
-#define ASSERT(x) if(!(x)) return -1;
+#define TEXTSTR(a) #a
+# define ASSERT(x) \
+do { \
+if (0 == (x)) { \
+fprintf(stderr, \
+"Assertion failed: %s, " \
+"%d at \'%s\'\n", \
+__FILE__, \
+__LINE__, \
+TEXTSTR(a)); \
+return -1; \
+} \
+} while (0)
 
 
 #define IPMI_FRU_AREA_TYPE_LENGTH_FIELD_MAX            512
@@ -57,6 +69,20 @@
 #define IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK 0x3F
 #define IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE   0x03
 
+/* OpenBMC defines for Parser */
+#define IPMI_FRU_AREA_TYPE_MAX                         0x05
+#define IPMI_FRU_AREA_INTERNAL_USE                     0x00
+#define IPMI_FRU_AREA_CHASSIS_INFO                     0x01
+#define IPMI_FRU_AREA_BOARD_INFO                       0x02
+#define IPMI_FRU_AREA_PRODUCT_INFO                     0x03
+#define IPMI_FRU_AREA_MULTI_RECORD                     0x04
+
+#define OPENBMC_VPD_KEY_LEN                            64
+#define OPENBMC_VPD_VAL_LEN                            512
+
+
+int sd_bus_message_append (void*, const char*, ...);
+typedef struct sd_bus_message sd_bus_message;
 
 struct ipmi_fru_field
 {
@@ -66,7 +92,91 @@ struct ipmi_fru_field
 };
 
 typedef struct ipmi_fru_field ipmi_fru_field_t;
+/* 
+ * FRU Parser 
+ */
+
+typedef struct ipmi_fru_area_info
+{
+    uint8_t off;
+    uint8_t len;
+} ipmi_fru_area_info_t;
+
+typedef struct ipmi_fru_common_hdr
+{
+    uint8_t fmtver;
+    uint8_t internal;
+    uint8_t chassis;
+    uint8_t board;
+    uint8_t product;
+    uint8_t multirec;
+} ipmi_fru_common_hdr_t;
+
+enum openbmc_vpd_key_id
+{
+  OPENBMC_VPD_KEY_CHASSIS_TYPE = 1, /* not a type/len */
+  OPENBMC_VPD_KEY_CHASSIS_PART_NUM,
+  OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,
+  /* TODO: chassis_custom_fields */
+
+  OPENBMC_VPD_KEY_BOARD_MFG_DATE, /* not a type/len */
+  OPENBMC_VPD_KEY_BOARD_MFR,
+  OPENBMC_VPD_KEY_BOARD_NAME,
+  OPENBMC_VPD_KEY_BOARD_SERIAL_NUM,
+  OPENBMC_VPD_KEY_BOARD_PART_NUM,
+  OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID,
+  /* TODO: board_custom_fields */
+
+  OPENBMC_VPD_KEY_PRODUCT_MFR,
+  OPENBMC_VPD_KEY_PRODUCT_NAME,
+  OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM,
+  OPENBMC_VPD_KEY_PRODUCT_VER,
+  OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM,
+  OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG,
+  OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID,
+  /* TODO: product_custom_fields */
+
+  OPENBMC_VPD_KEY_MAX,
+  
+};
+
+const char* vpd_key_names [] = 
+{
+  "Key Names Table Start", 
+  "Chassis Type", /*OPENBMC_VPD_KEY_CHASSIS_TYPE*/
+  "Chassis Part Number", /*OPENBMC_VPD_KEY_CHASSIS_PART_NUM,*/
+  "Chassis Serial Number", /*OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM,*/
+
+  /* TODO: chassis_custom_fields */
+
+  "Board Mfg Date", /* OPENBMC_VPD_KEY_BOARD_MFG_DATE, */ /* not a type/len */
+  "Board Manufacturer", /* OPENBMC_VPD_KEY_BOARD_MFR, */
+  "Board Name", /* OPENBMC_VPD_KEY_BOARD_NAME, */
+  "Board Serial Number", /* OPENBMC_VPD_KEY_BOARD_SERIAL_NUM, */
+  "Board Part Number", /* OPENBMC_VPD_KEY_BOARD_PART_NUM, */
+  "Board FRU File ID", /* OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID, */
+  /* TODO: board_custom_fields */
+
+  "Product Manufacturer", /* OPENBMC_VPD_KEY_PRODUCT_MFR, */
+  "Product Name", /* OPENBMC_VPD_KEY_PRODUCT_NAME, */
+  "Product Model Number", /* OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM, */
+  "Product Version", /* OPENBMC_VPD_KEY_PRODUCT_VER, */
+  "Product Serial Number", /* OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM, */
+  "Product Asset Tag", /* OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG, */
+  "Product FRU File ID", /* OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID, */
+  /* TODO: product_custom_fields */
+
+  "Key Names Table End" /*OPENBMC_VPD_KEY_MAX,*/
+};
 
+
+/*
+ * --------------------------------------------------------------------
+ *
+ * --------------------------------------------------------------------
+ */
+
+/* private method to parse type/length */
 static int
 _parse_type_length (const void *areabuf,
                     unsigned int areabuflen,
@@ -84,14 +194,14 @@ _parse_type_length (const void *areabuf,
   
   type_length = areabufptr[current_area_offset];
 
-  /* IPMI Workaround 
+  /* ipmi workaround 
    *
-   * Dell P weredge R610
+   * dell p weredge r610
    *
-   * My reading of the FRU Spec is that all non-custom fields are
-   * required to be listed by the vendor.  However, on this
+   * my reading of the fru spec is that all non-custom fields are
+   * required to be listed by the vendor.  however, on this
    * motherboard, some areas list this, indicating that there is
-   * no more data to be parsed.  So now, for "required" fields, I
+   * no more data to be parsed.  so now, for "required" fields, i
    * check to see if the type-length field is a sentinel before
    * calling this function.
    */
@@ -101,8 +211,8 @@ _parse_type_length (const void *areabuf,
   type_code = (type_length & IPMI_FRU_TYPE_LENGTH_TYPE_CODE_MASK) >> IPMI_FRU_TYPE_LENGTH_TYPE_CODE_SHIFT;
   (*number_of_data_bytes) = type_length & IPMI_FRU_TYPE_LENGTH_NUMBER_OF_DATA_BYTES_MASK;
 
-  /* Special Case: This shouldn't be a length of 0x01 (see type/length
-   * byte format in FRU Information Storage Definition).
+  /* special case: this shouldn't be a length of 0x01 (see type/length
+   * byte format in fru information storage definition).
    */
   if (type_code == IPMI_FRU_TYPE_LENGTH_TYPE_CODE_LANGUAGE_CODE
       && (*number_of_data_bytes) == 0x01)
@@ -294,19 +404,19 @@ ipmi_fru_board_info_area (const void *areabuf,
       /* mfg_date_time is in minutes, so multiple by 60 to get seconds */
       mfg_date_time_tmp *= 60;
 
-      /* Posix says individual calls need not clear/set all portions of
+      /* posix says individual calls need not clear/set all portions of
        * 'struct tm', thus passing 'struct tm' between functions could
-       * have issues.  So we need to memset.
+       * have issues.  so we need to memset.
        */
       memset (&tm, '\0', sizeof(struct tm));
 
-      /* In FRU, epoch is 0:00 hrs 1/1/96
+      /* in fru, epoch is 0:00 hrs 1/1/96
        *
-       * So convert into ansi epoch
+       * so convert into ansi epoch
        */
 
       tm.tm_year = 96;          /* years since 1900 */
-      tm.tm_mon = 0;            /* months since January */
+      tm.tm_mon = 0;            /* months since january */
       tm.tm_mday = 1;           /* 1-31 */
       tm.tm_hour = 0;
       tm.tm_min = 0;
@@ -597,3 +707,117 @@ ipmi_fru_product_info_area (const void *areabuf,
  cleanup:
   return (rv);
 }
+
+
+int
+parse_fru (const void* msgbuf, sd_bus_message* vpdtbl)
+{
+  int ret = 0;
+  int rv = -1;
+  int i = 0;
+  ipmi_fru_area_info_t fru_area_info [ IPMI_FRU_AREA_TYPE_MAX ];
+  ipmi_fru_common_hdr_t* chdr = NULL;
+  uint8_t* hdr = NULL;
+
+
+  ipmi_fru_field_t vpd_info [ OPENBMC_VPD_KEY_MAX ];
+
+  /* Chassis */
+  uint8_t chassis_type;
+
+  /* Board */
+  uint32_t mfg_date_time;
+
+  /* Product */
+  unsigned int product_custom_fields_len;
+
+  ASSERT (msgbuf);
+  ASSERT (vpdtbl);
+
+  chdr = (ipmi_fru_common_hdr_t*) msgbuf;
+  hdr  = (uint8_t*) msgbuf;
+
+  fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].off = chdr->internal;
+  fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].off = chdr->chassis;
+  fru_area_info [ IPMI_FRU_AREA_BOARD_INFO   ].off = chdr->board;
+  fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].off = chdr->product;
+  fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].off = chdr->multirec;
+
+  if (chdr->internal)
+  {
+    fru_area_info [ IPMI_FRU_AREA_INTERNAL_USE ].len = 8*(*(hdr+chdr->internal+1));
+    
+    /* TODO: Parse internal use area */
+  }
+
+  if (chdr->chassis)
+  {
+    fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len = 8*(*(hdr+chdr->chassis+1));
+    ipmi_fru_chassis_info_area (hdr+chdr->chassis,
+        fru_area_info [ IPMI_FRU_AREA_CHASSIS_INFO ].len,
+        &chassis_type,
+        &vpd_info [OPENBMC_VPD_KEY_CHASSIS_PART_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_CHASSIS_SERIAL_NUM],
+        NULL, 0);
+  }
+    
+  if (chdr->board)
+  {
+    fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len = 8*(*(hdr+chdr->board+1));
+    ipmi_fru_board_info_area (hdr+chdr->board, 
+        fru_area_info [ IPMI_FRU_AREA_BOARD_INFO ].len,
+        NULL,
+        &mfg_date_time,
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_MFR],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_NAME],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_SERIAL_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_PART_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_BOARD_FRU_FILE_ID],
+        NULL, 0);
+  }
+
+  if (chdr->product)
+  {
+    fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len = 8*(*(hdr+chdr->product+1));
+    ipmi_fru_product_info_area (hdr+chdr->product, 
+        fru_area_info [ IPMI_FRU_AREA_PRODUCT_INFO ].len,
+        NULL,
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_MFR],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_NAME],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_PART_MODEL_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_VER],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_SERIAL_NUM],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_ASSET_TAG],
+        &vpd_info [OPENBMC_VPD_KEY_PRODUCT_FRU_FILE_ID],
+        NULL, 0);
+  }
+
+  if (chdr->multirec)
+  {
+    fru_area_info [ IPMI_FRU_AREA_MULTI_RECORD ].len = 8*(*(hdr+chdr->multirec+1));
+    /* TODO: Parse multi record area */
+  }
+
+  /* Populate VPD Table */
+  for (i=1; i<OPENBMC_VPD_KEY_MAX; i++)
+  {
+    if (i==OPENBMC_VPD_KEY_CHASSIS_TYPE)
+    {
+        sd_bus_message_append (vpdtbl, "sd", vpd_key_names[i], chassis_type);
+        continue;
+    }
+
+    if (i==OPENBMC_VPD_KEY_BOARD_MFG_DATE)
+    {
+        sd_bus_message_append (vpdtbl, "sd", vpd_key_names[i], mfg_date_time);
+        continue;
+    }
+    
+    sd_bus_message_append (vpdtbl, "ss", vpd_key_names[i], vpd_info [i].type_length_field); 
+  }
+
+ out:
+  rv = 0;
+ cleanup:
+  return (rv);
+}
-- 
2.6.0

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-10-16 12:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-16 12:20 [PATCH ipmi-fru-parser v2 0/3] Checking in the basic IPMI FRU Parser Library OpenBMC Patches
2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 1/3] Checking in the basic IPMI FRU Parser Library. Parser has just enough intelligence to parse Chassis, Board & Product info areas. No support for multi-record in this version. This parser is a stripped down version of the parser in the FreeIPMI distribution OpenBMC Patches
2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 2/3] IPMI FRU Parser Interface OpenBMC Patches
2015-10-16 12:20 ` [PATCH ipmi-fru-parser v2 3/3] Added interface function to parse wirte fru data message into a dictionary OpenBMC Patches

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.