diff mbox

[3/5] ipmi: Implement Read Event and SEL parsing

Message ID 1422577911-18394-4-git-send-email-joel@jms.id.au
State Changes Requested
Headers show

Commit Message

Joel Stanley Jan. 30, 2015, 12:31 a.m. UTC
The read event mechanism is used when the BMC has an asynchronous message
for the host. It sets a flag that we read with Get Message Flags, and then
we read the message using Read Event. This event message contains a SEL
message. There are two OEM SEL messages we expect from the AMI BMC:

 - graceful power operations. This is when the BMC wants the host to
   power down or reboot.

 - PNOR Locking. When the BMC wants to access the PNOR, it requests
   that the host not touch it.

This patch implements the parsing.

Signed-off-by: Joel Stanley <joel@jms.id.au>
---
 core/ipmi.c        |  3 +-
 hw/ipmi/ipmi-sel.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/ipmi.h     |  3 ++
 3 files changed, 89 insertions(+), 1 deletion(-)

Comments

Stewart Smith Feb. 4, 2015, 5:14 a.m. UTC | #1
Joel Stanley <joel@jms.id.au> writes:
> +	default:
> +		printf("IPMI: unknown OEM SEL command %02x received\n",
> +		       sel.cmd);
> +	}

Maybe PR_WARNING ?
Stewart Smith Feb. 4, 2015, 5:25 a.m. UTC | #2
Joel Stanley <joel@jms.id.au> writes:
> The read event mechanism is used when the BMC has an asynchronous message
> for the host. It sets a flag that we read with Get Message Flags, and then
> we read the message using Read Event. This event message contains a SEL
> message. There are two OEM SEL messages we expect from the AMI BMC:
>
>  - graceful power operations. This is when the BMC wants the host to
>    power down or reboot.
>
>  - PNOR Locking. When the BMC wants to access the PNOR, it requests
>    that the host not touch it.
>

My concern is that here we start to leak some OEM/AMI specific IPMI
things into "standard" IPMI code parts rather than tucked somewhere safe
for AMI specific things.
Joel Stanley Feb. 4, 2015, 5:52 a.m. UTC | #3
On Wed, Feb 4, 2015 at 3:44 PM, Stewart Smith
<stewart@linux.vnet.ibm.com> wrote:
> Joel Stanley <joel@jms.id.au> writes:
>> +     default:
>> +             printf("IPMI: unknown OEM SEL command %02x received\n",
>> +                    sel.cmd);
>> +     }
>
> Maybe PR_WARNING ?
>

Done, thanks
Joel Stanley Feb. 4, 2015, 5:54 a.m. UTC | #4
On Wed, Feb 4, 2015 at 3:55 PM, Stewart Smith
<stewart@linux.vnet.ibm.com> wrote:
> My concern is that here we start to leak some OEM/AMI specific IPMI
> things into "standard" IPMI code parts rather than tucked somewhere safe
> for AMI specific things.

We've called a truce for now; we'll keep using hw/ipmi until we have
another IPMI device to talk to.
diff mbox

Patch

diff --git a/core/ipmi.c b/core/ipmi.c
index 35bfead..b5ada0e 100644
--- a/core/ipmi.c
+++ b/core/ipmi.c
@@ -108,7 +108,8 @@  static void ipmi_read_event_complete(struct ipmi_msg *msg)
 	prlog(PR_DEBUG, "IPMI read event %02x complete: %d bytes. cc: %02x\n",
 	      msg->cmd, msg->resp_size, msg->cc);
 
-	/* TODO: Handle power control & PNOR handshake events */
+	/* Handle power control & PNOR handshake events */
+	ipmi_parse_sel(msg);
 
 	ipmi_free_msg(msg);
 }
diff --git a/hw/ipmi/ipmi-sel.c b/hw/ipmi/ipmi-sel.c
index d6f7f47..301e559 100644
--- a/hw/ipmi/ipmi-sel.c
+++ b/hw/ipmi/ipmi-sel.c
@@ -22,6 +22,33 @@ 
 #include <errorlog.h>
 #include <pel.h>
 
