[Skiboot] [PATCH v3] IPMI: Fix eSEL logging

Vasant Hegde hegdevasant at linux.vnet.ibm.com
Mon Aug 10 15:22:13 AEST 2015


Presently we are passing PEL log without adding Extended SEL record.
Hence logging eSEL event is failing.

This patch sends Extended SEL structure before sending actual PEL log.
So that BMC understands its eSEL log and logs it appropriately.

eSEL format:
  <IPMI SEL header> : <eSEL record> : <PEL data>

Note that we use sensor type "System Event (0x12)" for logging OPAL
events.

Signed-off-by: Vasant Hegde <hegdevasant at linux.vnet.ibm.com>
Cc: Alistair Popple <alistair at popple.id.au>
Cc: Jeremy Kerr <jk at ozlabs.org>
---
 hw/ipmi/ipmi-sel.c    | 125 +++++++++++++++++++++++++++++++++++++++++++++-----
 hw/ipmi/ipmi-sensor.c |   5 ++
 include/ipmi.h        |   3 ++
 3 files changed, 121 insertions(+), 12 deletions(-)

diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index e672ecf..f03f19e 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -44,6 +44,74 @@
 #define RELEASE_PNOR		0x00
 #define REQUEST_PNOR		0x01
 
+/* 32.1 SEL Event Records type */
+#define SEL_REC_TYPE_SYS_EVENT	0x02
+#define SEL_REC_TYPE_AMI_ESEL	0xDF
+
+/* OEM SEL generator ID for AMI */
+#define SEL_GENERATOR_ID_AMI	0x2000
+
+/* IPMI SEL version */
+#define SEL_EVM_VER_1		0x03
+#define SEL_EVM_VER_2		0x04
+
+/*
+ * Sensor type for System events
+ *
+ * Sensor information (type, number, etc) is passed to us via
+ * device tree. Currently we are using System Event type to
+ * log OPAL events.
+ */
+#define SENSOR_TYPE_SYS_EVENT	0x12
+
+/*
+ * 42.1 Event/Reading Type Codes
+ *
+ * Note that device hotplug and availability related events
+ * are not defined as we are not using those events type.
+ */
+#define SEL_EVENT_DIR_TYPE_UNSPECIFIED	0x00
+#define SEL_EVENT_DIR_TYPE_THRESHOLD	0x01
+#define SEL_EVENT_DIR_TYPE_STATE	0x03
+#define SEL_EVENT_DIR_TYPE_PREDICTIVE	0x04
+#define SEL_EVENT_DIR_TYPE_LIMIT	0x05
+#define SEL_EVENT_DIR_TYPE_PERFORMANCE	0x06
+#define SEL_EVENT_DIR_TYPE_TRANSITION	0x07
+#define SEL_EVENT_DIR_TYPE_OEM		0x70
+
+/*
+ * 42.1 Event/Reading Type Codes
+ */
+#define SEL_DATA1_AMI			0xAA
+#define SEL_DATA1_DEASSERTED		0x00
+#define SEL_DATA1_ASSERTED		0x01
+#define SEL_DATA1_OK			0x00
+#define SEL_DATA1_NON_CRIT_FROM_OK	0x01
+#define SEL_DATA1_CRIT_FROM_LESS_SEV	0x02
+#define SEL_DATA1_NON_REC_FROM_LESS_SEV	0x03
+#define SEL_DATA1_NON_CRIT		0x04
+#define SEL_DATA1_CRITICAL		0x05
+#define SEL_DATA1_NON_RECOVERABLE	0X06
+#define SEL_DATA1_MONITOR		0x07
+#define SEL_DATA1_INFORMATIONAL		0x08
+
+/* SEL Record Entry */
+struct sel_record {
+	le16		record_id;
+	uint8_t		record_type;
+	le32		timestamp;
+	le16		generator_id;
+	uint8_t		evm_ver;
+	uint8_t		sensor_type;
+	uint8_t		sensor_number;
+	uint8_t		event_dir_type;
+	uint8_t		event_data1;
+	uint8_t		event_data2;
+	uint8_t		event_data3;
+} __packed;
+
+static struct sel_record sel_record;
+
 struct oem_sel {
 	/* SEL header */
 	uint8_t id[2];
@@ -65,6 +133,21 @@ struct oem_sel {
 
 #define ESEL_HDR_SIZE 7
 
+
+/* Initialize eSEL record */
+static void ipmi_init_esel_record(void)
+{
+	memset(&sel_record, 0, sizeof(struct sel_record));
+	sel_record.record_type = SEL_REC_TYPE_AMI_ESEL;
+	sel_record.generator_id = SEL_GENERATOR_ID_AMI;
+	sel_record.evm_ver = SEL_EVM_VER_2;
+	sel_record.sensor_type	= SENSOR_TYPE_SYS_EVENT;
+	sel_record.sensor_number =
+		ipmi_get_sensor_number(SENSOR_TYPE_SYS_EVENT);
+	sel_record.event_dir_type = SEL_EVENT_DIR_TYPE_OEM;
+	sel_record.event_data1 = SEL_DATA1_AMI;
+}
+
 static void ipmi_elog_error(struct ipmi_msg *msg)
 {
 	if (msg->cc == IPMI_LOST_ARBITRATION_ERR)
@@ -79,7 +162,8 @@ static void ipmi_elog_error(struct ipmi_msg *msg)
 /* Goes through the required steps to add a complete eSEL:
  *
  *  1. Get a reservation
- *  2. Partially add data to the SEL
+ *  2. Add eSEL header
+ *  3. Partially add data to the SEL
  *
  * Because a reservation is needed we need to ensure eSEL's are added
  * as a single transaction as concurrent/interleaved adds would cancel
@@ -96,15 +180,21 @@ static void ipmi_elog_error(struct ipmi_msg *msg)
  */
 static void ipmi_elog_poll(struct ipmi_msg *msg)
 {
+	static bool first = false;
 	static char pel_buf[MAX_PEL_SIZE];
 	static size_t pel_size;
-	static int index = 0;
+	static size_t esel_size;
+	static int esel_index = 0;
+	int pel_index;
 	static unsigned int reservation_id = 0;
 	static unsigned int record_id = 0;
 	struct errorlog *elog_buf = (struct errorlog *) msg->user_data;
 	size_t req_size;
 
+	ipmi_init_esel_record();
+
 	if (msg->cmd == IPMI_CMD(IPMI_RESERVE_SEL)) {
+		first = true;
 		reservation_id = msg->data[0];
 		reservation_id |= msg->data[1] << 8;
 		if (!reservation_id) {
@@ -118,7 +208,8 @@ static void ipmi_elog_poll(struct ipmi_msg *msg)
 		}
 
 		pel_size = create_pel_log(elog_buf, pel_buf, MAX_PEL_SIZE);
-		index = 0;
+		esel_size = pel_size + sizeof(struct sel_record);
+		esel_index = 0;
 		record_id = 0;
 	} else {
 		record_id = msg->data[0];
@@ -126,21 +217,21 @@ static void ipmi_elog_poll(struct ipmi_msg *msg)
 	}
 
 	/* Start or continue the IPMI_PARTIAL_ADD_SEL */
-	if (index >= pel_size) {
+	if (esel_index >= esel_size) {
 		/* We're all done. Invalidate the resevation id to
 		 * ensure we get an error if we cut in on another eSEL
 		 * message. */
 		reservation_id = 0;
-		index = 0;
+		esel_index = 0;
 		opal_elog_complete(elog_buf, true);
 		ipmi_free_msg(msg);
 		return;
 	}
 
-	if ((pel_size - index) < (IPMI_MAX_REQ_SIZE - ESEL_HDR_SIZE)) {
+	if ((esel_size - esel_index) < (IPMI_MAX_REQ_SIZE - ESEL_HDR_SIZE)) {
 		/* Last data to send */
 		msg->data[6] = 1;
-		req_size = pel_size - index + ESEL_HDR_SIZE;
+		req_size = esel_size - esel_index + ESEL_HDR_SIZE;
 	} else {
 		msg->data[6] = 0;
 		req_size = IPMI_MAX_REQ_SIZE;
@@ -153,11 +244,21 @@ static void ipmi_elog_poll(struct ipmi_msg *msg)
 	msg->data[1] = (reservation_id >> 8) & 0xff;
 	msg->data[2] = record_id & 0xff;
 	msg->data[3] = (record_id >> 8) & 0xff;
-	msg->data[4] = index & 0xff;
-	msg->data[5] = (index >> 8) & 0xff;
-
-	memcpy(&msg->data[ESEL_HDR_SIZE], &pel_buf[index], msg->req_size - ESEL_HDR_SIZE);
-	index += msg->req_size - ESEL_HDR_SIZE;
+	msg->data[4] = esel_index & 0xff;
+	msg->data[5] = (esel_index >> 8) & 0xff;
+
+	if (first) {
+		first = false;
+		memcpy(&msg->data[ESEL_HDR_SIZE],
+		       &sel_record, sizeof(struct sel_record));
+		esel_index = sizeof(struct sel_record);
+		msg->req_size = esel_index + ESEL_HDR_SIZE;
+	} else {
+		pel_index = esel_index - sizeof(struct sel_record);
+		memcpy(&msg->data[ESEL_HDR_SIZE],
+		       &pel_buf[pel_index], msg->req_size - ESEL_HDR_SIZE);
+		esel_index += msg->req_size - ESEL_HDR_SIZE;
+	}
 
 	ipmi_queue_msg_head(msg);
 	return;
diff --git a/hw/ipmi/ipmi-sensor.c b/hw/ipmi/ipmi-sensor.c
index d890534..c8723ae 100644
--- a/hw/ipmi/ipmi-sensor.c
+++ b/hw/ipmi/ipmi-sensor.c
@@ -36,6 +36,11 @@ struct set_sensor_req {
 	u8 event_data[3];
 };
 
+uint8_t ipmi_get_sensor_number(uint8_t sensor_type)
+{
+	return sensors[sensor_type];
+}
+
 int ipmi_set_boot_count(void)
 {
 	struct set_sensor_req req;
diff --git a/include/ipmi.h b/include/ipmi.h
index 3aaa041..f34fbbe 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -258,6 +258,9 @@ void ipmi_wdt_final_reset(void);
 /* Discover id of settable ipmi sensors */
 void ipmi_sensor_init(void);
 
+/* Get sensor number for given sensor type */
+uint8_t ipmi_get_sensor_number(uint8_t sensor_type);
+
 /* Set the boot count once the OS is up and running */
 int ipmi_set_boot_count(void);
 
-- 
2.1.0



More information about the Skiboot mailing list