diff mbox series

[V2,1/6] rasdaemon: CCIX: memory error support

Message ID 20190827113010.50405-2-Jonathan.Cameron@huawei.com (mailing list archive)
State Accepted
Headers show
Series CCIX rasdaemon support | expand

Commit Message

Jonathan Cameron Aug. 27, 2019, 11:30 a.m. UTC
Adds support for basic decoding and logging of ccix memory errors
+ storing to sqlite3 DB.

Given that the CCIX memory record is very tightly defined by the
specification and that databases with large blobs in them
are not particularly useful, I have separately exposed all of the
standard fields.  Note that this means setting them NULL if the
validation bits indicate that the field is not valid.

Includes making a few ras-record.c functions available from other
files to allow us to split off the CCIX error recording functionality.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 Makefile.am        |   8 +-
 configure.ac       |  10 ++
 ras-ccix-handler.c | 244 +++++++++++++++++++++++++++++++++++++++++++++
 ras-ccix-handler.h |  61 ++++++++++++
 ras-events.c       |  16 +++
 ras-record-ccix.c  | 204 +++++++++++++++++++++++++++++++++++++
 ras-record.c       |  15 ++-
 ras-record.h       |  28 ++++++
 ras-report.h       |   6 +-
 9 files changed, 585 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/Makefile.am b/Makefile.am
index 3d89672..9d54390 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,10 +20,16 @@  rasdaemon_SOURCES = rasdaemon.c ras-events.c ras-mc-handler.c \
 		    bitfield.c
 if WITH_SQLITE3
    rasdaemon_SOURCES += ras-record.c
+if WITH_CCIX
+   rasdaemon_SOURCES += ras-record-ccix.c
+endif
 endif
 if WITH_AER
    rasdaemon_SOURCES += ras-aer-handler.c
 endif
+if WITH_CCIX
+   rasdaemon_SOURCES += ras-ccix-handler.c
+endif
 if WITH_NON_STANDARD
    rasdaemon_SOURCES += ras-non-standard-handler.c
 endif
@@ -56,7 +62,7 @@  rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) libtrace/libtrace.a
 include_HEADERS = config.h  ras-events.h  ras-logger.h  ras-mc-handler.h \
 		  ras-aer-handler.h ras-mce-handler.h ras-record.h bitfield.h ras-report.h \
 		  ras-extlog-handler.h ras-arm-handler.h ras-non-standard-handler.h \
-		  ras-devlink-handler.h
+		  ras-devlink-handler.h ras-ccix-handler.h
 
 # This rule can't be called with more than one Makefile job (like make -j8)
 # I can't figure out a way to fix that
diff --git a/configure.ac b/configure.ac
index fecff51..ca8977c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,6 +44,15 @@  AS_IF([test "x$enable_aer" = "xyes"], [
 ])
 AM_CONDITIONAL([WITH_AER], [test x$enable_aer = xyes])
 
+AC_ARG_ENABLE([ccix],
+    AS_HELP_STRING([--enable-ccix], [enable CCIX PER events (currently experimental)]))
+
+AS_IF([test "x$enable_ccix" = "xyes"], [
+  AC_DEFINE(HAVE_CCIX,1,"have CCIX PER events collect")
+  AC_SUBST([WITH_CCIX])
+])
+AM_CONDITIONAL([WITH_CCIX], [test x$enable_ccix = xyes])
+
 AC_ARG_ENABLE([non_standard],
     AS_HELP_STRING([--enable-non-standard], [enable NON_STANDARD events (currently experimental)]))
 
@@ -137,4 +146,5 @@  compile time options summary
     HIP07 SAS HW errors : $enable_hisi_ns_decode
     ARM events          : $enable_arm
     DEVLINK             : $enable_devlink
+    CCIX                : $enable_ccix
 EOF
