[PATCH] V2 opal/prd_info: Add OPAL Processor Recovery Diagnostics

Deb McLemore debmc at linux.vnet.ibm.com
Tue Jun 21 13:58:18 UTC 2016


We added a new capability to perform PRD integrity checks.
The OPAL PRD firmware feature will be set 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-full-0001.log                   |   2 +
 src/Makefile.am                                    |   8 +-
 src/lib/include/fwts_firmware.h                    |  22 ++-
 src/lib/include/fwts_pipeio.h                      |   1 +
 src/lib/src/Makefile.am                            |   3 +-
 src/lib/src/fwts_devicetree.c                      |  12 +-
 src/lib/src/fwts_firmware.c                        |  25 ++-
 src/lib/src/fwts_framework.c                       |   5 +-
 src/lib/src/fwts_pipeio.c                          |  29 ++++
 src/opal/prd_info.c                                | 188 +++++++++++++++++++++
 11 files changed, 277 insertions(+), 20 deletions(-)
 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-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..b86fe52 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,6 +26,11 @@ dt_tests = \
 	devicetree/dt_sysinfo/dt_sysinfo.c
 endif
 
+if HAVE_ASM_OPAL_PRD_H
+opal_tests = \
+	opal/prd_info.c
+endif
+
 #
 #  fwts main + tests
 #
@@ -142,7 +147,8 @@ fwts_SOURCES = main.c 				\
 	uefi/uefirtauthvar/uefirtauthvar.c	\
 	uefi/esrtdump/esrtdump.c		\
 	uefi/esrt/esrt.c			\
-	$(dt_tests)
+	$(dt_tests)				\
+	$(opal_tests)
 
 fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
 
diff --git a/src/lib/include/fwts_firmware.h b/src/lib/include/fwts_firmware.h
index 9221afc..fa8f621 100644
--- a/src/lib/include/fwts_firmware.h
+++ b/src/lib/include/fwts_firmware.h
@@ -1,5 +1,6 @@
 /*
  * 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
@@ -30,21 +31,24 @@ enum firmware_type {
 };
 
 enum firmware_feature {
-	FWTS_FW_FEATURE_ACPI		= 0x1,
-	FWTS_FW_FEATURE_DEVICETREE	= 0x2,
-	FWTS_FW_FEATURE_IPMI		= 0x4,
-	FWTS_FW_FEATURE_ALL		= FWTS_FW_FEATURE_ACPI |
-					  FWTS_FW_FEATURE_DEVICETREE |
-					  FWTS_FW_FEATURE_IPMI
+	FWTS_FW_FEATURE_ACPI		=	0x1,
+	FWTS_FW_FEATURE_DEVICETREE	=	0x2,
+	FWTS_FW_FEATURE_IPMI		=	0x4,
+	FWTS_FW_FEATURE_OPAL_PRD	=	0x8,
+	FWTS_FW_FEATURE_ALL		=	FWTS_FW_FEATURE_ACPI |
+						FWTS_FW_FEATURE_DEVICETREE |
+						FWTS_FW_FEATURE_IPMI |
+						FWTS_FW_FEATURE_OPAL_PRD
 };
 
 int fwts_firmware_detect(void);
-int fwts_firmware_features(void);
+int fwts_firmware_features(fwts_framework *fw);
 const char *fwts_firmware_feature_string(const int features);
 
-static inline bool fwts_firmware_has_features(const int features)
+static inline bool fwts_firmware_has_features(fwts_framework *fw,
+			const int features)
 {
-	return (fwts_firmware_features() & features) == features;
+	return (fwts_firmware_features(fw) & features) == features;
 }
 
 #endif
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_devicetree.c b/src/lib/src/fwts_devicetree.c
index 5978ab9..0c62953 100644
--- a/src/lib/src/fwts_devicetree.c
+++ b/src/lib/src/fwts_devicetree.c
@@ -20,7 +20,7 @@
 #define _GNU_SOURCE
 
 #include <stdio.h>
-
+#include <libfdt.h>
 #include "fwts.h"
 
 static const char *devicetree_fs_path = "/sys/firmware/devicetree/base";
@@ -32,10 +32,12 @@ int fwts_devicetree_read(fwts_framework *fwts)
 	ssize_t len;
 	pid_t pid;
 
-	if (!fwts_firmware_has_features(FWTS_FW_FEATURE_DEVICETREE))
+	if (!fwts_firmware_has_features(fwts,
+		FWTS_FW_FEATURE_DEVICETREE))
 		return FWTS_OK;
 
-	rc = asprintf(&command, "dtc -I fs -O dtb %s", devicetree_fs_path);
+	rc = asprintf(&command, "dtc -I fs -O dtb %s",
+		devicetree_fs_path);
 	if (rc < 0)
 		return FWTS_ERROR;
 
@@ -55,7 +57,8 @@ int fwts_devicetree_read(fwts_framework *fwts)
 	status = fwts_pipe_close(fd, pid);
 
 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0 || len == 0) {
-		fprintf(stderr, "Cannot read devicetree data: dtc failed\n");
+		fprintf(stderr,
+			"Cannot read devicetree data: dtc failed\n");
 		free(data);
 		return FWTS_ERROR;
 	}
@@ -64,4 +67,3 @@ int fwts_devicetree_read(fwts_framework *fwts)
 
 	return FWTS_OK;
 }
-
diff --git a/src/lib/src/fwts_firmware.c b/src/lib/src/fwts_firmware.c
index 972303a..f0bde63 100644
--- a/src/lib/src/fwts_firmware.c
+++ b/src/lib/src/fwts_firmware.c
@@ -1,5 +1,6 @@
 /*
  * 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
@@ -23,6 +24,10 @@
 
 #include "fwts.h"
 
+#if defined HAVE_LIBFDT
+#include <libfdt.h>
+#endif
+
 static enum firmware_type firmware_type;
 static bool firmware_type_valid;
 
@@ -33,6 +38,7 @@ static struct {
 	{ FWTS_FW_FEATURE_ACPI,		"ACPI" },
 	{ FWTS_FW_FEATURE_DEVICETREE,	"devicetree" },
 	{ FWTS_FW_FEATURE_IPMI,		"IPMI" },
+	{ FWTS_FW_FEATURE_OPAL_PRD,	"OPAL PRD" },
 };
 
 /*
@@ -60,7 +66,7 @@ int fwts_firmware_detect(void)
 	return firmware_type;
 }
 
-int fwts_firmware_features(void)
+int fwts_firmware_features(fwts_framework *fw)
 {
 	int features = 0;
 
@@ -83,6 +89,21 @@ int fwts_firmware_features(void)
 	if (!stat("/dev/ipmi0", &ipmi_statbuf))
 		features |= FWTS_FW_FEATURE_IPMI;
 
+	if (fw->fdt) { /* condition suppresses compile to use fw parm */
+#if defined HAVE_LIBFDT
+	/* conditionally check to make sure the timing has fdt set */
+		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")) {
+				features |= FWTS_FW_FEATURE_OPAL_PRD;
+			}
+		}
+#endif
+	}
+
 	return features;
 }
 
