ACK: [PATCH] [V3] opal/prd_info: Add OPAL Processor Recovery Diagnostics
Colin Ian King
colin.king at canonical.com
Thu Jun 23 18:40:51 UTC 2016
On 23/06/16 18:48, Deb McLemore wrote:
> We added a new capability to perform PRD integrity checks.
> The OPAL PRD firmware tests will be run when the device tree
> has the proper node configured. Runtime checks will use the
> opal-prd service to query the version of the opal-prd service to
> confirm operational state.
>
> Signed-off-by: Deb McLemore <debmc at linux.vnet.ibm.com>
> ---
> configure.ac | 2 +
> .../arg-show-tests-0001/arg-show-tests-0001.log | 1 +
> .../arg-show-tests-full-0001.log | 2 +
> src/Makefile.am | 1 +
> src/lib/include/fwts_pipeio.h | 1 +
> src/lib/src/Makefile.am | 3 +-
> src/lib/src/fwts_pipeio.c | 29 +++
> src/opal/prd_info.c | 224 +++++++++++++++++++++
> 8 files changed, 262 insertions(+), 1 deletion(-)
> create mode 100644 src/opal/prd_info.c
>
> diff --git a/configure.ac b/configure.ac
> index 6ada384..e3e7512 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -63,6 +63,8 @@
> AC_CHECK_HEADERS([json/json.h])
> AC_CHECK_HEADERS([glib.h])
> AC_CHECK_HEADERS([gio/gio.h])
> + AC_CHECK_HEADERS([asm/opal-prd.h])
> + AM_CONDITIONAL([HAVE_ASM_OPAL_PRD_H], [test "x$ac_cv_header_asm_opal_prd_h" = "xyes"])
> #AC_CHECK_LIB(pcre, pcre_compile)
> AC_SEARCH_LIBS([fdt_check_header], [fdt], [
> AC_DEFINE([HAVE_LIBFDT], [1], [Define if we have libfdt])
> diff --git a/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log b/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log
> index 4179090..1a76b9d 100644
> --- a/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log
> +++ b/fwts-test/arg-show-tests-0001/arg-show-tests-0001.log
> @@ -112,6 +112,7 @@ Batch tests:
> pcc Processor Clocking Control (PCC) test.
> pciirq PCI IRQ Routing Table test.
> pnp BIOS Support Installation structure test.
> + prd_info OPAL Processor Recovery Diagnostics Info
> rsdp RSDP Root System Description Pointer test.
> rsdt RSDT Root System Description Table test.
> sbst SBST Smart Battery Specification Table test.
> diff --git a/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log b/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
> index 6784ed3..695c5d6 100644
> --- a/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
> +++ b/fwts-test/arg-show-tests-full-0001/arg-show-tests-full-0001.log
> @@ -663,6 +663,8 @@ Batch tests:
> PCI IRQ Routing Table test.
> pnp (1 test):
> PnP BIOS Support Installation structure test.
> + prd_info (1 test):
> + OPAL Processor Recovery Diagnostics Info
> rsdp (1 test):
> RSDP Root System Description Pointer test.
> rsdt (1 test):
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 00cde32..100eaa3 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -128,6 +128,7 @@ fwts_SOURCES = main.c \
> kernel/olog/olog.c \
> kernel/oops/oops.c \
> kernel/version/version.c \
> + opal/prd_info.c \
> pci/aspm/aspm.c \
> pci/crs/crs.c \
> pci/maxreadreq/maxreadreq.c \
> diff --git a/src/lib/include/fwts_pipeio.h b/src/lib/include/fwts_pipeio.h
> index 9a874dd..8c1b664 100644
> --- a/src/lib/include/fwts_pipeio.h
> +++ b/src/lib/include/fwts_pipeio.h
> @@ -41,6 +41,7 @@ int fwts_pipe_close(const int fd, const pid_t pid);
> int fwts_pipe_close2(const int in_fd, const int out_fd, const pid_t pid);
> int fwts_pipe_exec(const char *command, fwts_list **list, int *status);
> int fwts_exec(const char *command, int *status);
> +int fwts_exec2(const char *command, char **output);
> int fwts_write_string_to_file(const fwts_framework *fw, FILE *file, const char *str);
> int fwts_write_string_file(const fwts_framework *fw, const char *file_name, const char *str);
> int fwts_read_file_first_line(const fwts_framework *fw, const char *file_name, char **line);
> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
> index e96b75f..1b8fd74 100644
> --- a/src/lib/src/Makefile.am
> +++ b/src/lib/src/Makefile.am
> @@ -19,7 +19,8 @@ libfwts_la_LDFLAGS = \
> libfwts_la_CPPFLAGS = $(AM_CPPFLAGS) -DACPI_DEBUG_OUTPUT
>
> if HAVE_LIBFDT
> -dt_sources = fwts_devicetree.c
> +dt_sources = \
> + fwts_devicetree.c
> endif
>
> #
> diff --git a/src/lib/src/fwts_pipeio.c b/src/lib/src/fwts_pipeio.c
> index b501f7b..f62621a 100644
> --- a/src/lib/src/fwts_pipeio.c
> +++ b/src/lib/src/fwts_pipeio.c
> @@ -321,6 +321,35 @@ int fwts_exec(const char *command, int *status)
> }
>
> /*
> + * fwts_exec2()
> + * execute a command
> + * Return to the parent/caller the exit status from the command
> + * status is -1 if errors.
> + */
> +
> +int fwts_exec2(const char *command, char **output)
> +{
> + pid_t pid;
> + int status = -1, in_fd, out_fd;
> + ssize_t out_len;
> +
> + if (fwts_pipe_open_rw(command, &pid,
> + &in_fd, &out_fd) < 0) {
> + return -1;
> + }
> +
> + if (fwts_pipe_readwrite(in_fd,
> + command, sizeof(command),
> + out_fd, output, &out_len)) {
> + return -1;
> + }
> +
> + status = fwts_pipe_close2(in_fd, out_fd, pid);
> +
> + return status;
> +}
> +
> +/*
> * fwts_write_string_to_file()
> * write a string to a file pointer
> * Return FWTS_OK if writing worked, FWTS_ERROR if it failed.
> diff --git a/src/opal/prd_info.c b/src/opal/prd_info.c
> new file mode 100644
> index 0000000..537d1ed
> --- /dev/null
> +++ b/src/opal/prd_info.c
> @@ -0,0 +1,224 @@
> +/*
> + * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> + *
> + * 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 <fcntl.h>
> +#include <sys/ioctl.h>
> +
> +#include "fwts.h"
> +
> +#ifdef HAVE_LIBFDT
> +#include <libfdt.h>
> +#endif
> +
> +#ifdef HAVE_ASM_OPAL_PRD_H
> +#include <asm/opal-prd.h>
> +#endif
> +
> +static const char *prd_devnode = "/dev/opal-prd";
> +
> +bool prd_present(int fwts_prd_flags) {
> + return !access(prd_devnode, fwts_prd_flags);
> +}
> +
> +#ifdef HAVE_ASM_OPAL_PRD_H
> +int prd_dev_query(fwts_framework *fw)
> +{
> +
> + int fd = 0;
> + struct opal_prd_info info;
> +
> + if ((fd = open(prd_devnode, O_RDWR)) < 0) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info",
> + "Cannot get data from the OPAL PRD "
> + " device interface,"
> + " check if opal-prd daemon may be in use "
> + "or check your user privileges.");
> + return FWTS_ERROR;
> + }
> +
> + memset(&info, 0, sizeof(info));
> +
> + if (ioctl(fd, OPAL_PRD_GET_INFO, &info)) {
> + close(fd);
> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info",
> + "Cannot get data from the"
> + " OPAL PRD device interface.");
> + return FWTS_ERROR;
> + } else {
> + fwts_log_info(fw, "OPAL PRD Version is %lu",
> + info.version);
> + close(fd);
> + return FWTS_OK;
> + }
> +}
> +#endif
> +
> +static int prd_service_check(fwts_framework *fw, int *restart)
> +{
> + int rc = FWTS_OK, status = 0, stop_status = 0;
> + char *command = NULL;
> + char *output = NULL;
> +
> + command = "systemctl status opal-prd.service 2>&1";
> + status = fwts_exec2(command, &output);
> +
> + if (output)
> + free(output);
> +
> + switch (status) {
> + case -1: /* status when nothing was successful */
> + fwts_failed(fw, LOG_LEVEL_HIGH, "OPAL PRD Info",
> + "Attempt was made to stop the "
> + "opal-prd.service but was not "
> + "successful. Try to "
> + "\"sudo systemctl stop "
> + "opal-prd.service\" and retry.");
> + rc = FWTS_ERROR;
> + goto out;
> + case 0: /* "running" */
> + command = "systemctl stop opal-prd.service 2>&1";
> + stop_status = fwts_exec2(command, &output);
> +
> + if (output)
> + free(output);
> +
> + switch (stop_status) {
> + case 0:
> + *restart = 1;
> + break;
> + default:
> + fwts_failed(fw, LOG_LEVEL_HIGH, "OPAL PRD Info",
> + "Attempt was made to stop the "
> + "opal-prd.service but was not "
> + "successful. Try to "
> + "\"sudo systemctl stop "
> + "opal-prd.service\" and retry.");
> + rc = FWTS_ERROR;
> + goto out;
> + }
> + default:
> + break;
> + }
> +
> +out:
> + return rc;
> +}
> +
> +static int prd_restart(fwts_framework *fw)
> +{
> + int status = 0;
> + char *command = NULL;
> + char *output = NULL;
> +
> + command = "systemctl start opal-prd.service 2>&1";
> + status = fwts_exec2(command, &output);
> +
> + if (output)
> + free(output);
> +
> + if (status) {
> + fwts_log_info(fw, "OPAL PRD service (opal-prd.service)"
> + " was restarted after stopping it to allow "
> + "checks. Please re-check since processing "
> + "was not able to be confirmed, "
> + "\"sudo systemctl status opal-prd.service\"");
> + } else {
> + fwts_log_info(fw, "OPAL PRD service (opal-prd.service)"
> + " was restarted after stopping it to allow "
> + "checks. This is informational only, "
> + "no action needed.");
> + }
> +
> + return status; /* ignored by caller */
> +}
> +
> +static int prd_info_test1(fwts_framework *fw)
> +{
> +
> + int restart = 0;
> +
> + if (prd_service_check(fw, &restart)) {
> + /* failures logged in subroutine */
> + return FWTS_ERROR;
> + }
> +
> + if (!prd_present(R_OK | W_OK)) {
> + fwts_failed(fw, LOG_LEVEL_CRITICAL, "OPAL PRD Info",
> + "Cannot read and write to the OPAL PRD"
> + " device interface,"
> + " check your user privileges.");
> + return FWTS_ERROR;
> + }
> +
> +#ifdef HAVE_ASM_OPAL_PRD_H
> + if (prd_dev_query(fw)) {
> + /* failures logged in subroutine */
> + return FWTS_ERROR;
> + }
> +#endif
> +
> + if (restart) {
> + prd_restart(fw); /* ignore rc */
> + }
> +
> + fwts_passed(fw, "OPAL PRD info passed.");
> +
> + return FWTS_OK;
> +}
> +
> +static int prd_info_init(fwts_framework *fw)
> +{
> + if (fw->fdt) {
> +#ifdef HAVE_LIBFDT
> + int node;
> + node = fdt_path_offset(fw->fdt,
> + "/ibm,opal/diagnostics");
> + if (node >= 0) {
> + if (!fdt_node_check_compatible(fw->fdt, node,
> + "ibm,opal-prd")) {
> + return FWTS_OK;
> + } else {
> + return FWTS_SKIP;
> + }
> + }
> +#endif
> + } else {
> + fwts_log_info(fw, "The OPAL PRD device tree node"
> + " is not present so skipping test");
> + return FWTS_SKIP;
> + }
> +
> + /* only run test when fdt node is confirmed */
> + return FWTS_SKIP;
> +}
> +
> +static fwts_framework_minor_test prd_info_tests[] = {
> + { prd_info_test1, "OPAL Processor Recovery Diagnostics Info" },
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops prd_info_ops = {
> + .description = "OPAL Processor Recovery Diagnostics Info",
> + .init = prd_info_init,
> + .minor_tests = prd_info_tests
> +};
> +
> +FWTS_REGISTER("prd_info", &prd_info_ops, FWTS_TEST_EARLY,
> + FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV)
>
That looks good to me. Passes the fwts "make check" tests and is clean
on CoverityScan too. Thanks Deb.
Acked-by: Colin Ian King <colin.king at canonical.com>
More information about the fwts-devel
mailing list