diff --git a/ras-ccix-handler.c b/ras-ccix-handler.c
new file mode 100644
index 0000000..2be413f
--- /dev/null
+++ b/ras-ccix-handler.c
@@ -0,0 +1,244 @@ 
+/*
+ * Copyright (c) 2019 Hisilicon Limited.
+ *
+ * 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 2 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.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "libtrace/kbuffer.h"
+#include "ras-record.h"
+#include "ras-logger.h"
+#include "bitfield.h"
+#include "ras-report.h"
+
+static char *ccix_mem_pool_type(uint8_t pt)
+{
+	switch (pt) {
+	case 0: return "other/not-specified";
+	case 1: return "ROM";
+	case 2: return "volatile";
+	case 3: return "non-volatile";
+	case 4: return "device/register";
+	}
+	if (pt >= 0x80)
+		return "vendor";
+	return "unknown";
+}
+
+static char *ccix_mem_spec_type(uint8_t st)
+{
+	switch (st) {
+	case 0: return "other/not-specified";
+	case 1: return "SRAM";
+	case 2: return "DDR";
+	case 3: return "NVDIMM-F";
+	case 4: return "NVDIMM-N";
+	case 5: return "HBM";
+	case 6: return "flash";
+	}
+	if (st >= 0x80)
+		return "vendor";
+	return "unknown";
+}
+
+static char *ccix_mem_op(uint8_t op)
+{
+	switch (op) {
+	case 0: return "generic";
+	case 1: return "read";
+	case 2: return "write";
+	case 4: return "scrub";
+	}
+	return "unknown";
+}
+
+static char *ccix_mem_err_type(int etype)
+{
+	switch (etype) {
+	case 0: return "unknown";
+	case 1: return "no error";
+	case 2: return "single-bit ECC";
+	case 3: return "multi-bit ECC";
+	case 4: return "single-symbol chipkill ECC";
+	case 5: return "multi-symbol chipkill ECC";
+	case 6: return "master abort";
+	case 7: return "target abort";
+	case 8: return "parity error";
+	case 9: return "watchdog timeout";
+	case 10: return "invalid address";
+	case 11: return "mirror Broken";
+	case 12: return "memory sparing";
+	case 13: return "scrub";
+	case 14: return "physical memory map-out event";
+	}
+	return "unknown-type";
+}
+
+static char *ccix_mem_err_cper_data(const char *c)
+{
+	const struct cper_ccix_mem_err_compact *cpd =
+		(struct cper_ccix_mem_err_compact *)c;
+	static char buf[1024];
+	char *p = buf;
+
+	p += sprintf(p, " (");
+	p += sprintf(p, "fru: %u ", cpd->fru);
+	if (cpd->validation_bits & CCIX_MEM_ERR_MEM_ERR_TYPE_VALID)
+		p += sprintf(p, "error: %s ",
+			     ccix_mem_err_type(cpd->mem_err_type));
+	if (cpd->validation_bits & CCIX_MEM_ERR_GENERIC_MEM_VALID)
+		p += sprintf(p, "type: %s ",
+			     ccix_mem_pool_type(cpd->pool_generic_type));
+	if (cpd->validation_bits & CCIX_MEM_ERR_SPEC_TYPE_VALID)
+		p += sprintf(p, "sub_type: %s ",
+			     ccix_mem_spec_type(cpd->pool_specific_type));
+	if (cpd->validation_bits & CCIX_MEM_ERR_OP_VALID)
+		p += sprintf(p, "op: %s ", ccix_mem_op(cpd->op_type));
+	if (cpd->validation_bits & CCIX_MEM_ERR_CARD_VALID)
+		p += sprintf(p, "card: %u ", cpd->card);
+	if (cpd->validation_bits & CCIX_MEM_ERR_MOD_VALID)
+		p += sprintf(p, "mod: %u ", cpd->module);
+	if (cpd->validation_bits & CCIX_MEM_ERR_BANK_VALID)
+		p += sprintf(p, "bank: %u ", cpd->bank);
+	if (cpd->validation_bits & CCIX_MEM_ERR_DEVICE_VALID)
+		p += sprintf(p, "device: %u ", cpd->device);
+	if (cpd->validation_bits & CCIX_MEM_ERR_ROW_VALID)
+		p += sprintf(p, "row: %u ", cpd->row);
+	if (cpd->validation_bits & CCIX_MEM_ERR_COL_VALID)
+		p += sprintf(p, "col: %u ", cpd->column);
+	if (cpd->validation_bits & CCIX_MEM_ERR_RANK_VALID)
+		p += sprintf(p, "rank: %u ", cpd->rank);
+	if (cpd->validation_bits & CCIX_MEM_ERR_BIT_POS_VALID)
+		p += sprintf(p, "bitpos: %u ", cpd->bit_pos);
+	if (cpd->validation_bits & CCIX_MEM_ERR_CHIP_ID_VALID)
+		p += sprintf(p, "chipid: %u ", cpd->chip_id);
+	p += sprintf(p - 1, ")");
+
+	return buf;
+}
+
+static char *ccix_component_type(int type)
+{
+	switch (type) {
+	case 0: return "RA";
+	case 1: return "HA";
+	case 2: return "SA";
+	case 3: return "Port";
+	case 4: return "CCIX-Link";
+	}
+	return "unknown-component";
+}
+
+static char *err_severity(int severity)
+{
+	switch (severity) {
+	case 0: return "recoverable";
+	case 1: return "fatal";
+	case 2: return "corrected";
+	case 3: return "informational";
+	}
+	return "unknown-severity";
+}
+
+static unsigned long long err_mask(int lsb)
+{
+	if (lsb == 0xff)
+		return ~0ull;
+	return ~((1ull << lsb) - 1);
+}
+
+static int ras_ccix_common_parse(struct trace_seq *s,
+				 struct pevent_record *record,
+				 struct event_format *event, void *context,
+				 struct ras_ccix_event *ev)
+{
+	unsigned long long val;
+	int len;
+
+	if (pevent_get_field_val(s,  event, "err_seq", record, &val, 1) < 0)
+		return -1;
+	ev->error_seq = val;
+	if (pevent_get_field_val(s,  event, "sev", record, &val, 1) < 0)
+		return -1;
+	ev->severity = val;
+	if (pevent_get_field_val(s, event, "sevdetail", record, &val, 1) < 0)
+		return -1;
+	ev->severity_detail = val;
+	if (pevent_get_field_val(s,  event, "pa", record, &val, 1) < 0)
+		return -1;
+	ev->address = val;
+	if (pevent_get_field_val(s,  event, "pa_mask_lsb", record, &val, 1) < 0)
+		return -1;
+	ev->pa_mask_lsb = val;
+	if (pevent_get_field_val(s, event, "source", record, &val, 1) < 0)
+		return -1;
+	ev->source = val;
+	if (pevent_get_field_val(s, event, "component", record, &val, 1) < 0)
+		return -1;
+	ev->component = val;
+
+	ev->cper_data = pevent_get_field_raw(s, event, "data", record, &len, 1);
+	ev->cper_data_length = len;
+
+	if (pevent_get_field_val(s, event, "vendor_data_length", record, &val,
+				 1))
+		return -1;
+	ev->vendor_data_length = val;
+
+	ev->vendor_data = pevent_get_field_raw(s, event, "vendor_data", record,
+					       &len, 1);
+
+	return 0;
+}
+
+int ras_ccix_memory_event_handler(struct trace_seq *s,
+				  struct pevent_record *record,
+				  struct event_format *event, void *context)
+{
+	struct ras_events *ras = context;
+	struct tm *tm;
+	struct ras_ccix_event ev;
+	time_t now;
+	int ret;
+
+	if (ras->use_uptime)
+		now = record->ts/user_hz + ras->uptime_diff;
+	else
+		now = time(NULL);
+
+	tm = localtime(&now);
+
+	if (tm)
+		strftime(ev.timestamp, sizeof(ev.timestamp),
+			 "%Y-%m-%d %H:%M:%S %z", tm);
+	trace_seq_printf(s, "%s ", ev.timestamp);
+
+	ret = ras_ccix_common_parse(s, record, event, context, &ev);
+	if (ret)
+		return ret;
+
+	trace_seq_printf(s, "%d %s id:%d CCIX memory error %s ue:%d nocomm:%d degraded:%d deferred:%d physical addr: 0x%llx mask: 0x%llx %s",
+			 ev.error_seq, err_severity(ev.severity),
+			 ev.source, ccix_component_type(ev.component),
+			 (ev.severity_detail & 0x1) ? 1 : 0,
+			 (ev.severity_detail & 0x2) ? 1 : 0,
+			 (ev.severity_detail & 0x4) ? 1 : 0,
+			 (ev.severity_detail & 0x8) ? 1 : 0,
+			 ev.address,
+			 err_mask(ev.pa_mask_lsb),
+			 ccix_mem_err_cper_data(ev.cper_data));
+
+	ras_store_ccix_memory_event(ras, &ev);
+
+	return 0;
+}
diff --git a/ras-ccix-handler.h b/ras-ccix-handler.h
new file mode 100644
index 0000000..f6d25b1
--- /dev/null
+++ b/ras-ccix-handler.h
@@ -0,0 +1,61 @@ 
+/*
+ * Copyright (c) 2019 Hisilicon Limited.
+ *
+ * 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 2 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.
+ */
+
+#ifndef __RAS_CCIX_HANDLER_H
+#define __RAS_CCIX_HANDLER_H
+
+#include "ras-events.h"
+#include "libtrace/event-parse.h"
+
+int ras_ccix_memory_event_handler(struct trace_seq *s,
+				  struct pevent_record *record,
+				  struct event_format *event, void *context);
+
+/* Perhaps unnecessary paranoia, but the tracepoint structure is packed */
+#pragma pack(1)
+struct cper_ccix_mem_err_compact {
+	uint32_t validation_bits;
+	uint8_t mem_err_type;
+	uint8_t pool_generic_type;
+	uint8_t pool_specific_type;
+	uint8_t op_type;
+	uint8_t card;
+	uint16_t module;
+	uint16_t bank;
+	uint32_t device;
+	uint32_t row;
+	uint32_t column;
+	uint32_t rank;
+	uint8_t bit_pos;
+	uint8_t chip_id;
+	uint8_t fru;
+};
+#pragma pack()
+
+#define CCIX_MEM_ERR_GENERIC_MEM_VALID		0x0001
+#define CCIX_MEM_ERR_OP_VALID			0x0002
+#define CCIX_MEM_ERR_MEM_ERR_TYPE_VALID		0x0004
+#define CCIX_MEM_ERR_CARD_VALID			0x0008
+#define CCIX_MEM_ERR_BANK_VALID			0x0010
+#define CCIX_MEM_ERR_DEVICE_VALID		0x0020
+#define CCIX_MEM_ERR_ROW_VALID			0x0040
+#define CCIX_MEM_ERR_COL_VALID			0x0080
+#define CCIX_MEM_ERR_RANK_VALID			0x0100
+#define CCIX_MEM_ERR_BIT_POS_VALID		0x0200
+#define CCIX_MEM_ERR_CHIP_ID_VALID		0x0400
+#define CCIX_MEM_ERR_VENDOR_DATA_VALID		0x0800
+#define CCIX_MEM_ERR_MOD_VALID			0x1000
+#define CCIX_MEM_ERR_SPEC_TYPE_VALID		0x2000
+
+#endif
diff --git a/ras-events.c b/ras-events.c
index 6ba7a6a..e365d97 100644
--- a/ras-events.c
+++ b/ras-events.c
@@ -29,6 +29,7 @@ 
 #include "libtrace/event-parse.h"
 #include "ras-mc-handler.h"
 #include "ras-aer-handler.h"