@@ -90,7 +111,7 @@ const char *fwts_firmware_feature_string(const int features)
 {
 	const int n = FWTS_ARRAY_LEN(feature_names);
 	const char sep[] = ", ";
-	static char str[60];
+	static char str[70];
 	size_t len;
 	char *p;
 	int i;
diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c
index c53306a..1e75085 100644
--- a/src/lib/src/fwts_framework.c
+++ b/src/lib/src/fwts_framework.c
@@ -605,8 +605,9 @@ static int fwts_framework_run_test(fwts_framework *fw, fwts_framework_test *test
 		goto done;
 	}
 
-	if (!fwts_firmware_has_features(test->fw_features)) {
-		int missing = test->fw_features & ~fwts_firmware_features();
+	if (!fwts_firmware_has_features(fw, test->fw_features)) {
+		int missing = test->fw_features &
+			~fwts_firmware_features(fw);
 		fwts_log_info(fw, "Test skipped, missing features: %s",
 			fwts_firmware_feature_string(missing));
 		fw->current_major_test->results.skipped +=
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..2f12625
--- /dev/null
+++ b/src/opal/prd_info.c
@@ -0,0 +1,188 @@
+/*
+ * 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 <asm/opal-prd.h>
+
+#include "fwts.h"
+
+static const char *prd_devnode = "/dev/opal-prd";
+
+bool prd_present(int fwts_prd_flags) {
+	return !access(prd_devnode, fwts_prd_flags);
+}
+
+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;
+	}
+}
+
+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;
+	}
+
+	if (prd_dev_query(fw)) {
+		/* failures logged in subroutine */
+		return FWTS_ERROR;
+	}
+
+	if (restart) {
+		prd_restart(fw); /* ignore rc */
+	}
+
+	fwts_passed(fw, "OPAL PRD info passed.");
+
+	return FWTS_OK;
+}
+
+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",
+	.minor_tests = prd_info_tests
+};
+
+FWTS_REGISTER_FEATURES("prd_info", &prd_info_ops, FWTS_TEST_EARLY,
+		FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
+		FWTS_FW_FEATURE_OPAL_PRD)
-- 
1.8.3.1




More information about the fwts-devel mailing list