discover/platform-powerpc: Set IPMI OS boot sensor
authorJoel Stanley <joel@jms.id.au>
Tue, 21 Apr 2015 06:17:57 +0000 (16:17 +1000)
committerJeremy Kerr <jk@ozlabs.org>
Thu, 23 Apr 2015 22:48:53 +0000 (17:48 -0500)
This is to indicate to a BMC that we have initiated OS boot.

This patch manually parses the device tree for the sensor information.
In the future this could be replaced by libfdt or similar.

Discover the id of your OS Boot sensor:

$ sudo ipmitool sensor get "OS Boot"
Locating sensor record...
Sensor ID              : OS Boot (0x5a)
 Entity ID             : 35.0 (Operating System)
 Sensor Type (Discrete): OS Boot (0x1f)
 Sensor Reading        : 0h
 Event Message Control : Per-threshold
 Assertion Events      : OS Boot
                         [boot completed - device not specified]
 Assertions Enabled    : OS Boot
                         [A: boot completed]
                         [C: boot completed]
                         [PXE boot completed]
                         [Diagnostic boot completed]
                         [CD-ROM boot completed]
                         [ROM boot completed]
                         [boot completed - device not specified]
                         [Installation started]
                         [Installation completed]
                         [Installation aborted]
                         [Installation failed]
 OEM                   : 0

In this case it is 0x1f. Note that the sesnor is currently asserted iwth boot
completed - device not specified.

Test by clearing all assertions in the OS Boot sensor:

$ sudo ipmitool raw 0x04 0x30 0x5a 0x30 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
$ sudo ipmitool sensor get "OS Boot"
Locating sensor record...
Sensor ID              : OS Boot (0x5a)
 Entity ID             : 35.0 (Operating System)
 Sensor Type (Discrete): OS Boot (0x1f)
 Sensor Reading        : 0h
 Event Message Control : Per-threshold
 Assertions Enabled    : OS Boot
                         [A: boot completed]
                         [C: boot completed]
                         [PXE boot completed]
                         [Diagnostic boot completed]
                         [CD-ROM boot completed]
                         [ROM boot completed]
                         [boot completed - device not specified]
                         [Installation started]
                         [Installation completed]
                         [Installation aborted]
                         [Installation failed]
 OEM                   : 0

Then reboot your system. The assertion event should once more say "boot
completed - device not specified".

Signed-off-by: Joel Stanley <joel@jms.id.au>
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
discover/Makefile.am
discover/dt.c [new file with mode: 0644]
discover/dt.h [new file with mode: 0644]
discover/ipmi.h
discover/platform-powerpc.c

index 1e4df0b19ca34d286dc6d5302b3f5f69bca261c5..7808110811cb00654f5605a51031235f780be568 100644 (file)
@@ -71,6 +71,8 @@ discover_platform_ro_SOURCES = \
        discover/platform.h \
        discover/ipmi.c \
        discover/ipmi.h \
+       discover/dt.c \
+       discover/dt.h \
        discover/platform-powerpc.c
 
 discover_platform_ro_LINK = \
