Blame opae-libs/plugins/xfpga/error.c

Packit 534379
// Copyright(c) 2018-2020, Intel Corporation
Packit 534379
//
Packit 534379
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 534379
// modification, are permitted provided that the following conditions are met:
Packit 534379
//
Packit 534379
// * Redistributions of  source code  must retain the  above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer.
Packit 534379
// * Redistributions in binary form must reproduce the above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer in the documentation
Packit 534379
//   and/or other materials provided with the distribution.
Packit 534379
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 534379
//   may be used to  endorse or promote  products derived  from this  software
Packit 534379
//   without specific prior written permission.
Packit 534379
//
Packit 534379
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 534379
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 534379
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 534379
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 534379
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 534379
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 534379
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 534379
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 534379
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 534379
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 534379
// POSSIBILITY OF SUCH DAMAGE.
Packit 534379
Packit 534379
#ifdef HAVE_CONFIG_H
Packit 534379
#include <config.h>
Packit 534379
#endif // HAVE_CONFIG_H
Packit 534379
Packit 534379
#include <sys/stat.h>
Packit 534379
#include <unistd.h>
Packit 534379
#include <dirent.h>
Packit 534379
#include <stdio.h>
Packit 534379
Packit 534379
#include "common_int.h"
Packit 534379
#include "opae/error.h"
Packit 534379
Packit 534379
#include "error_int.h"
Packit 534379
Packit 534379
#define INJECT_ERROR "inject_error"
Packit 534379
Packit 534379
fpga_result __XFPGA_API__ xfpga_fpgaReadError(fpga_token token, uint32_t error_num, uint64_t *value)
Packit 534379
{
Packit 534379
	struct _fpga_token *_token = (struct _fpga_token *)token;
Packit 534379
	struct stat st;
Packit 534379
	uint32_t i = 0;
Packit 534379
	fpga_result res = FPGA_OK;
Packit 534379
Packit 534379
	ASSERT_NOT_NULL(token);
Packit 534379
	if (_token->magic != FPGA_TOKEN_MAGIC) {
Packit 534379
		OPAE_MSG("Invalid token");
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	struct error_list *p = _token->errors;
Packit 534379
	while (p) {
Packit 534379
		if (i == error_num) {
Packit 534379
			// test if file exists
Packit 534379
			if (stat(p->error_file, &st) == -1) {
Packit 534379
				OPAE_MSG("can't stat %s", p->error_file);
Packit 534379
				return FPGA_EXCEPTION;
Packit 534379
			}
Packit 534379
			res = sysfs_read_u64(p->error_file, value);
Packit 534379
			if (res != FPGA_OK) {
Packit 534379
				OPAE_MSG("can't read error file '%s'", p->error_file);
Packit 534379
				return res;
Packit 534379
			}
Packit 534379
Packit 534379
			return FPGA_OK;
Packit 534379
		}
Packit 534379
		i++;
Packit 534379
		p = p->next;
Packit 534379
	}
Packit 534379
Packit 534379
	OPAE_MSG("error %d not found", error_num);
Packit 534379
	return FPGA_NOT_FOUND;
Packit 534379
}
Packit 534379
Packit 534379
fpga_result __XFPGA_API__
Packit 534379
xfpga_fpgaClearError(fpga_token token, uint32_t error_num)
Packit 534379
{
Packit 534379
	struct _fpga_token *_token = (struct _fpga_token *)token;
Packit 534379
	struct stat st;
Packit 534379
	uint32_t i = 0;
Packit 534379
	uint64_t value = 0;
Packit 534379
	fpga_result res = FPGA_OK;
Packit 534379
Packit 534379
	ASSERT_NOT_NULL(token);
Packit 534379
	if (_token->magic != FPGA_TOKEN_MAGIC) {
Packit 534379
		OPAE_MSG("Invalid token");
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	struct error_list *p = _token->errors;
Packit 534379
	while (p) {
Packit 534379
		if (i == error_num) {
Packit 534379
			if (!p->info.can_clear) {
Packit 534379
				OPAE_MSG("can't clear error '%s'", p->info.name);
Packit 534379
				return FPGA_NOT_SUPPORTED;
Packit 534379
			}
Packit 534379
Packit 534379
			if (strcmp(p->info.name, INJECT_ERROR) == 0) {
Packit 534379
				value = 0;
Packit 534379
			} else {
Packit 534379
				// read current error value
Packit 534379
				res = xfpga_fpgaReadError(token, error_num, &value);
Packit 534379
				if (res != FPGA_OK)
Packit 534379
					return res;
Packit 534379
			}
Packit 534379
Packit 534379
			// write to 'clear' file
Packit 534379
			if (stat(p->clear_file, &st) == -1) {
Packit 534379
				OPAE_MSG("can't stat %s", p->clear_file);
Packit 534379
				return FPGA_EXCEPTION;
Packit 534379
			}
Packit 534379
			res = sysfs_write_u64(p->clear_file, value);
Packit 534379
			if (res != FPGA_OK) {
Packit 534379
				OPAE_MSG("can't write clear file '%s'", p->clear_file);
Packit 534379
				return res;
Packit 534379
			}
Packit 534379
			return FPGA_OK;
Packit 534379
		}
Packit 534379
		i++;
Packit 534379
		p = p->next;
Packit 534379
	}
Packit 534379
Packit 534379
	OPAE_MSG("error info %d not found", error_num);
Packit 534379
	return FPGA_NOT_FOUND;
Packit 534379
}
Packit 534379
Packit 534379
fpga_result __XFPGA_API__ xfpga_fpgaClearAllErrors(fpga_token token)
Packit 534379
{
Packit 534379
	struct _fpga_token *_token = (struct _fpga_token *)token;
Packit 534379
	uint32_t i = 0;
Packit 534379
	fpga_result res = FPGA_OK;
Packit 534379
Packit 534379
	ASSERT_NOT_NULL(token);
Packit 534379
	if (_token->magic != FPGA_TOKEN_MAGIC) {
Packit 534379
		OPAE_MSG("Invalid token");
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	struct error_list *p = _token->errors;
Packit 534379
	while (p) {
Packit 534379
		// if error can be cleared
Packit 534379
		if (p->info.can_clear) {
Packit 534379
			// clear error
Packit 534379
			res = xfpga_fpgaClearError(token, i);
Packit 534379
			if (res != FPGA_OK)
Packit 534379
				return res;
Packit 534379
		}
Packit 534379
		i++;
Packit 534379
		p = p->next;
Packit 534379
	}
Packit 534379
Packit 534379
	return FPGA_OK;
Packit 534379
}
Packit 534379
Packit 534379
fpga_result __XFPGA_API__ xfpga_fpgaGetErrorInfo(fpga_token token,
Packit 534379
			     uint32_t error_num,
Packit 534379
			     struct fpga_error_info *error_info)
Packit 534379
{
Packit 534379
	struct _fpga_token *_token = (struct _fpga_token *)token;
Packit 534379
	uint32_t i = 0;
Packit 534379
Packit 534379
	if (!error_info) {
Packit 534379
		OPAE_MSG("error_info is NULL");
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	ASSERT_NOT_NULL(token);
Packit 534379
	if (_token->magic != FPGA_TOKEN_MAGIC) {
Packit 534379
		OPAE_MSG("Invalid token");
Packit 534379
		return FPGA_INVALID_PARAM;
Packit 534379
	}
Packit 534379
Packit 534379
	struct error_list *p = _token->errors;
Packit 534379
	while (p) {
Packit 534379
		if (i == error_num) {
Packit 534379
			memcpy(error_info, &p->info, sizeof(struct fpga_error_info));
Packit 534379
			return FPGA_OK;
Packit 534379
		}
Packit 534379
		i++;
Packit 534379
		p = p->next;
Packit 534379
	}
Packit 534379
Packit 534379
	OPAE_MSG("error info %d not found", error_num);
Packit 534379
	return FPGA_NOT_FOUND;
Packit 534379
}
Packit 534379
Packit 534379
/* files and directories to ignore when looking for errors */
Packit 534379
#define NUM_ERRORS_EXCLUDE 4
Packit 534379
const char *errors_exclude[NUM_ERRORS_EXCLUDE] = {
Packit 534379
	"revision",
Packit 534379
	"uevent",
Packit 534379
	"power",
Packit 534379
	"clear"
Packit 534379
};
Packit 534379
Packit 534379
/* files that can be cleared by writing their value to them */
Packit 534379
#define NUM_ERRORS_CLEARABLE 6
Packit 534379
const char *errors_clearable[] = {
Packit 534379
	"pcie0_errors",
Packit 534379
	"pcie1_errors",
Packit 534379
	"warning_errors",
Packit 534379
	"inject_error",
Packit 534379
	"fme_errors",
Packit 534379
	"errors"
Packit 534379
};
Packit 534379
Packit 534379
/* Walks the given directory and adds error entries to `list`.
Packit 534379
 * This function is called during enumeration when adding tokens to
Packit 534379
 * the global tokens list. When tokens are cloned, their error
Packit 534379
 * lists are only shallowly copied (which works because errors of
Packit 534379
 * a token never change).
Packit 534379
 * Note that build_error_list() does not check for dupliates; if
Packit 534379
 * called again on the same list, it will add all found errors again.
Packit 534379
 * Returns the number of error entries added to `list` */
Packit 534379
uint32_t
Packit 534379
build_error_list(const char *path, struct error_list **list)
Packit 534379
{
Packit 534379
	struct dirent *de;
Packit 534379
	DIR *dir;
Packit 534379
	struct stat st;
Packit 534379
	char basedir[FILENAME_MAX] = { 0, };
Packit 534379
	int len;
Packit 534379
	int subpath_len = 0;
Packit 534379
	uint32_t n = 0;
Packit 534379
	unsigned int i;
Packit 534379
	struct error_list **el = list;
Packit 534379
Packit 534379
	len = strnlen(path, FILENAME_MAX - 1);
Packit 534379
Packit 534379
	// add 3 to the len
Packit 534379
	// 1 for the '/' char
Packit 534379
	// 1 for the minimum length of a file appended
Packit 534379
	// 1 for null string to terminate
Packit 534379
	// if we go over now, then leave without doing anything else
Packit 534379
	if (len+3 > FILENAME_MAX) {
Packit 534379
		OPAE_MSG("path too long");
Packit 534379
		return 0;
Packit 534379
	}
Packit 534379
Packit 534379
	len = snprintf(basedir, sizeof(basedir),
Packit 534379
		       "%s/", path);
Packit 534379
Packit 534379
	// now we've added one to length
Packit 534379
Packit 534379
	dir = opendir(path);
Packit 534379
	if (!dir) {
Packit 534379
		OPAE_MSG("unable to open %s", path);
Packit 534379
		return 0;
Packit 534379
	}
Packit 534379
Packit 534379
	while ((de = readdir(dir))) {
Packit 534379
		size_t blen;
Packit 534379
		size_t dlen;
Packit 534379
Packit 534379
		// skip hidden ('.*') files (includes "." and "..")
Packit 534379
		if (de->d_name[0] == '.')
Packit 534379
			continue;
Packit 534379
Packit 534379
		// skip names on blacklist
Packit 534379
		for (i = 0; i < NUM_ERRORS_EXCLUDE; i++) {
Packit 534379
			if (strcmp(de->d_name, errors_exclude[i]) == 0) {
Packit 534379
				break;
Packit 534379
			}
Packit 534379
		}
Packit 534379
		if (i < NUM_ERRORS_EXCLUDE)
Packit 534379
			continue;
Packit 534379
Packit 534379
		subpath_len = strnlen(de->d_name, sizeof(de->d_name) - 1);
Packit 534379
Packit 534379
		// check if the result abs path is longer than  our max
Packit 534379
		if (len + subpath_len > FILENAME_MAX) {
Packit 534379
			OPAE_MSG("Error path length is too long");
Packit 534379
			continue;
Packit 534379
		}
Packit 534379
Packit 534379
		// build absolute path
Packit 534379
		// dmax (arg2) is restricted max length of resulting dest,
Packit 534379
		// including null - it must also be at least smax+1 (arg4)
Packit 534379
		strncpy(basedir + len, de->d_name, subpath_len + 1);
Packit 534379
Packit 534379
		// try accessing file/dir
Packit 534379
		if (lstat(basedir, &st) == -1) {
Packit 534379
			OPAE_MSG("can't stat %s", basedir);
Packit 534379
			continue;
Packit 534379
		}
Packit 534379
Packit 534379
		// skip symlinks
Packit 534379
		if (S_ISLNK(st.st_mode))
Packit 534379
			continue;
Packit 534379
Packit 534379
		// recursively dive into subdirectories
Packit 534379
		if (S_ISDIR(st.st_mode)) {
Packit 534379
			n += build_error_list(basedir, el);
Packit 534379
			continue;
Packit 534379
		}
Packit 534379
Packit 534379
		// not blacklisted, not hidden, accessible, no symlink, no dir -> count and append it!
Packit 534379
		n++;
Packit 534379
		if (!el)	// no list
Packit 534379
			continue;
Packit 534379
Packit 534379
		// append error info to list
Packit 534379
		struct error_list *new_entry = malloc(sizeof(struct error_list));
Packit 534379
		if (!new_entry) {
Packit 534379
			OPAE_MSG("can't allocate memory");
Packit 534379
			n--;
Packit 534379
			break;
Packit 534379
		}
Packit 534379
Packit 534379
		dlen = strnlen(de->d_name, sizeof(new_entry->info.name) - 1);
Packit 534379
		memcpy(new_entry->info.name, de->d_name, dlen);
Packit 534379
		new_entry->info.name[dlen] = '\0';
Packit 534379
Packit 534379
		blen = strnlen(basedir, sizeof(new_entry->error_file) - 1);
Packit 534379
		memcpy(new_entry->error_file, basedir, blen);
Packit 534379
		new_entry->error_file[blen] = '\0';
Packit 534379
Packit 534379
		new_entry->next = NULL;
Packit 534379
		// Errors can be cleared:
Packit 534379
		//   * if the name is "errors" and there is a file called "clear" (generic case), OR
Packit 534379
		//   * if the name is in the "errors_clearable" table
Packit 534379
		new_entry->info.can_clear = false;
Packit 534379
		if (strcmp(de->d_name, "errors") == 0 &&
Packit 534379
			!stat(FPGA_SYSFS_CLASS_PATH_INTEL, &st)) {
Packit 534379
			strncpy(basedir + len, "clear", 6);
Packit 534379
			// try accessing clear file
Packit 534379
			if (lstat(basedir, &st) != -1) {
Packit 534379
				new_entry->info.can_clear = true;
Packit 534379
				memcpy(new_entry->clear_file, basedir, blen);
Packit 534379
				new_entry->clear_file[blen] = '\0';
Packit 534379
			}
Packit 534379
		} else {
Packit 534379
			for (i = 0; i < NUM_ERRORS_CLEARABLE; i++) {
Packit 534379
				if (strcmp(de->d_name, errors_clearable[i]) == 0) {
Packit 534379
					memcpy(basedir + len, de->d_name, dlen);
Packit 534379
					*(basedir + len + dlen) = '\0';
Packit 534379
					// try accessing clear file
Packit 534379
					if (lstat(basedir, &st) != -1) {
Packit 534379
						new_entry->info.can_clear = true;
Packit 534379
						memcpy(new_entry->clear_file, basedir, blen);
Packit 534379
						new_entry->clear_file[blen] = '\0';
Packit 534379
					}
Packit 534379
				}
Packit 534379
			}
Packit 534379
		}
Packit 534379
Packit 534379
		if (new_entry && !new_entry->info.can_clear) {
Packit 534379
			memset(new_entry->clear_file, 0, sizeof(new_entry->clear_file));
Packit 534379
		}
Packit 534379
Packit 534379
		// find end of list
Packit 534379
		while (*el)
Packit 534379
			el = &(*el)->next;
Packit 534379
Packit 534379
		// append
Packit 534379
		if (new_entry)
Packit 534379
			*el = new_entry;
Packit 534379
		el = &new_entry->next;
Packit 534379
	}
Packit 534379
	closedir(dir);
Packit 534379
Packit 534379
	return n;
Packit 534379
}
Packit 534379
Packit 534379
uint32_t count_error_files(const char *path)
Packit 534379
{
Packit 534379
	return build_error_list(path, NULL);
Packit 534379
}