[Skiboot] [RFC PATCH 4/6] opal/errorlog: Add support to include callout section in error log.
Mahesh Salgaonkar
mahesh at linux.vnet.ibm.com
Wed Apr 24 04:13:05 AEST 2019
Allow inclusion of HW callout to eSEL being generated. This will help OPAL
to generate errorlog with fru callout section that includes location code,
part number and serial number of a faulty hardware that may need replacement.
Signed-off-by: Mahesh Salgaonkar <mahesh at linux.vnet.ibm.com>
---
core/errorlog.c | 32 ++++++++++++++++++++++
core/pel.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/errorlog.h | 9 ++++++
include/pel.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 186 insertions(+)
diff --git a/core/errorlog.c b/core/errorlog.c
index 31e603815..54a6d446e 100644
--- a/core/errorlog.c
+++ b/core/errorlog.c
@@ -117,6 +117,38 @@ void log_add_section(struct errorlog *buf, uint32_t tag)
buf->user_section_count++;
}
+void log_add_callout_section(struct errorlog *buf, const char *loc_code,
+ const char *part_no, const char *serial_no)
+{
+ if (!buf) {
+ prerror("ELOG: Cannot add callout section. "
+ "Buffer is invalid\n");
+ return;
+ }
+
+ /* Location codes -- at most 80 chars with null termination */
+ if (strlen(loc_code) >= LOC_CODE_SIZE) {
+ prerror("ELOG: Invalid Size of location code.\n");
+ return;
+ }
+
+ buf->fru_callout = true;
+ memset(buf->loc_code, 0, LOC_CODE_SIZE);
+ strcpy(buf->loc_code, loc_code);
+
+ /*
+ * Part number contains a null-terminated ASCII character string.
+ * 7 ASCII character part number
+ */
+ if (part_no) {
+ memcpy(buf->part_no, part_no, OPAL_FRU_PART_LEN);
+ buf->part_no[7] = '\0';
+ }
+
+ if (serial_no)
+ memcpy(buf->serial_no, serial_no, OPAL_FRU_SERIAL_LEN);
+}
+
void opal_elog_complete(struct errorlog *buf, bool success)
{
if (!success)
diff --git a/core/pel.c b/core/pel.c
index 62cf6b3c9..2724bcee9 100644
--- a/core/pel.c
+++ b/core/pel.c
@@ -98,10 +98,77 @@ static void setrefcode(struct opal_src_section *src, uint16_t src_refcode)
memcpy(src->srcstring+4, refcode, 4);
}
+static int create_fru_identity(struct errorlog *elog_data,
+ char *pel_buffer, int pel_offset)
+{
+ int data_len = 0;
+ struct opal_fru_identity *identity;
+
+ identity = (struct opal_fru_identity *)(pel_buffer + pel_offset);
+
+ if (!strlen(elog_data->part_no) && !strlen(elog_data->serial_no))
+ return 0;
+
+ identity->id = OPAL_FRU_IDENT_ID;
+ identity->flags = OPAL_FRU_IDENT_FLAG_NORMAL;
+
+ if (strlen(elog_data->part_no)) {
+ identity->flags |= OPAL_FRU_IDENT_FLAG_PART;
+ memset(identity->fru_data, 0, OPAL_FRU_PART_LEN);
+ memcpy(identity->fru_data, elog_data->part_no,
+ OPAL_FRU_PART_LEN);
+ data_len = OPAL_FRU_PART_LEN;
+ }
+
+ if (strlen(elog_data->serial_no)) {
+ identity->flags |= OPAL_FRU_IDENT_FLAG_SERIAL;
+ memset(identity->fru_data + data_len, 0, OPAL_FRU_SERIAL_LEN);
+ memcpy(identity->fru_data + data_len, elog_data->serial_no,
+ OPAL_FRU_SERIAL_LEN);
+ data_len += OPAL_FRU_SERIAL_LEN;
+ }
+ identity->length = FRU_IDENTITY_HEADER_SIZE + data_len;
+
+ return identity->length;
+}
+
+static int create_fru_callout_section(struct errorlog *elog_data,
+ char *pel_buffer, int pel_offset)
+{
+ int len;
+ struct opal_fru_callout_section *fru;
+
+ fru = (struct opal_fru_callout_section *)(pel_buffer + pel_offset);
+ fru->header.id = OPAL_SRC_SUB_SECTION_ID;
+ fru->header.flags = 0;
+
+ fru->callout.type = OPAL_FRU_TYPE_NORMAL;
+ fru->callout.priority = OPAL_FRU_PRIO_MEDIUM;
+ len = strlen(elog_data->loc_code);
+
+ /* Length of Location Code field - must be a multiple of 4. */
+ len = ALIGN_UP(len, 4);
+ memcpy(fru->callout.loc_code, elog_data->loc_code, len);
+ fru->callout.loc_code_len = len;
+ fru->callout.length = FRU_CALLOUT_SECTION_SIZE +
+ fru->callout.loc_code_len;
+
+ len = create_fru_identity(elog_data, pel_buffer,
+ pel_offset + SRC_SUBSECTION_SIZE + fru->callout.length);
+
+ fru->callout.length += len;
+
+ /* SRC sub section size is expressed in # of words (4 byte fields) */
+ fru->header.length = (SRC_SUBSECTION_SIZE + fru->callout.length) / 4;
+
+ return SRC_SUBSECTION_SIZE + fru->callout.length;
+}
+
/* Create SRC section of OPAL log */
static void create_src_section(struct errorlog *elog_data,
char *pel_buffer, int *pel_offset)
{
+ int len;
struct opal_src_section *src = (struct opal_src_section *)
(pel_buffer + *pel_offset);
@@ -125,6 +192,16 @@ static void create_src_section(struct errorlog *elog_data,
src->hexwords[6] = elog_data->additional_info[2];
src->hexwords[7] = elog_data->additional_info[3];
*pel_offset += SRC_SECTION_SIZE;
+
+ if (!elog_data->fru_callout)
+ return;
+
+ /* Fill up src sub section header */
+ len = create_fru_callout_section(elog_data, pel_buffer, *pel_offset);
+ src->srclength += len;
+ src->v6header.length += len;
+ src->flags |= OPAL_SRC_FLAG_SUB_SECTION_PRESENT;
+ *pel_offset += len;
}
/* Create user header section */
diff --git a/include/errorlog.h b/include/errorlog.h
index 9ccfb47ec..a99c63fc5 100644
--- a/include/errorlog.h
+++ b/include/errorlog.h
@@ -102,6 +102,9 @@
/* Max user dump size is 14K */
#define OPAL_LOG_MAX_DUMP 14336
+#define OPAL_FRU_PART_LEN 8
+#define OPAL_FRU_SERIAL_LEN 12
+
/* Origin of error, elog_origin */
#define ORG_SAPPHIRE 1
#define ORG_POWERNV 2
@@ -138,6 +141,10 @@ struct __attribute__((__packed__)) errorlog {
uint32_t log_size;
uint64_t elog_timeout;
bool service_req;
+ bool fru_callout;
+ char loc_code[LOC_CODE_SIZE];
+ char part_no[OPAL_FRU_PART_LEN];
+ char serial_no[OPAL_FRU_SERIAL_LEN];
char user_data_dump[OPAL_LOG_MAX_DUMP];
struct list_node link;
@@ -358,6 +365,8 @@ uint32_t log_simple_error(struct opal_err_info *e_info,
struct errorlog *opal_elog_create(struct opal_err_info *e_info,
uint32_t tag) __warn_unused_result;
void log_add_section(struct errorlog *buf, uint32_t tag);
+void log_add_callout_section(struct errorlog *buf, const char *loc_code,
+ const char *part_no, const char *serial_no);
void log_append_data(struct errorlog *buf, unsigned char *data, uint16_t size);
void log_append_msg(struct errorlog *buf,
const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
diff --git a/include/pel.h b/include/pel.h
index 0bfaa33c0..95c6755bb 100644
--- a/include/pel.h
+++ b/include/pel.h
@@ -30,6 +30,8 @@
#define EXTENDED_HEADER_SECTION_SIZE 76
#define MTMS_SECTION_SIZE 28
#define IO_EVENT_SECTION_SIZE 16
+#define FRU_CALLOUT_SECTION_SIZE 4
+#define FRU_IDENTITY_HEADER_SIZE 4
#define OPAL_ELOG_VERSION 1
#define OPAL_ELOG_SST 0
@@ -48,6 +50,8 @@
#define OPAL_SRC_SEC_VER 0x02
#define OPAL_EXT_HRD_VER 0x01
+#define OPAL_SRC_FLAG_SUB_SECTION_PRESENT 0x01
+
/* Error log reporting action */
#define ERRL_ACTION_REPORT 0x2000
#define ERRL_ACTION_SERVICE 0x8000
@@ -83,6 +87,37 @@ struct opal_v6_header {
/* opal_srctype */
#define OPAL_SRC_TYPE_ERROR 0xBB
+/* opal SRC subsection id */
+#define OPAL_SRC_SUB_SECTION_ID 0xC0
+
+/* FRU callout Type */
+#define OPAL_FRU_TYPE_NORMAL 0x2
+/* FRU callout flags */
+#define OPAL_FRU_FLAG_IDENTITY_INCLUDED 0x8
+#define OPAL_FRU_FLAG_MRU_INCLUDED 0x4
+/* FRU callout priority */
+#define OPAL_FRU_PRIO_HIGH 'H'
+#define OPAL_FRU_PRIO_MEDIUM 'M'
+#define OPAL_FRU_PRIO_MEDIUM_GROUP_A 'A'
+#define OPAL_FRU_PRIO_MEDIUM_GROUP_B 'B'
+#define OPAL_FRU_PRIO_MEDIUM_GROUP_C 'C'
+#define OPAL_FRU_PRIO_LOW 'L'
+
+/* FRU identity srtucture id */
+#define OPAL_FRU_IDENT_ID 0x4944 /* ID */
+/* FRU identity flags bits 0-3 */
+#define OPAL_FRU_IDENT_FLAG_NORMAL 0x10 /* "normal" hardware FRU */
+#define OPAL_FRU_IDENT_FLAG_CODE 0x20 /* code FRU */
+#define OPAL_FRU_IDENT_FLAG_CONFIG 0x30 /* configuration error */
+#define OPAL_FRU_IDENT_FLAG_MAINT 0x40 /* Maintenance Procedure req */
+#define OPAL_FRU_IDENT_FLAG_EXT 0x90 /* External FRU */
+#define OPAL_FRU_IDENT_FLAG_EXT_CODE 0xa0 /* External code FRU */
+#define OPAL_FRU_IDENT_FLAG_TOOL 0xb0 /* Tool FRU */
+#define OPAL_FRU_IDENT_FLAG_SYMBOL 0xc0 /* Symbolic FRU */
+/* FRU identity flags bits 4-7 */
+#define OPAL_FRU_IDENT_FLAG_PART 0x08 /* FRU Part Number supplied */
+#define OPAL_FRU_IDENT_FLAG_CCIN 0x04 /* CCIN supplied */
+#define OPAL_FRU_IDENT_FLAG_SERIAL 0x01 /* FRU serial number supplied */
#define OPAL_CID_SAPPHIRE 'K' /* creator ID for sapphire log */
#define OPAL_CID_POWERNV 'P' /* creator ID for powernv log */
@@ -141,6 +176,39 @@ struct opal_src_section {
char srcstring[OPAL_MAX_SRC_BYTES];
};
+struct opal_src_sub_section {
+ uint8_t id; /* SRC sub section id */
+ uint8_t flags;
+ uint16_t length; /* in # of words (4 byte fields) */
+};
+
+struct opal_fru_callout {
+ uint8_t length; /* in bytes */
+ uint8_t type:4;
+ uint8_t flags:4;
+ uint8_t priority;
+ uint8_t loc_code_len;
+ char loc_code[0];
+};
+
+struct opal_fru_callout_section {
+ struct opal_src_sub_section header;
+ struct opal_fru_callout callout;
+};
+
+struct opal_fru_identity {
+ uint16_t id;
+ uint8_t length;
+ uint8_t flags;
+ /*
+ * Depending on flags[4-7] bits fru_data will contain:
+ * part number 8 bytes (7 ASCII character + 1 null-terminator)
+ * CCIN number 4 bytes (not a null-terminated string)
+ * FRU serial number 12 bytes (not a null-terminated string)
+ */
+ char fru_data[0];
+};
+
struct opal_extended_header_section {
struct opal_v6_header v6header;
char model[OPAL_SYS_MODEL_LEN];
More information about the Skiboot
mailing list