+/* OEM SEL fields */
+#define SEL_OEM_ID_0		0x55
+#define SEL_OEM_ID_1		0x55
+#define SEL_RECORD_TYPE_OEM	0xC0
+#define SEL_RECORD_TYPE_EVENT	0x02
+#define SEL_MANUF_0		0x8E
+#define SEL_MANUF_1		0xCB
+#define SEL_MANUF_2		0xC8
+
+#define SEL_NETFN_IBM		0x3a
+
+/* OEM SEL Commands */
+#define CMD_AMI_POWER		0x04
+#define CMD_AMI_PNOR_ACCESS	0x07
+
+struct oem_sel {
+	/* SEL header */
+	uint8_t id[2];
+	uint8_t type;
+	uint8_t manuf_id[3];
+	uint8_t timestamp[4];
+	/* OEM SEL data (6 bytes) follows */
+	uint8_t netfun;
+	uint8_t cmd;
+	uint8_t data[4];
+};
+
 /* As far as I can tell the size of PEL record is unbounded (due to
  * the possible presence of the user defined section). We chose this
  * size because it's what FSP uses, but we could probably reduce
@@ -148,3 +175,60 @@  int ipmi_elog_commit(struct errorlog *elog_buf)
 
 	return 0;
 }
+
+static void dump_sel(struct oem_sel *sel)
+{
+	const int level = PR_DEBUG;
+
+	prlog(level, "\tid %02x%02x\n", sel->id[0], sel->id[1]);
+	prlog(level, "\ttype %02x\n", sel->type);
+	prlog(level, "\tmanuf %02x %02x %02x\n",
+	      sel->manuf_id[0], sel->manuf_id[1], sel->manuf_id[2]);
+	prlog(level, "\ttime %02x %02x %02x %02x\n",
+	      sel->timestamp[0], sel->timestamp[1],
+	      sel->timestamp[2], sel->timestamp[3]);
+	prlog(level, "\tnetfun %02x\n", sel->netfun);
+	prlog(level, "\tcmd %02x\n", sel->cmd);
+	prlog(level, "\tdata %02x %02x %02x %02x\n", sel->data[0],
+	      sel->data[1], sel->data[2], sel->data[3]);
+}
+
+void ipmi_parse_sel(struct ipmi_msg *msg)
+{
+	struct oem_sel sel;
+
+	prlog(PR_INFO, "SEL received (size: %d)\n", msg->resp_size);
+	assert(msg->resp_size <= 16);
+
+	memcpy(&sel, msg->data, msg->resp_size);
+
+	dump_sel(&sel);
+
+	/* We do not process system event records */
+	if (sel.type == SEL_RECORD_TYPE_EVENT) {
+		prlog(PR_INFO, "IPMI: dropping System Event Record SEL\n");
+		return;
+	}
+
+	/* Only accept OEM SEL messages */
+	if (sel.id[0] != SEL_OEM_ID_0 ||
+	    sel.id[1] != SEL_OEM_ID_1 ||
+	    sel.type != SEL_RECORD_TYPE_OEM ||
+	    sel.manuf_id[0] != SEL_MANUF_0 ||
+	    sel.manuf_id[1] != SEL_MANUF_1 ||
+	    sel.manuf_id[2] != SEL_MANUF_2) {
+		prlog(PR_WARNING, "IPMI: unknown SEL %02x%02x (type %02x)\n",
+		      sel.id[0], sel.id[1], sel.type);
+		return;
+	}
+
+	switch (sel.cmd) {
+	case CMD_AMI_POWER:
+		break;
+	case CMD_AMI_PNOR_ACCESS:
+		break;
+	default:
+		printf("IPMI: unknown OEM SEL command %02x received\n",
+		       sel.cmd);
+	}
+}
diff --git a/include/ipmi.h b/include/ipmi.h
index 048e6cf..c1f0493 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -213,4 +213,7 @@  void ipmi_fru_init(uint8_t fru_dev_id);
 struct errorlog;
 int ipmi_elog_commit(struct errorlog *elog_buf);
 
+/* Callback to parse an OEM SEL message */
+void ipmi_parse_sel(struct ipmi_msg *msg);
+
 #endif