From patchwork Wed Oct 7 12:09:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mahesh J Salgaonkar X-Patchwork-Id: 1377977 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4C5tV21YNLz9sSG for ; Wed, 7 Oct 2020 23:11:22 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linux.ibm.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=c24/WdGr; dkim-atps=neutral Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 4C5tV20TsMzDqPW for ; Wed, 7 Oct 2020 23:11:22 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=mahesh@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=c24/WdGr; dkim-atps=neutral Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4C5tRc3HZdzDqPf for ; Wed, 7 Oct 2020 23:09:16 +1100 (AEDT) Received: from pps.filterd (m0098410.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 097C2V8e011418 for ; Wed, 7 Oct 2020 08:09:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=subject : from : to : cc : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=pp1; bh=Yyz2xqFxU456B7i7t4OP9M1Xi8AYBYOwx3QeZqSj8VA=; b=c24/WdGrbEfOaytzUCX7fNPQTkhpQ7hBu1d2kluCAaiJY8bt4qbXtyUPm/1jCk9aGBqc 4nA4rydoErLWOZ+7HpnN5dmfaHU9wwsC4nMTAjEmU+ZfXI0BWU7+7p9JsonKE50FT6Um h5gOOgmJjTUV2wGR5LYdlJ0wPF+C25iPQLThLUTxbzEL1ED7Ca1Pfw3zcVae9Kgf/ThU DZHnE+925IgjzhANn9YM1LhwAlwQYtS03M7gQBzT4HEKr6o4lZrlOoM1IL35IstwHurQ oEZ8xmD5eBaTMvUkziCGsuahBIALXyl3dcrysy6W92jBJ2TKJQAPlsiWO452fltUHhvp nQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 341d7e0he0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Wed, 07 Oct 2020 08:09:14 -0400 Received: from m0098410.ppops.net (m0098410.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.36/8.16.0.36) with SMTP id 097C2jvT013302 for ; Wed, 7 Oct 2020 08:09:14 -0400 Received: from ppma03ams.nl.ibm.com (62.31.33a9.ip4.static.sl-reverse.com [169.51.49.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 341d7e0hct-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 07 Oct 2020 08:09:13 -0400 Received: from pps.filterd (ppma03ams.nl.ibm.com [127.0.0.1]) by ppma03ams.nl.ibm.com (8.16.0.42/8.16.0.42) with SMTP id 097C87h1021531; Wed, 7 Oct 2020 12:09:11 GMT Received: from b06cxnps3075.portsmouth.uk.ibm.com (d06relay10.portsmouth.uk.ibm.com [9.149.109.195]) by ppma03ams.nl.ibm.com with ESMTP id 33xgx8c8tt-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 07 Oct 2020 12:09:11 +0000 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 097C99HN33292732 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 7 Oct 2020 12:09:09 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 068E34C050; Wed, 7 Oct 2020 12:09:09 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4460C4C046; Wed, 7 Oct 2020 12:09:08 +0000 (GMT) Received: from [192.168.0.63] (unknown [9.199.48.78]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Wed, 7 Oct 2020 12:09:08 +0000 (GMT) From: Mahesh Salgaonkar To: skiboot list Date: Wed, 07 Oct 2020 17:39:07 +0530 Message-ID: <160207254747.2097386.5086237208543320593.stgit@jupiter> In-Reply-To: <160207247879.2097386.9393389763183654717.stgit@jupiter> References: <160207247879.2097386.9393389763183654717.stgit@jupiter> User-Agent: StGit/0.21 MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.235, 18.0.687 definitions=2020-10-07_08:2020-10-06, 2020-10-07 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 phishscore=0 clxscore=1015 impostorscore=0 mlxscore=0 mlxlogscore=999 adultscore=0 lowpriorityscore=0 priorityscore=1501 bulkscore=0 spamscore=0 malwarescore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2010070079 Subject: [Skiboot] [PATCH v2 03/10] opal/errorlog: Add support to include callout section in error log. X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vasant Hegde Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" From: Mahesh Salgaonkar 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 --- Change in v2: - Avoid use of bitfields in opal_fru_callout structure. --- core/errorlog.c | 49 +++++++++++++++++ core/pel.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/errorlog.h | 17 ++++++ include/pel.h | 71 ++++++++++++++++++++++++ 4 files changed, 287 insertions(+), 2 deletions(-) diff --git a/core/errorlog.c b/core/errorlog.c index 2f7bcce19..0ea248b39 100644 --- a/core/errorlog.c +++ b/core/errorlog.c @@ -105,6 +105,55 @@ 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) +{ + int index; + struct elog_fru_callout *fru; + + if (!buf) { + prerror("ELOG: Cannot add callout section. " + "Buffer is invalid\n"); + return; + } + index = buf->num_fru_callout; + fru = &buf->fru_callout[index]; + + if (buf->num_fru_callout >= PEL_MAX_FRU_CALL_OUTS) { + prerror("ELOG: Cannot add callout section. " + "Maximum limit reached\n"); + return; + } + + if (!loc_code) { + prerror("ELOG: Cannot add callout section. " + "location code is not specified\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->num_fru_callout++; + memset(fru->loc_code, 0, LOC_CODE_SIZE); + strcpy(fru->loc_code, loc_code); + + /* + * Part number contains a null-terminated ASCII character string. + * 7 ASCII character part number + */ + if (part_no) { + memcpy(fru->part_no, part_no, PEL_FRU_PART_LEN); + fru->part_no[7] = '\0'; + } + + if (serial_no) + memcpy(fru->serial_no, serial_no, PEL_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 3a200238e..1be1ab990 100644 --- a/core/pel.c +++ b/core/pel.c @@ -107,10 +107,112 @@ static void setrefcode(struct pel_src_section *src, uint16_t src_refcode) memcpy(src->srcstring+4, refcode, 4); } +static int create_fru_identity(struct elog_fru_callout *elog_fru, + char *pel_buffer, int pel_offset) +{ + int data_len = 0; + struct pel_fru_identity *identity; + + identity = (struct pel_fru_identity *)(pel_buffer + pel_offset); + + if (!strlen(elog_fru->part_no) && !strlen(elog_fru->serial_no)) + return 0; + + identity->id = PEL_FRU_IDENT_ID; + identity->flags = PEL_FRU_IDENT_FLAG_NORMAL; + + if (strlen(elog_fru->part_no)) { + identity->flags |= PEL_FRU_IDENT_FLAG_PART; + memset(identity->fru_data, 0, PEL_FRU_PART_LEN); + memcpy(identity->fru_data, elog_fru->part_no, + PEL_FRU_PART_LEN); + data_len = PEL_FRU_PART_LEN; + } + + if (strlen(elog_fru->serial_no)) { + identity->flags |= PEL_FRU_IDENT_FLAG_SERIAL; + memset(identity->fru_data + data_len, 0, PEL_FRU_SERIAL_LEN); + memcpy(identity->fru_data + data_len, elog_fru->serial_no, + PEL_FRU_SERIAL_LEN); + data_len += PEL_FRU_SERIAL_LEN; + } + identity->length = FRU_IDENTITY_HEADER_SIZE + data_len; + + return identity->length; +} + +/* + * The FRU Call-out section is added as additional/optional sub section. + * Each additional sub section starts with sub section header followed by + * data. The sub section header contains section id, flags and size of the + * sub section including header size. A variable number of FRU Call-outs are + * possible up to the maximum of 10. Each FRU Callout structure starts on a + * word boundary. + */ +static int create_fru_callout_section(struct errorlog *elog_data, + char *pel_buffer, int pel_offset) +{ + int len; + struct pel_fru_callout_section *fru; + struct pel_fru_callout *fru_callout; + int i, fru_count; + + fru = (struct pel_fru_callout_section *)(pel_buffer + pel_offset); + fru->header.id = PEL_SRC_SUB_SECTION_ID; + fru->header.flags = 0; + /* + * Initialize SRC sub section size with sub section header size. + * SRC sub section size is expressed in # of words (4 byte fields) + * SRC sub section size will be updated for each FRU call out. + */ + fru->header.length += SRC_SUBSECTION_HEADER_SIZE / 4; + pel_offset += SRC_SUBSECTION_HEADER_SIZE; + fru_callout = (struct pel_fru_callout *)(pel_buffer + pel_offset); + + /* Add FRU Call-outs */ + fru_count = MIN(PEL_MAX_FRU_CALL_OUTS, elog_data->num_fru_callout); + for (i = 0; i < fru_count; i++) { + struct elog_fru_callout *elog_fru = &elog_data->fru_callout[i]; + + /* Set FRU callout type */ + fru_callout->type_flags |= PEL_FRU_TYPE_NORMAL; + fru_callout->priority = PEL_FRU_PRIO_MEDIUM; + /* Size of loc-code including NULL terminator. */ + len = strlen(elog_fru->loc_code) + 1; + + /* Length of Location Code field - must be a multiple of 4. */ + len = ALIGN_UP(len, 4); + memcpy(fru_callout->loc_code, elog_fru->loc_code, len); + fru_callout->loc_code_len = len; + fru_callout->length = FRU_CALLOUT_SECTION_SIZE + + fru_callout->loc_code_len; + + pel_offset += fru_callout->length; + len = create_fru_identity(elog_fru, pel_buffer, pel_offset); + if (len) { + /* Set FRU callout flag */ + fru_callout->type_flags |= + PEL_FRU_FLAG_IDENTITY_INCLUDED; + } + fru_callout->length += len; + pel_offset += len; + + /* + * SRC sub section size is expressed in # of words + * (4 byte fields) + */ + fru->header.length += fru_callout->length / 4; + fru_callout = + (struct pel_fru_callout *)(pel_buffer + pel_offset); + } + return fru->header.length * 4; +} + /* Create SRC section of OPAL log */ static void create_src_section(struct errorlog *elog_data, char *pel_buffer, int *pel_offset) { + int len; struct pel_src_section *src = (struct pel_src_section *) (pel_buffer + *pel_offset); @@ -134,6 +236,16 @@ static void create_src_section(struct errorlog *elog_data, src->hexwords[6] = cpu_to_be32(elog_data->additional_info[2]); src->hexwords[7] = cpu_to_be32(elog_data->additional_info[3]); *pel_offset += SRC_SECTION_SIZE; + + if (!elog_data->num_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 |= PEL_SRC_FLAG_SUB_SECTION_PRESENT; + *pel_offset += len; } /* Create user header section */ @@ -252,9 +364,47 @@ static size_t pel_user_section_size(struct errorlog *elog_data) return total; } +static size_t pel_fru_callout_section_size(struct errorlog *elog_data) +{ + int i, fru_count; + size_t total = 0; + + if (!elog_data->num_fru_callout) + return 0; + + total += SRC_SUBSECTION_HEADER_SIZE; + fru_count = MIN(PEL_MAX_FRU_CALL_OUTS, elog_data->num_fru_callout); + for (i = 0; i < fru_count; i++) { + size_t len; + + total += FRU_CALLOUT_SECTION_SIZE; + /* Size of loc-code including NULL terminator. */ + len = strlen(elog_data->fru_callout[i].loc_code) + 1; + len = ALIGN_UP(len, 4); + total += len; + + /* Calculate size for FRU identity if present */ + if (!strlen(elog_data->fru_callout[i].part_no) + && !strlen(elog_data->fru_callout[i].serial_no)) + continue; + + if (strlen(elog_data->fru_callout[i].part_no)) + total += PEL_FRU_PART_LEN; + + if (strlen(elog_data->fru_callout[i].serial_no)) + total += PEL_FRU_SERIAL_LEN; + + total += FRU_IDENTITY_HEADER_SIZE; + } + return total; +} + size_t pel_size(struct errorlog *elog_data) { - return PEL_MIN_SIZE + pel_user_section_size(elog_data); + size_t len; + + len = PEL_MIN_SIZE + pel_user_section_size(elog_data); + return len + pel_fru_callout_section_size(elog_data); } /* Converts an OPAL errorlog into a PEL formatted log */ diff --git a/include/errorlog.h b/include/errorlog.h index 74fe8b1fd..a9c3250e8 100644 --- a/include/errorlog.h +++ b/include/errorlog.h @@ -89,6 +89,12 @@ /* Max user dump size is 14K */ #define OPAL_LOG_MAX_DUMP 14336 +#define PEL_FRU_PART_LEN 8 +#define PEL_FRU_SERIAL_LEN 12 + +/* Maximum possible FRU Call-outs in PEL errorlog */ +#define PEL_MAX_FRU_CALL_OUTS 10 + /* Origin of error, elog_origin */ #define ORG_SAPPHIRE 1 #define ORG_POWERNV 2 @@ -101,6 +107,13 @@ struct elog_user_data_section { char data_dump[1]; } __packed; + +struct elog_fru_callout { + char loc_code[LOC_CODE_SIZE]; + char part_no[PEL_FRU_PART_LEN]; + char serial_no[PEL_FRU_SERIAL_LEN]; +}; + /* * All the information regarding an error/event to be reported * needs to populate this structure using pre-defined interfaces @@ -125,6 +138,8 @@ struct errorlog { uint32_t log_size; uint64_t elog_timeout; bool service_req; + uint16_t num_fru_callout; + struct elog_fru_callout fru_callout[PEL_MAX_FRU_CALL_OUTS]; char user_data_dump[OPAL_LOG_MAX_DUMP]; struct list_node link; @@ -347,6 +362,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 fdc30366a..968bf2779 100644 --- a/include/pel.h +++ b/include/pel.h @@ -12,12 +12,14 @@ #define PRIVATE_HEADER_SECTION_SIZE 48 #define USER_HEADER_SECTION_SIZE 24 #define SRC_SECTION_SIZE 80 -#define SRC_SUBSECTION_SIZE 4 +#define SRC_SUBSECTION_HEADER_SIZE 4 #define SRC_LENGTH 72 #define PEL_MAX_SRC_BYTES 32 #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 PEL_ELOG_VERSION 1 #define PEL_ELOG_SST 0 @@ -36,6 +38,8 @@ #define PEL_SRC_SEC_VER 0x02 #define PEL_EXT_HRD_VER 0x01 +#define PEL_SRC_FLAG_SUB_SECTION_PRESENT 0x01 + /* Error log reporting action */ #define ERRL_ACTION_REPORT 0x2000 #define ERRL_ACTION_SERVICE 0x8000 @@ -71,6 +75,37 @@ struct pel_v6_header { /* opal_srctype */ #define OPAL_SRC_TYPE_ERROR 0xBB +/* pel SRC subsection id */ +#define PEL_SRC_SUB_SECTION_ID 0xC0 + +/* FRU callout Type */ +#define PEL_FRU_TYPE_NORMAL 0x20 +/* FRU callout flags */ +#define PEL_FRU_FLAG_IDENTITY_INCLUDED 0x08 +#define PEL_FRU_FLAG_MRU_INCLUDED 0x04 +/* FRU callout priority */ +#define PEL_FRU_PRIO_HIGH 'H' +#define PEL_FRU_PRIO_MEDIUM 'M' +#define PEL_FRU_PRIO_MEDIUM_GROUP_A 'A' +#define PEL_FRU_PRIO_MEDIUM_GROUP_B 'B' +#define PEL_FRU_PRIO_MEDIUM_GROUP_C 'C' +#define PEL_FRU_PRIO_LOW 'L' + +/* FRU identity srtucture id */ +#define PEL_FRU_IDENT_ID 0x4944 /* ID */ +/* FRU identity flags bits 0-3 */ +#define PEL_FRU_IDENT_FLAG_NORMAL 0x10 /* "normal" hardware FRU */ +#define PEL_FRU_IDENT_FLAG_CODE 0x20 /* code FRU */ +#define PEL_FRU_IDENT_FLAG_CONFIG 0x30 /* configuration error */ +#define PEL_FRU_IDENT_FLAG_MAINT 0x40 /* Maintenance Procedure req */ +#define PEL_FRU_IDENT_FLAG_EXT 0x90 /* External FRU */ +#define PEL_FRU_IDENT_FLAG_EXT_CODE 0xa0 /* External code FRU */ +#define PEL_FRU_IDENT_FLAG_TOOL 0xb0 /* Tool FRU */ +#define PEL_FRU_IDENT_FLAG_SYMBOL 0xc0 /* Symbolic FRU */ +/* FRU identity flags bits 4-7 */ +#define PEL_FRU_IDENT_FLAG_PART 0x08 /* FRU Part Number supplied */ +#define PEL_FRU_IDENT_FLAG_CCIN 0x04 /* CCIN supplied */ +#define PEL_FRU_IDENT_FLAG_SERIAL 0x01 /* FRU serial number supplied */ #define PEL_CID_SAPPHIRE 'K' /* creator ID for sapphire log */ #define PEL_CID_POWERNV 'P' /* creator ID for powernv log */ @@ -129,6 +164,40 @@ struct pel_src_section { char srcstring[PEL_MAX_SRC_BYTES]; } __packed; +struct pel_src_sub_section { + uint8_t id; /* SRC sub section id */ + uint8_t flags; + uint16_t length; /* in # of words (4 byte fields) */ +}; + +struct pel_fru_callout_section { + struct pel_src_sub_section header; +}; + +struct pel_fru_callout { + uint8_t length; /* in bytes */ + /* First 4 bits are FRU callout type */ + /* Second 4 bits are the FRU callout flags */ + uint8_t type_flags; + uint8_t flags:4; + uint8_t priority; + uint8_t loc_code_len; + char loc_code[0]; +}; + +struct pel_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 pel_extended_header_section { struct pel_v6_header v6header; char model[PEL_SYS_MODEL_LEN];