From 8704c9c80e8b129f78bc1416001fd74ba6d0f7d0 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Fri, 26 Apr 2024 15:32:27 +0200 Subject: [PATCH] zpcictl: Pull SCLP handling out and into libzpci MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upcoming optics monitoring tool will have to issue SCLP Write Event data just like zpcictl so pull that functionality out and into libzpci. While at it decouple getting SMART data from the actual SCLP handling. No change in behavior intended. Signed-off-by: Niklas Schnelle Signed-off-by: Jan Höppner --- include/lib/pci_sclp.h | 53 ++++++++++++++++++++++++++++++++++++ libzpci/Makefile | 2 +- libzpci/pci_sclp.c | 61 ++++++++++++++++++++++++++++++++++++++++++ zpcictl/Makefile | 2 +- zpcictl/zpcictl.c | 48 ++++++++------------------------- zpcictl/zpcictl.h | 27 +------------------ 6 files changed, 128 insertions(+), 65 deletions(-) create mode 100644 include/lib/pci_sclp.h create mode 100644 libzpci/pci_sclp.c diff --git a/include/lib/pci_sclp.h b/include/lib/pci_sclp.h new file mode 100644 index 00000000..8713e897 --- /dev/null +++ b/include/lib/pci_sclp.h @@ -0,0 +1,53 @@ +/** + * @defgroup pci_sclp_h libzpci: zPCI device handling + * @{ + * @brief Issue SCLPs for zPCI devices + * + * Copyright IBM Corp. 2024 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef LIB_ZPCI_PCI_SCLP_H +#define LIB_ZPCI_PCI_SCLP_H + +#include +#include + +#include "lib/zt_common.h" + +#define SCLP_ERRNOTIFY_AQ_RESET 0 +#define SCLP_ERRNOTIFY_AQ_DECONF 1 +#define SCLP_ERRNOTIFY_AQ_REPORT_ERR 2 + +#define SCLP_ERRNOTIFY_ID_ZPCICTL 0x4713 + +#define SCLP_ERRNOTIFY_DATA_SIZE 4054 + +struct zpci_report_error_header { + __u8 version; /* Interface version byte */ + __u8 action; /* Action qualifier byte + * 0: Adapter Reset Request + * 1: Deconfigure and repair action requested + * 2: Informational Report + */ + __u16 length; /* Length of Subsequent Data (up to 4K – SCLP header) */ +} __packed; + +struct zpci_report_error_data { + __u64 timestamp; + __u64 err_log_id; + /* We cannot exceed a total of 4074 bytes (header + data) */ + char log_data[SCLP_ERRNOTIFY_DATA_SIZE]; +} __packed; + +struct zpci_report_error { + struct zpci_report_error_header header; + struct zpci_report_error_data data; +} __packed; + +int zpci_sclp_issue_action(char *pci_addr, int action, + char *data, size_t length, u64 err_log_id); + +#endif /* LIB_ZPCI_PCI_SCLP_H */ diff --git a/libzpci/Makefile b/libzpci/Makefile index 344f32b4..f5a83cf8 100644 --- a/libzpci/Makefile +++ b/libzpci/Makefile @@ -4,7 +4,7 @@ lib = libzpci.a all: $(lib) -objects = pci_list.o +objects = pci_list.o pci_sclp.o examples := $(patsubst %.c,%,$(wildcard *_example.c)) diff --git a/libzpci/pci_sclp.c b/libzpci/pci_sclp.c new file mode 100644 index 00000000..90ac0f25 --- /dev/null +++ b/libzpci/pci_sclp.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lib/pci_sclp.h" +#include "lib/util_path.h" + +static int zpci_sclp_report(char *pci_addr, struct zpci_report_error *report) +{ + size_t r_size = sizeof(*report); + char *path; + FILE *fp; + + path = util_path_sysfs("bus/pci/devices/%s/report_error", pci_addr); + fp = fopen(path, "w"); + free(path); + if (!fp) + return -ENODEV; + if (fwrite(report, 1, r_size, fp) != r_size) + return -EIO; + if (fclose(fp)) + return -EIO; + return 0; +} + +/** + * Issue an SCLP Adapter Error Notification event with a specific action + * qualifier and optional log data. + * + * The logged data is truncated if needed. + * + * @return the number of bytes of the data which were actually logged + * or a negative value on error. + */ +int zpci_sclp_issue_action(char *pci_addr, int action, + char *data, size_t length, u64 err_log_id) +{ + struct zpci_report_error report = {0}; + size_t copy_length = 0; + int ret; + + /* Data is truncated to fit in the report */ + if (data) + copy_length = MIN(length, sizeof(report.data.log_data)); + report.header.version = 1; + report.header.action = action; + report.header.length = offsetof(struct zpci_report_error_data, log_data) + copy_length; + report.data.timestamp = (__u64)time(NULL); + report.data.err_log_id = err_log_id; + + if (data) + memcpy(report.data.log_data, data, copy_length); + ret = zpci_sclp_report(pci_addr, &report); + if (ret) + return ret; + return copy_length; +} diff --git a/zpcictl/Makefile b/zpcictl/Makefile index 2b315c5c..9f9ae5cf 100644 --- a/zpcictl/Makefile +++ b/zpcictl/Makefile @@ -2,7 +2,7 @@ include ../common.mak all: zpcictl -libs = $(rootdir)/libutil/libutil.a +libs = $(rootdir)/libzpci/libzpci.a $(rootdir)/libutil/libutil.a zpcictl: zpcictl.o $(libs) diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c index 8f27f577..d693f737 100644 --- a/zpcictl/zpcictl.c +++ b/zpcictl/zpcictl.c @@ -9,20 +9,17 @@ #include #include -#include #include #include #include -#include "lib/util_base.h" #include "lib/util_libc.h" #include "lib/util_opt.h" #include "lib/util_path.h" #include "lib/util_prg.h" -#include "lib/util_proc.h" -#include "lib/util_rec.h" #include "lib/util_scandir.h" #include "lib/util_sys.h" +#include "lib/pci_sclp.h" #include "zpcictl.h" @@ -224,25 +221,6 @@ static void sysfs_write_value(struct zpci_device *pdev, const char *attr, free(path); } -static void sysfs_report_error(struct zpci_report_error *report, char *slot) -{ - size_t r_size; - char *path; - FILE *fp; - - r_size = sizeof(*report); - - path = util_path_sysfs("bus/pci/devices/%s/report_error", slot); - fp = fopen(path, "w"); - if (!fp) - fopen_err(path); - if (fwrite(report, 1, r_size, fp) != r_size) - fwrite_err(fp, path); - if (fclose(fp)) - fclose_err(path); - free(path); -} - static void get_device_node(struct zpci_device *pdev) { struct dirent **de_vec; @@ -326,26 +304,22 @@ static void get_device_info(struct zpci_device *pdev, char *dev) */ static void sclp_issue_action(struct zpci_device *pdev, int action) { - struct zpci_report_error report = { - .header = { 0 }, - .data = { 0 } - }; char *sdata = NULL; - - report.header.version = 1; - report.header.action = action; - report.header.length = offsetof(struct zpci_report_error_data, log_data); - report.data.timestamp = (__u64)time(NULL); - report.data.err_log_id = 0x4713; + int length = 0; + int ret; if (pdev->class == PCI_CLASS_NVME) sdata = collect_smart_data(pdev); if (sdata) { - report.header.length += util_strlcpy(report.data.log_data, sdata, - sizeof(report.data.log_data)); - free(sdata); + /* Account for and ensure '\0' byte */ + length = MIN((int)strlen(sdata) + 1, SCLP_ERRNOTIFY_DATA_SIZE); + sdata[length - 1] = '\0'; } - sysfs_report_error(&report, pdev->slot); + ret = zpci_sclp_issue_action(pdev->slot, action, + sdata, length, SCLP_ERRNOTIFY_ID_ZPCICTL); + free(sdata); + if (ret < 0) + warn("Could not issue SCLP action"); } /* diff --git a/zpcictl/zpcictl.h b/zpcictl/zpcictl.h index 7b34ebb1..449505c0 100644 --- a/zpcictl/zpcictl.h +++ b/zpcictl/zpcictl.h @@ -11,11 +11,8 @@ #define ZPCICTL_H #include -#include "lib/zt_common.h" -#define SCLP_ERRNOTIFY_AQ_RESET 0 -#define SCLP_ERRNOTIFY_AQ_DECONF 1 -#define SCLP_ERRNOTIFY_AQ_REPORT_ERR 2 +#include "lib/zt_common.h" #define PCI_CLASS_UNCLASSIFIED 0x000000U #define PCI_CLASS_NVME 0x010802U @@ -36,26 +33,4 @@ struct zpci_device { char *device; }; -struct zpci_report_error_header { - __u8 version; /* Interface version byte */ - __u8 action; /* Action qualifier byte - * 0: Adapter Reset Request - * 1: Deconfigure and repair action requested - * 2: Informational Report - */ - __u16 length; /* Length of Subsequent Data (up to 4K – SCLP header) */ - __u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ -}; - -struct zpci_report_error_data { - __u64 timestamp; - __u64 err_log_id; - char log_data[4054]; /* We cannot exceed a total of 4074 bytes (header + data) */ -}; - -struct zpci_report_error { - struct zpci_report_error_header header; - struct zpci_report_error_data data; -} __packed; - #endif /* ZPCICTL_H */