+#include "ras-ccix-handler.h"
 #include "ras-non-standard-handler.h"
 #include "ras-arm-handler.h"
 #include "ras-mce-handler.h"
@@ -203,6 +204,10 @@  int toggle_ras_mc_event(int enable)
 	rc |= __toggle_ras_mc_event(ras, "ras", "aer_event", enable);
 #endif
 
+#ifdef HAVE_CCIX
+	rc |= __toggle_ras_mc_event(ras, "ras", "ccix_memory_event", enable);
+#endif
+
 #ifdef HAVE_MCE
 	rc |= __toggle_ras_mc_event(ras, "mce", "mce_record", enable);
 #endif
@@ -717,6 +722,17 @@  int handle_ras_events(int record_events)
 		    "ras", "aer_event");
 #endif
 
+#ifdef HAVE_CCIX
+	rc = add_event_handler(ras, pevent, page_size, "ras",
+			       "ccix_memory_error_event",
+			       ras_ccix_memory_event_handler, NULL);
+	if (!rc)
+		num_events++;
+	else
+		log(ALL, LOG_ERR, "Can't get traces from %s:%s\n",
+		    "ras", "ccix_memory_event");
+#endif
+
 #ifdef HAVE_NON_STANDARD
         rc = add_event_handler(ras, pevent, page_size, "ras", "non_standard_event",
                                ras_non_standard_event_handler, NULL);
