diff mbox

[2/4] opal: mem_info: Add OPAL MEM Info validation

Message ID 1478836928-8761-1-git-send-email-debmc@linux.vnet.ibm.com
State Accepted
Headers show

Commit Message

Deb McLemore Nov. 11, 2016, 4:02 a.m. UTC
Check that the MEM devices are properly setup in the device tree.

Signed-off-by: Deb McLemore <debmc@linux.vnet.ibm.com>
---
 src/Makefile.am     |   3 +
 src/opal/mem_info.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 451 insertions(+)
 create mode 100644 src/opal/mem_info.c

Comments

Colin Ian King Nov. 11, 2016, 9:45 a.m. UTC | #1
On 11/11/16 04:02, Deb McLemore wrote:
> Check that the MEM devices are properly setup in the device tree.
> 
> Signed-off-by: Deb McLemore <debmc@linux.vnet.ibm.com>
> ---
>  src/Makefile.am     |   3 +
>  src/opal/mem_info.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 451 insertions(+)
>  create mode 100644 src/opal/mem_info.c
> 
> diff --git a/src/Makefile.am b/src/Makefile.am
> index b2604e3..9c2975b 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -24,6 +24,8 @@ if HAVE_LIBFDT
>  dt_tests = \
>  	devicetree/dt_base/dt_base.c		\
>  	devicetree/dt_sysinfo/dt_sysinfo.c
> +mem_tests = \
> +	opal/mem_info.c
>  endif
>  
>  if HAVE_LIBFDT
> @@ -158,6 +160,7 @@ fwts_SOURCES = main.c 				\
>  	uefi/esrtdump/esrtdump.c		\
>  	uefi/esrt/esrt.c			\
>  	$(pci_tests)				\
> +	$(mem_tests)				\
>  	$(dt_tests)
>  
>  fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
> diff --git a/src/opal/mem_info.c b/src/opal/mem_info.c
> new file mode 100644
> index 0000000..749b422
> --- /dev/null
> +++ b/src/opal/mem_info.c
> @@ -0,0 +1,448 @@
> +/*
> + * 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.
> + *
> + */
> +
> +#define _GNU_SOURCE /* added for asprintf */
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <stdio.h>
> +
> +#include "fwts.h"
> +
> +#include <libfdt.h>
> +
> +static int get_dimm_property(fwts_framework *fw,
> +			char *my_path,
> +			bool hex,
> +			char *property)
> +{
> +	int node, prop_len, failures = 0;
> +	const char *prop_buf;
> +	char *prop_string = NULL;
> +
> +	prop_string = strstr(my_path, "/memory-buffer");
> +	if (prop_string) {
> +		node = fdt_path_offset(fw->fdt, prop_string);
> +		if (node >= 0) {
> +			prop_buf = fdt_getprop(fw->fdt, node,
> +					property,
> +					&prop_len);
> +			if ((prop_len > 0) && (prop_buf)) {
> +				fwts_log_nl(fw);
> +				if ((hex) && (prop_len == 4)) {
> +					fwts_passed(fw, "OPAL MEM Info"
> +						" Property of \"%s\" for "
> +						"\"%s\" is "
> +						"\"0x%02X%02X%02X%02X\".",
> +						property,
> +						my_path,
> +						prop_buf[0],
> +						prop_buf[1],
> +						prop_buf[2],
> +						prop_buf[3]);
> +				} else if (!hex) {
> +					if (check_property_printable(fw,
> +						property,
> +						prop_buf,
> +						prop_len)) {
> +							failures ++;
> +					}
> +					fwts_passed(fw,
> +						"OPAL MEM Info Property of"
> +						" \"%s\" for \"%s\" "
> +						"is \"%s\".",
> +						property,
> +						my_path,
> +						prop_buf);
> +				} else {
> +					failures ++;
> +					fwts_log_nl(fw);
> +					fwts_failed(fw,
> +						LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Property of \"%s\" for "
> +						"\"%s\" is not properly "
> +						"formatted. Check your "
> +						"installation for proper "
> +						" device tree nodes.",
> +						property,
> +						my_path);
> +				}
> +			} else {
> +				failures ++;
> +				fwts_log_nl(fw);
> +				fwts_failed(fw,
> +					LOG_LEVEL_CRITICAL,
> +					"OPAL MEM Info",
> +					"Property of \"%s\" for \"%s\" was not"
> +					" able to be retrieved. Check the "
> +					"installation for the MEM device "
> +					"config for missing nodes in the device"
> +					" tree if you expect MEM devices.",
> +					property,
> +					my_path);
> +			}
> +		} else {
> +			failures ++;
> +			fwts_log_nl(fw);
> +			fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +					"OPAL MEM Info",
> +					"Failed to get node for memory-buffer"
> +					" \"%s/%s\", please check the system"
> +					" for setup issues.",
> +					my_path, property);
> +		}
> +	} else {
> +		failures ++;
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +				"OPAL MEM Info",
> +				"Internal processing problem at strstr"
> +				" my_path of \"%s\" for \"%s\", please check"
> +				" the system for setup issues.",
> +				my_path,
> +				property);
> +	}
> +	if (failures) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static int process_dimm(fwts_framework *fw,
> +			char *my_string,
> +			char *my_dir)
> +{
> +	int count, i, failures = 0;
> +	struct dirent **namelist;
> +	bool found = false;
> +
> +	count = scandir(my_dir, &namelist, NULL, alphasort);
> +	if (count < 0) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Scan for MEM devices in '%s' is unable to find any "
> +			"candidates. Check the installation "
> +			"for the MEM device config for missing nodes"
> +			" in the device tree if you expect MEM devices.",
> +			my_dir);
> +		return FWTS_ERROR;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		struct dirent *dirent;
> +		char *my_buffer;
> +		char *my_path;
> +
> +		dirent = namelist[i];
> +
> +		if (dirent->d_name[0] == '.' ||
> +			asprintf(&my_buffer,
> +				"%s",
> +				dirent->d_name) < 0) {
> +			/* asprintf must be last condition so when it */
> +			/* evaluates my_buffer gets allocated */
> +			free(namelist[i]);
> +			continue;
> +		}
> +
> +		if (strstr(my_buffer, my_string)) {
> +			found = true;
> +			if (asprintf(&my_path,
> +				"%s/%s",
> +				my_dir,
> +				my_buffer) < 0 ) {
> +				fwts_log_nl(fw);
> +				fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Internal"
> +						" processing problem at"
> +						" my_link \"%s\", please"
> +						" check the system for"
> +						" setup issues.",
> +						my_buffer);
> +				free(my_buffer);
> +				free(namelist[i]);
> +				continue;
> +			}
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_SLOT_LOC)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_PART_NUM)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_SERIAL_NUM)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, true,
> +					DT_PROPERTY_OPAL_MANUFACTURER_ID)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_STATUS)) {
> +				failures ++;
> +			}
> +			free(my_buffer);
> +			free(namelist[i]);
> +		}
> +	}
> +	free(namelist);
> +
> +	if (!found) {
> +		failures ++;
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +				"OPAL MEM Info",
> +				"No MEM devices (memory-buffer) were found"
> +				" in \"%s\".  Check the system for setup"
> +				" issues.",
> +				DT_FS_PATH);
> +	}
> +
> +	if (failures) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static int process_mba(fwts_framework *fw,
> +			char *my_string,
> +			char *my_dir)
> +{
> +	int count, i, failures = 0;
> +	struct dirent **namelist;
> +	bool found = false;
> +
> +	count = scandir(my_dir, &namelist, NULL, alphasort);
> +	if (count < 0) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Scan for MEM devices for \"%s\" in \"%s\" is"
> +			" unable to find any candidates. Check the"
> +			" installation for the MEM device config for missing"
> +			" nodes in the device tree if you expect MEM devices.",
> +			my_string,
> +			my_dir);
> +		return FWTS_ERROR;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		struct dirent *dirent;
> +		char *my_buffer;
> +		char *my_path;
> +
> +		dirent = namelist[i];
> +
> +		if (dirent->d_name[0] == '.' ||
> +			asprintf(&my_buffer,
> +				"%s",
> +				dirent->d_name) < 0) {
> +			/* asprintf must be last condition so when it */
> +			/* evaluates my_buffer gets allocated */
> +			free(namelist[i]);
> +			continue;
> +		}
> +
> +		if (strstr(my_buffer, my_string)) {
> +			found = true;
> +			if (asprintf(&my_path,
> +				"%s/%s",
> +				my_dir,
> +				my_buffer) < 0 ) {
> +				fwts_log_nl(fw);
> +				fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Internal"
> +						" processing problem at"
> +						" my_link \"%s\", please"
> +						" check the system for"
> +						" setup issues.",
> +						my_buffer);
> +				free(my_buffer);
> +				free(namelist[i]);
> +				continue;
> +			}
> +			if (process_dimm(fw, "dimm", my_path)) {
> +				failures ++;
> +			}
> +			free(my_buffer);
> +			free(namelist[i]);
> +		}
> +	}
> +	free(namelist);
> +
> +	if (!found) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Failed to find any device"
> +			" tree nodes for mba@X from \"%s\"."
> +			" Check the installation "
> +			"for the MEM device config for missing nodes"
> +			" in the device tree if you expect MEM devices.",
> +			my_dir);
> +	}
> +
> +	if ((!found) || (failures)) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +
> +}
> +
> +static int get_linux_mem_devices(fwts_framework *fw)
> +{
> +	int count, i, failures = 0;
> +	struct dirent **namelist;
> +	bool found = false;
> +
> +	count = scandir(DT_FS_PATH, &namelist, NULL, alphasort);
> +	if (count < 0) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Scan for MEM devices in '%s' is unable to find any "
> +			"candidates. Check the installation "
> +			"for the MEM device config for missing nodes"
> +			" in the device tree if you expect MEM devices.",
> +			DT_FS_PATH);
> +		return FWTS_ERROR;
> +	}
> +
> +	fwts_log_nl(fw);
> +	fwts_log_info(fw, "STARTING checks of MEM devices");
> +
> +	for (i = 0; i < count; i++) {
> +		struct dirent *dirent;
> +		char *mem_buffer;
> +		char *mba_path;
> +
> +		dirent = namelist[i];
> +
> +		if (dirent->d_name[0] == '.' ||
> +			asprintf(&mem_buffer,
> +				"%s",
> +				dirent->d_name) < 0) {
> +			/* asprintf must be last condition so when it */
> +			/* evaluates mem_buffer gets allocated */
> +			free(namelist[i]);
> +			continue;
> +		}
> +
> +		if (strstr(mem_buffer, "memory-buffer")) {
> +			found = true;
> +			if (asprintf(&mba_path,
> +				"%s/%s",
> +				DT_FS_PATH,
> +				mem_buffer) < 0 ) {
> +				fwts_log_nl(fw);
> +				fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Internal"
> +						" processing problem at"
> +						" mem_buffer \"%s\", please"
> +						" check the system for"
> +						" setup issues.",
> +						mem_buffer);
> +				free(mem_buffer);
> +				free(namelist[i]);
> +				continue;
> +			}
> +			if (process_mba(fw, "mba", mba_path)) {
> +				failures ++;
> +			}
> +			free(mem_buffer);
> +			free(namelist[i]);
> +		}
> +	}
> +	free(namelist);
> +
> +	fwts_log_nl(fw);
> +	fwts_log_info(fw, "ENDING checks of MEM devices");
> +	fwts_log_nl(fw);
> +
> +	if (!found) {
> +		failures ++;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +				"OPAL MEM Info",
> +				"No MEM devices (memory-buffer@X) were found"
> +				" in \"%s\".  Check the system for setup"
> +				" issues.",
> +				DT_FS_PATH);
> +	}
> +
> +	if (failures) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +
> +}
> +
> +static int mem_info_test1(fwts_framework *fw)
> +{
> +
> +	if (get_linux_mem_devices(fw)) {
> +
> +		/* errors logged earlier */
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static int mem_info_init(fwts_framework *fw)
> +{
> +	if (fw->firmware_type != FWTS_FIRMWARE_OPAL) {
> +		fwts_skipped(fw,
> +			"The firmware type detected was not set"
> +			" to OPAL so skipping the OPAL PCI Info"
> +			" checks.");
> +		return FWTS_SKIP;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static fwts_framework_minor_test mem_info_tests[] = {
> +	{ mem_info_test1, "OPAL MEM Info" },
> +	{ NULL, NULL }
> +};
> +
> +static fwts_framework_ops mem_info_ops = {
> +	.description = "OPAL MEM Info",
> +	.init        = mem_info_init,
> +	.minor_tests = mem_info_tests
> +};
> +
> +FWTS_REGISTER_FEATURES("mem_info", &mem_info_ops, FWTS_TEST_ANYTIME,
> +		FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
> +		FWTS_FW_FEATURE_DEVICETREE);
> 
Acked-by: Colin Ian King <colin.king@canonical.com>
Alex Hung Nov. 16, 2016, 7:35 p.m. UTC | #2
On 2016-11-10 08:02 PM, Deb McLemore wrote:
> Check that the MEM devices are properly setup in the device tree.
>
> Signed-off-by: Deb McLemore <debmc@linux.vnet.ibm.com>
> ---
>  src/Makefile.am     |   3 +
>  src/opal/mem_info.c | 448 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 451 insertions(+)
>  create mode 100644 src/opal/mem_info.c
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index b2604e3..9c2975b 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -24,6 +24,8 @@ if HAVE_LIBFDT
>  dt_tests = \
>  	devicetree/dt_base/dt_base.c		\
>  	devicetree/dt_sysinfo/dt_sysinfo.c
> +mem_tests = \
> +	opal/mem_info.c
>  endif
>
>  if HAVE_LIBFDT
> @@ -158,6 +160,7 @@ fwts_SOURCES = main.c 				\
>  	uefi/esrtdump/esrtdump.c		\
>  	uefi/esrt/esrt.c			\
>  	$(pci_tests)				\
> +	$(mem_tests)				\
>  	$(dt_tests)
>
>  fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
> diff --git a/src/opal/mem_info.c b/src/opal/mem_info.c
> new file mode 100644
> index 0000000..749b422
> --- /dev/null
> +++ b/src/opal/mem_info.c
> @@ -0,0 +1,448 @@
> +/*
> + * 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.
> + *
> + */
> +
> +#define _GNU_SOURCE /* added for asprintf */
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <stdio.h>
> +
> +#include "fwts.h"
> +
> +#include <libfdt.h>
> +
> +static int get_dimm_property(fwts_framework *fw,
> +			char *my_path,
> +			bool hex,
> +			char *property)
> +{
> +	int node, prop_len, failures = 0;
> +	const char *prop_buf;
> +	char *prop_string = NULL;
> +
> +	prop_string = strstr(my_path, "/memory-buffer");
> +	if (prop_string) {
> +		node = fdt_path_offset(fw->fdt, prop_string);
> +		if (node >= 0) {
> +			prop_buf = fdt_getprop(fw->fdt, node,
> +					property,
> +					&prop_len);
> +			if ((prop_len > 0) && (prop_buf)) {
> +				fwts_log_nl(fw);
> +				if ((hex) && (prop_len == 4)) {
> +					fwts_passed(fw, "OPAL MEM Info"
> +						" Property of \"%s\" for "
> +						"\"%s\" is "
> +						"\"0x%02X%02X%02X%02X\".",
> +						property,
> +						my_path,
> +						prop_buf[0],
> +						prop_buf[1],
> +						prop_buf[2],
> +						prop_buf[3]);
> +				} else if (!hex) {
> +					if (check_property_printable(fw,
> +						property,
> +						prop_buf,
> +						prop_len)) {
> +							failures ++;
> +					}
> +					fwts_passed(fw,
> +						"OPAL MEM Info Property of"
> +						" \"%s\" for \"%s\" "
> +						"is \"%s\".",
> +						property,
> +						my_path,
> +						prop_buf);
> +				} else {
> +					failures ++;
> +					fwts_log_nl(fw);
> +					fwts_failed(fw,
> +						LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Property of \"%s\" for "
> +						"\"%s\" is not properly "
> +						"formatted. Check your "
> +						"installation for proper "
> +						" device tree nodes.",
> +						property,
> +						my_path);
> +				}
> +			} else {
> +				failures ++;
> +				fwts_log_nl(fw);
> +				fwts_failed(fw,
> +					LOG_LEVEL_CRITICAL,
> +					"OPAL MEM Info",
> +					"Property of \"%s\" for \"%s\" was not"
> +					" able to be retrieved. Check the "
> +					"installation for the MEM device "
> +					"config for missing nodes in the device"
> +					" tree if you expect MEM devices.",
> +					property,
> +					my_path);
> +			}
> +		} else {
> +			failures ++;
> +			fwts_log_nl(fw);
> +			fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +					"OPAL MEM Info",
> +					"Failed to get node for memory-buffer"
> +					" \"%s/%s\", please check the system"
> +					" for setup issues.",
> +					my_path, property);
> +		}
> +	} else {
> +		failures ++;
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +				"OPAL MEM Info",
> +				"Internal processing problem at strstr"
> +				" my_path of \"%s\" for \"%s\", please check"
> +				" the system for setup issues.",
> +				my_path,
> +				property);
> +	}
> +	if (failures) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static int process_dimm(fwts_framework *fw,
> +			char *my_string,
> +			char *my_dir)
> +{
> +	int count, i, failures = 0;
> +	struct dirent **namelist;
> +	bool found = false;
> +
> +	count = scandir(my_dir, &namelist, NULL, alphasort);
> +	if (count < 0) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Scan for MEM devices in '%s' is unable to find any "
> +			"candidates. Check the installation "
> +			"for the MEM device config for missing nodes"
> +			" in the device tree if you expect MEM devices.",
> +			my_dir);
> +		return FWTS_ERROR;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		struct dirent *dirent;
> +		char *my_buffer;
> +		char *my_path;
> +
> +		dirent = namelist[i];
> +
> +		if (dirent->d_name[0] == '.' ||
> +			asprintf(&my_buffer,
> +				"%s",
> +				dirent->d_name) < 0) {
> +			/* asprintf must be last condition so when it */
> +			/* evaluates my_buffer gets allocated */
> +			free(namelist[i]);
> +			continue;
> +		}
> +
> +		if (strstr(my_buffer, my_string)) {
> +			found = true;
> +			if (asprintf(&my_path,
> +				"%s/%s",
> +				my_dir,
> +				my_buffer) < 0 ) {
> +				fwts_log_nl(fw);
> +				fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Internal"
> +						" processing problem at"
> +						" my_link \"%s\", please"
> +						" check the system for"
> +						" setup issues.",
> +						my_buffer);
> +				free(my_buffer);
> +				free(namelist[i]);
> +				continue;
> +			}
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_SLOT_LOC)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_PART_NUM)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_SERIAL_NUM)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, true,
> +					DT_PROPERTY_OPAL_MANUFACTURER_ID)) {
> +				failures ++;
> +			}
> +
> +			if (get_dimm_property(fw, my_path, false,
> +						DT_PROPERTY_OPAL_STATUS)) {
> +				failures ++;
> +			}
> +			free(my_buffer);
> +			free(namelist[i]);
> +		}
> +	}
> +	free(namelist);
> +
> +	if (!found) {
> +		failures ++;
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +				"OPAL MEM Info",
> +				"No MEM devices (memory-buffer) were found"
> +				" in \"%s\".  Check the system for setup"
> +				" issues.",
> +				DT_FS_PATH);
> +	}
> +
> +	if (failures) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static int process_mba(fwts_framework *fw,
> +			char *my_string,
> +			char *my_dir)
> +{
> +	int count, i, failures = 0;
> +	struct dirent **namelist;
> +	bool found = false;
> +
> +	count = scandir(my_dir, &namelist, NULL, alphasort);
> +	if (count < 0) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Scan for MEM devices for \"%s\" in \"%s\" is"
> +			" unable to find any candidates. Check the"
> +			" installation for the MEM device config for missing"
> +			" nodes in the device tree if you expect MEM devices.",
> +			my_string,
> +			my_dir);
> +		return FWTS_ERROR;
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		struct dirent *dirent;
> +		char *my_buffer;
> +		char *my_path;
> +
> +		dirent = namelist[i];
> +
> +		if (dirent->d_name[0] == '.' ||
> +			asprintf(&my_buffer,
> +				"%s",
> +				dirent->d_name) < 0) {
> +			/* asprintf must be last condition so when it */
> +			/* evaluates my_buffer gets allocated */
> +			free(namelist[i]);
> +			continue;
> +		}
> +
> +		if (strstr(my_buffer, my_string)) {
> +			found = true;
> +			if (asprintf(&my_path,
> +				"%s/%s",
> +				my_dir,
> +				my_buffer) < 0 ) {
> +				fwts_log_nl(fw);
> +				fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Internal"
> +						" processing problem at"
> +						" my_link \"%s\", please"
> +						" check the system for"
> +						" setup issues.",
> +						my_buffer);
> +				free(my_buffer);
> +				free(namelist[i]);
> +				continue;
> +			}
> +			if (process_dimm(fw, "dimm", my_path)) {
> +				failures ++;
> +			}
> +			free(my_buffer);
> +			free(namelist[i]);
> +		}
> +	}
> +	free(namelist);
> +
> +	if (!found) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Failed to find any device"
> +			" tree nodes for mba@X from \"%s\"."
> +			" Check the installation "
> +			"for the MEM device config for missing nodes"
> +			" in the device tree if you expect MEM devices.",
> +			my_dir);
> +	}
> +
> +	if ((!found) || (failures)) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +
> +}
> +
> +static int get_linux_mem_devices(fwts_framework *fw)
> +{
> +	int count, i, failures = 0;
> +	struct dirent **namelist;
> +	bool found = false;
> +
> +	count = scandir(DT_FS_PATH, &namelist, NULL, alphasort);
> +	if (count < 0) {
> +		fwts_log_nl(fw);
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"OPAL MEM Info",
> +			"Scan for MEM devices in '%s' is unable to find any "
> +			"candidates. Check the installation "
> +			"for the MEM device config for missing nodes"
> +			" in the device tree if you expect MEM devices.",
> +			DT_FS_PATH);
> +		return FWTS_ERROR;
> +	}
> +
> +	fwts_log_nl(fw);
> +	fwts_log_info(fw, "STARTING checks of MEM devices");
> +
> +	for (i = 0; i < count; i++) {
> +		struct dirent *dirent;
> +		char *mem_buffer;
> +		char *mba_path;
> +
> +		dirent = namelist[i];
> +
> +		if (dirent->d_name[0] == '.' ||
> +			asprintf(&mem_buffer,
> +				"%s",
> +				dirent->d_name) < 0) {
> +			/* asprintf must be last condition so when it */
> +			/* evaluates mem_buffer gets allocated */
> +			free(namelist[i]);
> +			continue;
> +		}
> +
> +		if (strstr(mem_buffer, "memory-buffer")) {
> +			found = true;
> +			if (asprintf(&mba_path,
> +				"%s/%s",
> +				DT_FS_PATH,
> +				mem_buffer) < 0 ) {
> +				fwts_log_nl(fw);
> +				fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +						"OPAL MEM Info",
> +						"Internal"
> +						" processing problem at"
> +						" mem_buffer \"%s\", please"
> +						" check the system for"
> +						" setup issues.",
> +						mem_buffer);
> +				free(mem_buffer);
> +				free(namelist[i]);
> +				continue;
> +			}
> +			if (process_mba(fw, "mba", mba_path)) {
> +				failures ++;
> +			}
> +			free(mem_buffer);
> +			free(namelist[i]);
> +		}
> +	}
> +	free(namelist);
> +
> +	fwts_log_nl(fw);
> +	fwts_log_info(fw, "ENDING checks of MEM devices");
> +	fwts_log_nl(fw);
> +
> +	if (!found) {
> +		failures ++;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +				"OPAL MEM Info",
> +				"No MEM devices (memory-buffer@X) were found"
> +				" in \"%s\".  Check the system for setup"
> +				" issues.",
> +				DT_FS_PATH);
> +	}
> +
> +	if (failures) {
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +
> +}
> +
> +static int mem_info_test1(fwts_framework *fw)
> +{
> +
> +	if (get_linux_mem_devices(fw)) {
> +
> +		/* errors logged earlier */
> +		return FWTS_ERROR;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static int mem_info_init(fwts_framework *fw)
> +{
> +	if (fw->firmware_type != FWTS_FIRMWARE_OPAL) {
> +		fwts_skipped(fw,
> +			"The firmware type detected was not set"
> +			" to OPAL so skipping the OPAL PCI Info"
> +			" checks.");
> +		return FWTS_SKIP;
> +	} else {
> +		return FWTS_OK;
> +	}
> +}
> +
> +static fwts_framework_minor_test mem_info_tests[] = {
> +	{ mem_info_test1, "OPAL MEM Info" },
> +	{ NULL, NULL }
> +};
> +
> +static fwts_framework_ops mem_info_ops = {
> +	.description = "OPAL MEM Info",
> +	.init        = mem_info_init,
> +	.minor_tests = mem_info_tests
> +};
> +
> +FWTS_REGISTER_FEATURES("mem_info", &mem_info_ops, FWTS_TEST_ANYTIME,
> +		FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
> +		FWTS_FW_FEATURE_DEVICETREE);
>

Acked-by: Alex Hung <alex.hung@canonical.com>
diff mbox

Patch

diff --git a/src/Makefile.am b/src/Makefile.am
index b2604e3..9c2975b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,6 +24,8 @@  if HAVE_LIBFDT
 dt_tests = \
 	devicetree/dt_base/dt_base.c		\
 	devicetree/dt_sysinfo/dt_sysinfo.c
+mem_tests = \
+	opal/mem_info.c
 endif
 
 if HAVE_LIBFDT
@@ -158,6 +160,7 @@  fwts_SOURCES = main.c 				\
 	uefi/esrtdump/esrtdump.c		\
 	uefi/esrt/esrt.c			\
 	$(pci_tests)				\
+	$(mem_tests)				\
 	$(dt_tests)
 
 fwts_LDFLAGS = -lm `pkg-config --libs glib-2.0 gio-2.0`
diff --git a/src/opal/mem_info.c b/src/opal/mem_info.c
new file mode 100644
index 0000000..749b422
--- /dev/null
+++ b/src/opal/mem_info.c
@@ -0,0 +1,448 @@ 
+/*
+ * 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.
+ *
+ */
+
+#define _GNU_SOURCE /* added for asprintf */
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+
+#include "fwts.h"
+
+#include <libfdt.h>
+
+static int get_dimm_property(fwts_framework *fw,
+			char *my_path,
+			bool hex,
+			char *property)
+{
+	int node, prop_len, failures = 0;
+	const char *prop_buf;
+	char *prop_string = NULL;
+
+	prop_string = strstr(my_path, "/memory-buffer");
+	if (prop_string) {
+		node = fdt_path_offset(fw->fdt, prop_string);
+		if (node >= 0) {
+			prop_buf = fdt_getprop(fw->fdt, node,
+					property,
+					&prop_len);
+			if ((prop_len > 0) && (prop_buf)) {
+				fwts_log_nl(fw);
+				if ((hex) && (prop_len == 4)) {
+					fwts_passed(fw, "OPAL MEM Info"
+						" Property of \"%s\" for "
+						"\"%s\" is "
+						"\"0x%02X%02X%02X%02X\".",
+						property,
+						my_path,
+						prop_buf[0],
+						prop_buf[1],
+						prop_buf[2],
+						prop_buf[3]);
+				} else if (!hex) {
+					if (check_property_printable(fw,
+						property,
+						prop_buf,
+						prop_len)) {
+							failures ++;
+					}
+					fwts_passed(fw,
+						"OPAL MEM Info Property of"
+						" \"%s\" for \"%s\" "
+						"is \"%s\".",
+						property,
+						my_path,
+						prop_buf);
+				} else {
+					failures ++;
+					fwts_log_nl(fw);
+					fwts_failed(fw,
+						LOG_LEVEL_CRITICAL,
+						"OPAL MEM Info",
+						"Property of \"%s\" for "
+						"\"%s\" is not properly "
+						"formatted. Check your "
+						"installation for proper "
+						" device tree nodes.",
+						property,
+						my_path);
+				}
+			} else {
+				failures ++;
+				fwts_log_nl(fw);
+				fwts_failed(fw,
+					LOG_LEVEL_CRITICAL,
+					"OPAL MEM Info",
+					"Property of \"%s\" for \"%s\" was not"
+					" able to be retrieved. Check the "
+					"installation for the MEM device "
+					"config for missing nodes in the device"
+					" tree if you expect MEM devices.",
+					property,
+					my_path);
+			}
+		} else {
+			failures ++;
+			fwts_log_nl(fw);
+			fwts_failed(fw, LOG_LEVEL_CRITICAL,
+					"OPAL MEM Info",
+					"Failed to get node for memory-buffer"
+					" \"%s/%s\", please check the system"
+					" for setup issues.",
+					my_path, property);
+		}
+	} else {
+		failures ++;
+		fwts_log_nl(fw);
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+				"OPAL MEM Info",
+				"Internal processing problem at strstr"
+				" my_path of \"%s\" for \"%s\", please check"
+				" the system for setup issues.",
+				my_path,
+				property);
+	}
+	if (failures) {
+		return FWTS_ERROR;
+	} else {
+		return FWTS_OK;
+	}
+}
+
+static int process_dimm(fwts_framework *fw,
+			char *my_string,
+			char *my_dir)
+{
+	int count, i, failures = 0;
+	struct dirent **namelist;
+	bool found = false;
+
+	count = scandir(my_dir, &namelist, NULL, alphasort);
+	if (count < 0) {
+		fwts_log_nl(fw);
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"OPAL MEM Info",
+			"Scan for MEM devices in '%s' is unable to find any "
+			"candidates. Check the installation "
+			"for the MEM device config for missing nodes"
+			" in the device tree if you expect MEM devices.",
+			my_dir);
+		return FWTS_ERROR;
+	}
+
+	for (i = 0; i < count; i++) {
+		struct dirent *dirent;
+		char *my_buffer;
+		char *my_path;
+
+		dirent = namelist[i];
+
+		if (dirent->d_name[0] == '.' ||
+			asprintf(&my_buffer,
+				"%s",
+				dirent->d_name) < 0) {
+			/* asprintf must be last condition so when it */
+			/* evaluates my_buffer gets allocated */
+			free(namelist[i]);
+			continue;
+		}
+
+		if (strstr(my_buffer, my_string)) {
+			found = true;
+			if (asprintf(&my_path,
+				"%s/%s",
+				my_dir,
+				my_buffer) < 0 ) {
+				fwts_log_nl(fw);
+				fwts_failed(fw, LOG_LEVEL_CRITICAL,
+						"OPAL MEM Info",
+						"Internal"
+						" processing problem at"
+						" my_link \"%s\", please"
+						" check the system for"
+						" setup issues.",
+						my_buffer);
+				free(my_buffer);
+				free(namelist[i]);
+				continue;
+			}
+			if (get_dimm_property(fw, my_path, false,
+						DT_PROPERTY_OPAL_SLOT_LOC)) {
+				failures ++;
+			}
+
+			if (get_dimm_property(fw, my_path, false,
+						DT_PROPERTY_OPAL_PART_NUM)) {
+				failures ++;
+			}
+
+			if (get_dimm_property(fw, my_path, false,
+						DT_PROPERTY_OPAL_SERIAL_NUM)) {
+				failures ++;
+			}
+
+			if (get_dimm_property(fw, my_path, true,
+					DT_PROPERTY_OPAL_MANUFACTURER_ID)) {
+				failures ++;
+			}
+
+			if (get_dimm_property(fw, my_path, false,
+						DT_PROPERTY_OPAL_STATUS)) {
+				failures ++;
+			}
+			free(my_buffer);
+			free(namelist[i]);
+		}
+	}
+	free(namelist);
+
+	if (!found) {
+		failures ++;
+		fwts_log_nl(fw);
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+				"OPAL MEM Info",
+				"No MEM devices (memory-buffer) were found"
+				" in \"%s\".  Check the system for setup"
+				" issues.",
+				DT_FS_PATH);
+	}
+
+	if (failures) {
+		return FWTS_ERROR;
+	} else {
+		return FWTS_OK;
+	}
+}
+
+static int process_mba(fwts_framework *fw,
+			char *my_string,
+			char *my_dir)
+{
+	int count, i, failures = 0;
+	struct dirent **namelist;
+	bool found = false;
+
+	count = scandir(my_dir, &namelist, NULL, alphasort);
+	if (count < 0) {
+		fwts_log_nl(fw);
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"OPAL MEM Info",
+			"Scan for MEM devices for \"%s\" in \"%s\" is"
+			" unable to find any candidates. Check the"
+			" installation for the MEM device config for missing"
+			" nodes in the device tree if you expect MEM devices.",
+			my_string,
+			my_dir);
+		return FWTS_ERROR;
+	}
+
+	for (i = 0; i < count; i++) {
+		struct dirent *dirent;
+		char *my_buffer;
+		char *my_path;
+
+		dirent = namelist[i];
+
+		if (dirent->d_name[0] == '.' ||
+			asprintf(&my_buffer,
+				"%s",
+				dirent->d_name) < 0) {
+			/* asprintf must be last condition so when it */
+			/* evaluates my_buffer gets allocated */
+			free(namelist[i]);
+			continue;
+		}
+
+		if (strstr(my_buffer, my_string)) {
+			found = true;
+			if (asprintf(&my_path,
+				"%s/%s",
+				my_dir,
+				my_buffer) < 0 ) {
+				fwts_log_nl(fw);
+				fwts_failed(fw, LOG_LEVEL_CRITICAL,
+						"OPAL MEM Info",
+						"Internal"
+						" processing problem at"
+						" my_link \"%s\", please"
+						" check the system for"
+						" setup issues.",
+						my_buffer);
+				free(my_buffer);
+				free(namelist[i]);
+				continue;
+			}
+			if (process_dimm(fw, "dimm", my_path)) {
+				failures ++;
+			}
+			free(my_buffer);
+			free(namelist[i]);
+		}
+	}
+	free(namelist);
+
+	if (!found) {
+		fwts_log_nl(fw);
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"OPAL MEM Info",
+			"Failed to find any device"
+			" tree nodes for mba@X from \"%s\"."
+			" Check the installation "
+			"for the MEM device config for missing nodes"
+			" in the device tree if you expect MEM devices.",
+			my_dir);
+	}
+
+	if ((!found) || (failures)) {
+		return FWTS_ERROR;
+	} else {
+		return FWTS_OK;
+	}
+
+}
+
+static int get_linux_mem_devices(fwts_framework *fw)
+{
+	int count, i, failures = 0;
+	struct dirent **namelist;
+	bool found = false;
+
+	count = scandir(DT_FS_PATH, &namelist, NULL, alphasort);
+	if (count < 0) {
+		fwts_log_nl(fw);
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"OPAL MEM Info",
+			"Scan for MEM devices in '%s' is unable to find any "
+			"candidates. Check the installation "
+			"for the MEM device config for missing nodes"
+			" in the device tree if you expect MEM devices.",
+			DT_FS_PATH);
+		return FWTS_ERROR;
+	}
+
+	fwts_log_nl(fw);
+	fwts_log_info(fw, "STARTING checks of MEM devices");
+
+	for (i = 0; i < count; i++) {
+		struct dirent *dirent;
+		char *mem_buffer;
+		char *mba_path;
+
+		dirent = namelist[i];
+
+		if (dirent->d_name[0] == '.' ||
+			asprintf(&mem_buffer,
+				"%s",
+				dirent->d_name) < 0) {
+			/* asprintf must be last condition so when it */
+			/* evaluates mem_buffer gets allocated */
+			free(namelist[i]);
+			continue;
+		}
+
+		if (strstr(mem_buffer, "memory-buffer")) {
+			found = true;
+			if (asprintf(&mba_path,
+				"%s/%s",
+				DT_FS_PATH,
+				mem_buffer) < 0 ) {
+				fwts_log_nl(fw);
+				fwts_failed(fw, LOG_LEVEL_CRITICAL,
+						"OPAL MEM Info",
+						"Internal"
+						" processing problem at"
+						" mem_buffer \"%s\", please"
+						" check the system for"
+						" setup issues.",
+						mem_buffer);
+				free(mem_buffer);
+				free(namelist[i]);
+				continue;
+			}
+			if (process_mba(fw, "mba", mba_path)) {
+				failures ++;
+			}
+			free(mem_buffer);
+			free(namelist[i]);
+		}
+	}
+	free(namelist);
+
+	fwts_log_nl(fw);
+	fwts_log_info(fw, "ENDING checks of MEM devices");
+	fwts_log_nl(fw);
+
+	if (!found) {
+		failures ++;
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+				"OPAL MEM Info",
+				"No MEM devices (memory-buffer@X) were found"
+				" in \"%s\".  Check the system for setup"
+				" issues.",
+				DT_FS_PATH);
+	}
+
+	if (failures) {
+		return FWTS_ERROR;
+	} else {
+		return FWTS_OK;
+	}
+
+}
+
+static int mem_info_test1(fwts_framework *fw)
+{
+
+	if (get_linux_mem_devices(fw)) {
+
+		/* errors logged earlier */
+		return FWTS_ERROR;
+	} else {
+		return FWTS_OK;
+	}
+}
+
+static int mem_info_init(fwts_framework *fw)
+{
+	if (fw->firmware_type != FWTS_FIRMWARE_OPAL) {
+		fwts_skipped(fw,
+			"The firmware type detected was not set"
+			" to OPAL so skipping the OPAL PCI Info"
+			" checks.");
+		return FWTS_SKIP;
+	} else {
+		return FWTS_OK;
+	}
+}
+
+static fwts_framework_minor_test mem_info_tests[] = {
+	{ mem_info_test1, "OPAL MEM Info" },
+	{ NULL, NULL }
+};
+
+static fwts_framework_ops mem_info_ops = {
+	.description = "OPAL MEM Info",
+	.init        = mem_info_init,
+	.minor_tests = mem_info_tests
+};
+
+FWTS_REGISTER_FEATURES("mem_info", &mem_info_ops, FWTS_TEST_ANYTIME,
+		FWTS_FLAG_BATCH | FWTS_FLAG_ROOT_PRIV,
+		FWTS_FW_FEATURE_DEVICETREE);