diff options
author | Samuel Mendoza-Jonas <sam@mendozajonas.com> | 2019-05-09 13:08:40 +1000 |
---|---|---|
committer | Oliver O'Halloran <oohall@gmail.com> | 2019-05-09 15:06:39 +1000 |
commit | 1bc63b896405ccea4584d764a28d01858e81efc3 (patch) | |
tree | 8cae38af94a430224e8c2fbff5afc40f7cc5c63f /hw/ipmi | |
parent | bc2b1de3beb2ee7904d936b10c8a57cd220d8ddc (diff) | |
download | skiboot-1bc63b896405ccea4584d764a28d01858e81efc3.zip skiboot-1bc63b896405ccea4584d764a28d01858e81efc3.tar.gz skiboot-1bc63b896405ccea4584d764a28d01858e81efc3.tar.bz2 |
platforms/astbmc: Check for SBE validation step
On some POWER8 astbmc systems an update to the SBE requires pausing at
runtime to ensure integrity of the SBE. If this is required the BMC will
set a chassis boot option IPMI flag using the OEM parameter 0x62. If
Skiboot sees this flag is set it waits until the SBE update is complete
and the flag is cleared.
Unfortunately the mystery operation that validates the SBE also leaves
it in a bad state and unable to be used for timer operations. To
workaround this the flag is checked as soon as possible (ie. when IPMI
and the console are set up), and once complete the system is rebooted.
Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
Reviewed-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com>
Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Diffstat (limited to 'hw/ipmi')
-rw-r--r-- | hw/ipmi/ipmi-info.c | 109 |
1 files changed, 106 insertions, 3 deletions
diff --git a/hw/ipmi/ipmi-info.c b/hw/ipmi/ipmi-info.c index 5637003..be2bd44 100644 --- a/hw/ipmi/ipmi-info.c +++ b/hw/ipmi/ipmi-info.c @@ -23,7 +23,7 @@ #include <timebase.h> /* - * Respones data from IPMI Get device ID command (As defined in + * Response data from IPMI Get device ID command (As defined in * Section 20.1 Get Device ID Command - IPMI standard spec). */ struct ipmi_dev_id { @@ -39,9 +39,27 @@ struct ipmi_dev_id { }; static struct ipmi_dev_id *ipmi_dev_id; +/* + * Response data from IPMI Chassis Get System Boot Option (As defined in + * Section 28.13 Get System Boot Options Command - IPMI standard spec). + */ +struct ipmi_sys_boot_opt { + uint8_t param_version; + uint8_t param_valid; + /* + * Fields for OEM parameter 0x62. This parameter does not follow + * the normal layout and just has a single byte to signal if it + * is active or not. + */ + uint8_t flag_set; +}; +static struct ipmi_sys_boot_opt *ipmi_sys_boot_opt; + /* Got response from BMC? */ static bool bmc_info_waiting = false; static bool bmc_info_valid = false; +static bool bmc_boot_opt_waiting = false; +static bool bmc_boot_opt_valid = false; /* This will free ipmi_dev_id structure */ void ipmi_dt_add_bmc_info(void) @@ -79,8 +97,14 @@ static void ipmi_get_bmc_info_resp(struct ipmi_msg *msg) return; } - bmc_info_valid = true; - memcpy(ipmi_dev_id, msg->data, msg->resp_size); + /* ipmi_dev_id has optional fields */ + if (msg->resp_size <= sizeof(struct ipmi_dev_id)) { + bmc_info_valid = true; + memcpy(ipmi_dev_id, msg->data, msg->resp_size); + } else { + prlog(PR_WARNING, "IPMI: IPMI_BMC_GET_DEVICE_ID unexpected response size\n"); + } + ipmi_free_msg(msg); } @@ -110,3 +134,82 @@ int ipmi_get_bmc_info_request(void) bmc_info_waiting = true; return rc; } + +/* This will free ipmi_sys_boot_opt structure */ +int ipmi_chassis_check_sbe_validation(void) +{ + int rc = -1; + + while (bmc_boot_opt_waiting) + time_wait_ms(10); + + if (!bmc_boot_opt_valid) + goto out; + + if ((ipmi_sys_boot_opt->param_valid & 0x8) != 0) + goto out; + if (ipmi_sys_boot_opt->param_valid != 0x62) + goto out; + + rc = ipmi_sys_boot_opt->flag_set; + +out: + free(ipmi_sys_boot_opt); + return rc; +} + +static void ipmi_get_chassis_boot_opt_resp(struct ipmi_msg *msg) +{ + bmc_boot_opt_waiting = false; + + if (msg->cc != IPMI_CC_NO_ERROR) { + prlog(PR_INFO, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT cmd returned error" + " [rc : 0x%x]\n", msg->data[0]); + ipmi_free_msg(msg); + return; + } + + if (msg->resp_size == sizeof(struct ipmi_sys_boot_opt)) { + bmc_boot_opt_valid = true; + memcpy(ipmi_sys_boot_opt, msg->data, msg->resp_size); + } else { + prlog(PR_WARNING, "IPMI: IPMI_CHASSIS_GET_BOOT_OPT unexpected response size\n"); + } + + ipmi_free_msg(msg); +} + +int ipmi_get_chassis_boot_opt_request(void) +{ + int rc; + struct ipmi_msg *msg; + uint8_t req[] = { + 0x62, /* OEM parameter (SBE Validation on astbmc) */ + 0x00, /* no set selector */ + 0x00, /* no block selector */ + }; + + ipmi_sys_boot_opt = zalloc(sizeof(struct ipmi_sys_boot_opt)); + assert(ipmi_sys_boot_opt); + + msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_CHASSIS_GET_BOOT_OPT, + ipmi_get_chassis_boot_opt_resp, NULL, req, + sizeof(req), sizeof(struct ipmi_sys_boot_opt)); + if (!msg) { + free(ipmi_sys_boot_opt); + return OPAL_NO_MEM; + } + + msg->error = ipmi_get_chassis_boot_opt_resp; + prlog(PR_INFO, "IPMI: Requesting IPMI_CHASSIS_GET_BOOT_OPT\n"); + rc = ipmi_queue_msg(msg); + if (rc) { + prlog(PR_ERR, "IPMI: Failed to queue IPMI_CHASSIS_GET_BOOT_OPT\n"); + free(ipmi_sys_boot_opt); + ipmi_free_msg(msg); + return rc; + } + + bmc_boot_opt_waiting = true; + return rc; +} |