diff --git a/ras-record-ccix.c b/ras-record-ccix.c
new file mode 100644
index 0000000..6e46b40
--- /dev/null
+++ b/ras-record-ccix.c
@@ -0,0 +1,204 @@ 
+/*
+ * Copyright (C) 2019 Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "bitfield.h"
+#include "ras-ccix-handler.h"
+#include "ras-logger.h"
+#include "ras-record.h"
+#include "ras-report.h"
+
+enum {
+	ccix_field_id,
+	ccix_field_timestamp,
+	ccix_field_error_count,
+	ccix_field_severity,
+	ccix_field_severity_detail,
+	ccix_field_address,
+	ccix_field_address_mask,
+	ccix_field_source,
+	ccix_field_component,
+	ccix_field_common_end
+};
+
+#define CCIX_COMMON_FIELDS \
+	[ccix_field_id] =		{ .name = "id",			.type = "INTEGER PRIMARY KEY" }, \
+	[ccix_field_timestamp] =	{ .name = "timestamp",		.type = "TEXT" },	\
+	[ccix_field_error_count] =	{ .name = "error_count",	.type = "INTEGER" }, \
+	[ccix_field_severity] =		{ .name = "severity",		.type = "INTEGER" }, \
+	[ccix_field_severity_detail] =	{ .name = "severity_detail",	.type = "INTEGER" }, \
+	[ccix_field_address] =		{ .name = "address",		.type = "INTEGER" }, \
+	[ccix_field_address_mask] =	{ .name = "address_mask",	.type = "INTEGER" }, \
+	[ccix_field_source] =		{ .name = "source",		.type = "INTEGER" }, \
+	[ccix_field_component] =	{ .name = "component",		.type = "INTEGER" }
+
+enum {
+	ccix_mem_field_error_type = ccix_field_common_end,
+	ccix_mem_field_fru,
+	ccix_mem_field_type,
+	ccix_mem_field_sub_type,
+	ccix_mem_field_operation,
+	ccix_mem_field_card,
+	ccix_mem_field_mod,
+	ccix_mem_field_bank,
+	ccix_mem_field_device,
+	ccix_mem_field_row,
+	ccix_mem_field_col,
+	ccix_mem_field_rank,
+	ccix_mem_field_bit_pos,
+	ccix_mem_field_chip_id,
+	ccix_mem_field_vendor
+};
+
+static const struct db_fields ccix_memory_event_fields[] = {
+	CCIX_COMMON_FIELDS,
+	[ccix_mem_field_error_type] =	{ .name = "mem_err_type",	.type = "INTEGER" },
+	[ccix_mem_field_fru] =		{ .name = "fru",		.type = "INTEGER" },
+	[ccix_mem_field_type] =		{ .name = "type",		.type = "INTEGER" },
+	[ccix_mem_field_sub_type] =	{ .name = "sub_type",		.type = "INTEGER" },
+	[ccix_mem_field_operation] =	{ .name = "operation",		.type = "INTEGER" },
+	[ccix_mem_field_card] =		{ .name = "card",		.type = "INTEGER" },
+	[ccix_mem_field_mod] =		{ .name = "mod",		.type = "INTEGER" },
+	[ccix_mem_field_bank] =		{ .name = "bank",		.type = "INTEGER" },
+	[ccix_mem_field_device] =	{ .name = "device",		.type = "INTEGER" },
+	[ccix_mem_field_row] =		{ .name = "row",		.type = "INTEGER" },
+	[ccix_mem_field_col] =		{ .name = "col",		.type = "INTEGER" },
+	[ccix_mem_field_rank] =		{ .name = "rank",		.type = "INTEGER" },
+	[ccix_mem_field_bit_pos] =	{ .name = "bit_position",	.type = "INTEGER" },
+	[ccix_mem_field_chip_id] =	{ .name = "chip_id",		.type = "INTEGER" },
+	[ccix_mem_field_vendor] =	{ .name = "vendor_data",	.type = "BLOB" },
+};
+
+static const struct db_table_descriptor ccix_memory_event_tab = {
+	.name = "ccix_memory_event",
+	.fields = ccix_memory_event_fields,
+	.num_fields = ARRAY_SIZE(ccix_memory_event_fields),
+};
+
+static void ras_store_ccix_common(sqlite3_stmt *record,
+				  struct ras_ccix_event *ev)
+{
+	sqlite3_bind_text(record, ccix_field_timestamp, ev->timestamp, -1,
+			  NULL);
+	sqlite3_bind_int(record, ccix_field_error_count, ev->error_seq);
+	sqlite3_bind_int(record, ccix_field_severity, ev->severity);
+	sqlite3_bind_int(record, ccix_field_severity_detail,
+			 ev->severity_detail);
+	sqlite3_bind_int64(record, ccix_field_address, ev->address);
+	sqlite3_bind_int64(record, ccix_field_address_mask, ev->pa_mask_lsb);
+	sqlite3_bind_int(record, ccix_field_source, ev->source);
+	sqlite3_bind_int(record, ccix_field_component, ev->component);
+}
+
+int ras_store_ccix_memory_event(struct ras_events *ras,
+				struct ras_ccix_event *ev)
+{
+	int rc;
+	struct sqlite3_priv *priv = ras->db_priv;
+	struct cper_ccix_mem_err_compact *mem =
+	  (struct cper_ccix_mem_err_compact *)ev->cper_data;
+	sqlite3_stmt *rec = priv->stmt_ccix_mem_record;
+
+	if (!priv || !rec)
+		return 0;
+	log(TERM, LOG_INFO, "ccix_memory_eventstore: %p\n", rec);
+
+	ras_store_ccix_common(rec, ev);
+
+	sqlite3_bind_int(rec, ccix_mem_field_fru, mem->fru);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_MEM_ERR_TYPE_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_error_type,
+				 mem->mem_err_type);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_GENERIC_MEM_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_type,
+				 mem->pool_generic_type);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_SPEC_TYPE_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_sub_type,
+				 mem->pool_specific_type);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_OP_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_operation, mem->op_type);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_CARD_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_card, mem->card);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_MOD_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_mod, mem->module);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_BANK_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_bank, mem->bank);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_DEVICE_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_device, mem->device);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_ROW_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_row, mem->row);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_COL_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_col, mem->column);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_RANK_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_rank, mem->rank);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_BIT_POS_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_bit_pos, mem->bit_pos);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_CHIP_ID_VALID)
+		sqlite3_bind_int(rec, ccix_mem_field_chip_id, mem->chip_id);
+
+	if (mem->validation_bits & CCIX_MEM_ERR_VENDOR_DATA_VALID)
+		sqlite3_bind_blob(rec, ccix_mem_field_vendor,
+				  ev->vendor_data, ev->vendor_data_length,
+				  NULL);
+
+	rc = sqlite3_step(rec);
+	if (rc != SQLITE_OK && rc != SQLITE_DONE)
+		log(TERM, LOG_ERR,
+		    "Failed to do ccix_mem_record step on sqlite: error = %d\n",
+		    rc);
+
+	rc = sqlite3_reset(rec);
+	if (rc != SQLITE_OK && rc != SQLITE_DONE)
+		log(TERM, LOG_ERR,
+		    "Failed reset ccix_mem_record on sqlite: error = %d\n",
+		    rc);
+
+	rc = sqlite3_clear_bindings(rec);
+	if (rc != SQLITE_OK && rc != SQLITE_DONE)
+		log(TERM, LOG_ERR,
+		    "Failed to clear ccix_mem_record: error %d\n",
+		    rc);
+	log(TERM, LOG_INFO, "register inserted at db\n");
+	return rc;
+}
+
+void ras_ccix_create_table(struct sqlite3_priv *priv)
+{
+	int rc;
+
+	rc = ras_mc_create_table(priv, &ccix_memory_event_tab);
+	if (rc == SQLITE_OK)
+		rc = ras_mc_prepare_stmt(priv, &priv->stmt_ccix_mem_record,
+					 &ccix_memory_event_tab);
+}
diff --git a/ras-record.c b/ras-record.c
index b212607..874902c 100644
--- a/ras-record.c
+++ b/ras-record.c
@@ -28,6 +28,7 @@ 
 #include "ras-events.h"
 #include "ras-mc-handler.h"
 #include "ras-aer-handler.h"
+#include "ras-ccix-handler.h"
 #include "ras-mce-handler.h"
 #include "ras-logger.h"
 
@@ -449,9 +450,9 @@  int ras_store_devlink_event(struct ras_events *ras, struct devlink_event *ev)
  * Generic code
  */
 