diff --git a/discover/dt.c b/discover/dt.c
new file mode 100644 (file)
index 0000000..a7383e1
--- /dev/null
@@ -0,0 +1,61 @@
+#include <asm/byteorder.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <talloc/talloc.h>
+#include <file/file.h>
+
+#include "dt.h"
+
+static int filter_sensors(const struct dirent *ent)
+{
+       /* Check for prefix "sensor@" */
+       return strncmp(ent->d_name, "sensor@", strlen("sensor@")) == 0;
+}
+
+int get_ipmi_sensor(void *t, enum ipmi_sensor_ids sensor_id)
+{
+       int rc, len, n;
+       struct dirent **namelist;
+       char *buf, *filename;
+       const char sensor_dir[] = "/proc/device-tree/bmc/sensors/";
+
+       n = scandir(sensor_dir, &namelist, filter_sensors, alphasort);
+       if (n <= 0)
+               return -1;
+
+       while (n--) {
+               filename = talloc_asprintf(t, "%s%s/ipmi-sensor-type",
+                                          sensor_dir, namelist[n]->d_name);
+               rc = read_file(t, filename, &buf, &len);
+               if (rc == 0 && len == 4 &&
+                   __be32_to_cpu(*(uint32_t *)buf) == sensor_id)
+                               break;
+               free(namelist[n]);
+       }
+       if (n < 0) {
+               rc = -1;
+               goto out;
+       }
+
+       filename = talloc_asprintf(t, "%s%s/reg", sensor_dir,
+                                  namelist[n]->d_name);
+       /* Free the rest of the scandir strings, if there are any */
+       do {
+               free(namelist[n]);
+       } while (n-- > 0);
+
+       rc = read_file(t, filename, &buf, &len);
+       if (rc != 0 || len != 4) {
+               rc = -1;
+               goto out;
+       }
+
+       rc = __be32_to_cpu(*(uint32_t *)buf);
+
+out:
+       free(namelist);
+       return rc;
+}
diff --git a/discover/dt.h b/discover/dt.h
new file mode 100644 (file)
index 0000000..4692d04
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _DT_H
+#define _DT_H
+
+#include "ipmi.h"
+
+int get_ipmi_sensor(void *t, enum ipmi_sensor_ids sensor_id);
+
+#endif /* _IPMI_H */
index e60ff619215984c58da52293df3315ad9de773ce..83f29107e276ef5545d0288c4acf5f90eabb18bd 100644 (file)
@@ -5,12 +5,14 @@
 #include <stdint.h>
 
 enum ipmi_netfn {
-       IPMI_NETFN_CHASSIS = 0x0,
+       IPMI_NETFN_CHASSIS      = 0x0,
+       IPMI_NETFN_SE           = 0x04,
 };
 
 enum ipmi_cmd {
        IPMI_CMD_CHASSIS_SET_SYSTEM_BOOT_OPTIONS        = 0x08,
        IPMI_CMD_CHASSIS_GET_SYSTEM_BOOT_OPTIONS        = 0x09,
+       IPMI_CMD_SENSOR_SET                             = 0x30,
 };
 
 enum ipmi_bootdev {
@@ -22,6 +24,10 @@ enum ipmi_bootdev {
        IPMI_BOOTDEV_SETUP = 0x6,
 };
 
+enum ipmi_sensor_ids {
+       IPMI_SENSOR_ID_OS_BOOT          = 0x1F,
+};
+
 struct ipmi;
 
 bool ipmi_present(void);
index a293ce9dd5506a0c03d000e0c1ba55d8d8e2ff51..4cc91fa2594eeac6c2b939ee50c4dc0821fe433a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "platform.h"
 #include "ipmi.h"
+#include "dt.h"
 
 static const char *partition = "common";
 static const char *sysparams_dir = "/sys/firmware/opal/sysparams/";
@@ -39,6 +40,8 @@ struct platform_powerpc {
                                uint8_t *bootdev, bool *persistent);
        int             (*clear_ipmi_bootdev)(
                                struct platform_powerpc *platform);
+       int             (*set_os_boot_sensor)(
+                               struct platform_powerpc *platform);
 };
 
 static const char *known_params[] = {
@@ -792,6 +795,42 @@ static int get_ipmi_bootdev_ipmi(struct platform_powerpc *platform,
        return 0;
 }
 
+static int set_ipmi_os_boot_sensor(struct platform_powerpc *platform)
+{
+       int sensor_number;
+       uint16_t resp_len;
+       uint8_t resp[1];
+       uint8_t req[] = {
+               0x00, /* sensor number: os boot */
+               0x10, /* operation: set assertion bits */
+               0x00, /* sensor reading: none */
+               0x40, /* assertion mask lsb: set state 6 */
+               0x00, /* assertion mask msb: none */
+               0x00, /* deassertion mask lsb: none */
+               0x00, /* deassertion mask msb: none */
+               0x00, /* event data 1: none */
+               0x00, /* event data 2: none */
+               0x00, /* event data 3: none */
+       };
+
+       sensor_number = get_ipmi_sensor(platform, IPMI_SENSOR_ID_OS_BOOT);
+       if (sensor_number < 0) {
+               pb_log("Couldn't find OS boot sensor in device tree\n");
+               return -1;
+       }
+
+       req[0] = sensor_number;
+
+       resp_len = sizeof(resp);
+
+       ipmi_transaction(platform->ipmi, IPMI_NETFN_SE,
+                       IPMI_CMD_SENSOR_SET,
+                       req, sizeof(req),
+                       resp, &resp_len,
+                       ipmi_timeout); return 0;
+
+       return 0;
+}
 
 static int load_config(struct platform *p, struct config *config)
 {
@@ -838,6 +877,9 @@ static void pre_boot(struct platform *p, const struct config *config)
 
        if (!config->ipmi_bootdev_persistent && platform->clear_ipmi_bootdev)
                platform->clear_ipmi_bootdev(platform);
+
+       if (platform->set_os_boot_sensor)
+               platform->set_os_boot_sensor(platform);
 }
 
 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
@@ -875,7 +917,7 @@ static bool probe(struct platform *p, void *ctx)
        if (!S_ISDIR(statbuf.st_mode))
                return false;
 
-       platform = talloc(ctx, struct platform_powerpc);
+       platform = talloc_zero(ctx, struct platform_powerpc);
        list_init(&platform->params);
 
        p->platform_data = platform;
@@ -885,6 +927,7 @@ static bool probe(struct platform *p, void *ctx)
                platform->ipmi = ipmi_open(platform);
                platform->get_ipmi_bootdev = get_ipmi_bootdev_ipmi;
                platform->clear_ipmi_bootdev = clear_ipmi_bootdev_ipmi;
+               platform->set_os_boot_sensor = set_ipmi_os_boot_sensor;
 
        } else if (!stat(sysparams_dir, &statbuf)) {
                pb_debug("platform: using sysparams for IPMI paramters\n");