-static int ras_mc_prepare_stmt(struct sqlite3_priv *priv,
-			       sqlite3_stmt **stmt,
-			       const struct db_table_descriptor *db_tab)
+int ras_mc_prepare_stmt(struct sqlite3_priv *priv,
+			sqlite3_stmt **stmt,
+			const struct db_table_descriptor *db_tab)
 
 {
 	int i, rc;
@@ -495,8 +496,8 @@  static int ras_mc_prepare_stmt(struct sqlite3_priv *priv,
 	return rc;
 }
 
-static int ras_mc_create_table(struct sqlite3_priv *priv,
-			       const struct db_table_descriptor *db_tab)
+int ras_mc_create_table(struct sqlite3_priv *priv,
+			const struct db_table_descriptor *db_tab)
 {
 	const struct db_fields *field;
 	char sql[1024], *p = sql, *end = sql + sizeof(sql);
@@ -604,6 +605,10 @@  int ras_mc_event_opendb(unsigned cpu, struct ras_events *ras)
 					 &extlog_event_tab);
 #endif
 
+#ifdef HAVE_CCIX
+	ras_ccix_create_table(priv);
+#endif
+
 #ifdef HAVE_MCE
 	rc = ras_mc_create_table(priv, &mce_record_tab);
 	if (rc == SQLITE_OK)
diff --git a/ras-record.h b/ras-record.h
index 432a571..c094c91 100644
--- a/ras-record.h
+++ b/ras-record.h
@@ -44,6 +44,21 @@  struct ras_aer_event {
 	const char *msg;
 };
 
+struct ras_ccix_event {
+	char timestamp[64];
+	int32_t error_seq;
+	int8_t severity;
+	int8_t severity_detail;
+	unsigned long long address;
+	int8_t pa_mask_lsb;
+	uint8_t source;
+	uint8_t component;
+	const char *cper_data;
+	unsigned short cper_data_length;
+	uint16_t vendor_data_length;
+	const char *vendor_data;
+};
+
 struct ras_extlog_event {
 	char timestamp[64];
 	int32_t error_seq;
@@ -108,6 +123,9 @@  struct sqlite3_priv {
 #ifdef HAVE_EXTLOG
 	sqlite3_stmt	*stmt_extlog_record;
 #endif
+#ifdef HAVE_CCIX
+	sqlite3_stmt	*stmt_ccix_mem_record;
+#endif
 #ifdef HAVE_NON_STANDARD
 	sqlite3_stmt	*stmt_non_standard_record;
 #endif
@@ -131,12 +149,20 @@  struct db_table_descriptor {
 };
 
 int ras_mc_event_opendb(unsigned cpu, struct ras_events *ras);
+int ras_mc_prepare_stmt(struct sqlite3_priv *priv,
+			sqlite3_stmt **stmt,
+			const struct db_table_descriptor *db_tab);
+int ras_mc_create_table(struct sqlite3_priv *priv,
+			const struct db_table_descriptor *db_tab);
+
 int ras_mc_add_vendor_table(struct ras_events *ras, sqlite3_stmt **stmt,
 			    const struct db_table_descriptor *db_tab);
 int ras_store_mc_event(struct ras_events *ras, struct ras_mc_event *ev);
 int ras_store_aer_event(struct ras_events *ras, struct ras_aer_event *ev);
 int ras_store_mce_record(struct ras_events *ras, struct mce_event *ev);
 int ras_store_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev);
+void ras_ccix_create_table(struct sqlite3_priv *priv);
+int ras_store_ccix_memory_event(struct ras_events *ras, struct ras_ccix_event *ev);
 int ras_store_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev);
 int ras_store_arm_record(struct ras_events *ras, struct ras_arm_event *ev);
 int ras_store_devlink_event(struct ras_events *ras, struct devlink_event *ev);
@@ -147,6 +173,8 @@  static inline int ras_store_mc_event(struct ras_events *ras, struct ras_mc_event
 static inline int ras_store_aer_event(struct ras_events *ras, struct ras_aer_event *ev) { return 0; };
 static inline int ras_store_mce_record(struct ras_events *ras, struct mce_event *ev) { return 0; };
 static inline int ras_store_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev) { return 0; };
+static inline void ras_ccix_create_table(void *priv) {};
+static inline int ras_store_ccix_memory_event(struct ras_events *ras, struct ras_ccix_event *ev) { return 0; };
 static inline int ras_store_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev) { return 0; };
 static inline int ras_store_arm_record(struct ras_events *ras, struct ras_arm_event *ev) { return 0; };
 static inline int ras_store_devlink_event(struct ras_events *ras, struct devlink_event *ev) { return 0; };
diff --git a/ras-report.h b/ras-report.h
index cb133a1..4684fdc 100644
--- a/ras-report.h
+++ b/ras-report.h
@@ -19,6 +19,7 @@ 
 #include "ras-mc-handler.h"
 #include "ras-mce-handler.h"
 #include "ras-aer-handler.h"
+#include "ras-ccix-handler.h"
 
 /* Maximal length of backtrace. */
 #define MAX_BACKTRACE_SIZE (1024*1024)
@@ -35,7 +36,8 @@  enum {
 	AER_EVENT,
 	NON_STANDARD_EVENT,
 	ARM_EVENT,
-	DEVLINK_EVENT
+	DEVLINK_EVENT,
+	CCIX_EVENT,
 };
 
 #ifdef HAVE_ABRT_REPORT
@@ -46,6 +48,7 @@  int ras_report_mce_event(struct ras_events *ras, struct mce_event *ev);
 int ras_report_non_standard_event(struct ras_events *ras, struct ras_non_standard_event *ev);
 int ras_report_arm_event(struct ras_events *ras, struct ras_arm_event *ev);
 int ras_report_devlink_event(struct ras_events *ras, struct devlink_event *ev);
+int ras_report_ccix_event(struct ras_events *ras, struct ras_ccix_event *ev);
 
 #else
 
@@ -55,6 +58,7 @@  static inline int ras_report_mce_event(struct ras_events *ras, struct mce_event
 static inline int ras_report_non_standard_event(struct ras_events *ras, struct ras_non_standard_event *ev) { return 0; };
 static inline int ras_report_arm_event(struct ras_events *ras, struct ras_arm_event *ev) { return 0; };
 static inline int ras_report_devlink_event(struct ras_events *ras, struct devlink_event *ev) { return 0; };
+static inline int ras_report_ccix_event(struct ras_events *ras, struct ras_ccix_event *ev) { return 0; };
 
 #endif