public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
To: git-commits@fedoraproject.org
Subject: [rpms/s390utils] rawhide: - rebased to 2.44.0 (rhbz#2509807)
Date: Fri, 31 Jul 2026 15:24:15 GMT	[thread overview]
Message-ID: <178551145592.1.14776496512583733006.rpms-s390utils-a05200ed603b@fedoraproject.org> (raw)

A new commit has been pushed.

Repo   : rpms/s390utils
Branch : rawhide
Commit : a05200ed603b98b46e4421c3cb132322b463a810
Author : Dan Horák <dan@danny.cz>
Date   : 2026-07-31T15:23:18+00:00
Stats  : +9/-3382 in 4 file(s)
URL    : https://src.fedoraproject.org/rpms/s390utils/c/a05200ed603b98b46e4421c3cb132322b463a810?branch=rawhide

Log:
- rebased to 2.44.0 (rhbz#2509807)

---
diff --git a/s390utils-2.43.1-fedora.patch b/s390utils-2.43.1-fedora.patch
deleted file mode 100644
index 5c7544b..0000000
--- a/s390utils-2.43.1-fedora.patch
+++ /dev/null
@@ -1,3374 +0,0 @@
-From 9d9fca6e72321fa83e2908f29ebe192257085833 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Jan=20H=C3=B6ppner?= <hoeppner@linux.ibm.com>
-Date: Wed, 22 Jul 2026 18:33:53 +0200
-Subject: [PATCH 01/23] Prepare for next release
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- CHANGELOG.md | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/CHANGELOG.md b/CHANGELOG.md
-index 8da80dd0..97fa3457 100644
---- a/CHANGELOG.md
-+++ b/CHANGELOG.md
-@@ -1,6 +1,16 @@
- Release history for s390-tools (MIT version)
- --------------------------------------------
- 
-+* __v2.xx.x (20xx-xx-xx)__
-+
-+  For Linux kernel version: 7.x
-+
-+  Add new tools / libraries:
-+
-+  Changes of existing tools:
-+
-+  Bug Fixes:
-+
- * __v2.43.1 (2026-07-22)__
- 
-   For Linux kernel version: 7.1
--- 
-2.55.0
-
-
-From e55e0e470a27cc224502fd3969fc99de677fc13c Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 16 Apr 2026 14:05:37 +0200
-Subject: [PATCH 02/23] opticsmon: Fix wrong JSON print for tx_fault
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The "tx_fault" field in the JSON output accidentally contained the
-rx_los value instead of the tx_fault one. Change it to the correct
-value. Note that this does not impact the data relayed to firmware as
-that uses the raw module data.
-
-Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool")
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/opticsmon.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c
-index ebae75ad..5a52f8a8 100644
---- a/opticsmon/opticsmon.c
-+++ b/opticsmon/opticsmon.c
-@@ -143,7 +143,7 @@ static void optics_json_print(struct opticsmon_ctx *ctx, struct zpci_netdev *nd,
- 	util_fmt_pair(FMT_QUOTE, "type", optics_type_str(optics_type(oi)));
- 	util_fmt_pair(FMT_QUOTE, "rx_los", optics_los_str(optics_rx_los(oi)));
- 	util_fmt_pair(FMT_QUOTE, "tx_los", optics_los_str(optics_tx_los(oi)));
--	util_fmt_pair(FMT_QUOTE, "tx_fault", optics_los_str(optics_rx_los(oi)));
-+	util_fmt_pair(FMT_QUOTE, "tx_fault", optics_los_str(optics_tx_fault(oi)));
- 	if (ctx->opts.module_info)
- 		module_info_pair(oi);
- 	util_fmt_obj_end();
--- 
-2.55.0
-
-
-From 905c3921af31b096149738a448e5e0120f538fb2 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 16 Apr 2026 13:47:58 +0200
-Subject: [PATCH 03/23] opticsmon: Close epoll fd in monitor_wait_loop()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The epoll fd (epfd) in monitor_wait_loop() is never closed. Close it in
-all return paths. Also there is no explicit check for an error return of
-epoll_create1() add that too.
-
-Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool")
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/opticsmon.c | 25 +++++++++++++++----------
- 1 file changed, 15 insertions(+), 10 deletions(-)
-
-diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c
-index 5a52f8a8..a7fa9fc2 100644
---- a/opticsmon/opticsmon.c
-+++ b/opticsmon/opticsmon.c
-@@ -271,54 +271,57 @@ void on_link_change(struct zpci_netdev *netdev, void *arg)
- static int monitor_wait_loop(struct opticsmon_ctx *ctx, int sigfd, int timerfd)
- {
- 	struct epoll_event events[MAX_EVENTS];
-+	int i, nlfd, epfd, nfds, ret = -EIO;
- 	struct signalfd_siginfo fdsi;
--	int i, nlfd, epfd, nfds;
- 	struct epoll_event ev;
- 	uint64_t expirations;
- 	ssize_t sread;
- 
- 	epfd = epoll_create1(EPOLL_CLOEXEC);
-+	if (epfd < 0)
-+		return -EIO;
- 
- 	ev.events = EPOLLIN;
- 	ev.data.fd = sigfd;
- 	if (epoll_ctl(epfd, EPOLL_CTL_ADD, sigfd, &ev) == -1)
--		return -EIO;
-+		goto out_close;
- 
- 	ev.events = EPOLLIN;
- 	ev.data.fd = timerfd;
- 	if (epoll_ctl(epfd, EPOLL_CTL_ADD, timerfd, &ev) == -1)
--		return -EIO;
-+		goto out_close;
- 
- 	nlfd = link_mon_nl_waitfd_getfd(&ctx->lctx);
- 	ev.events = EPOLLIN;
- 	ev.data.fd = nlfd;
- 	if (epoll_ctl(epfd, EPOLL_CTL_ADD, nlfd, &ev) == -1)
--		return -EIO;
-+		goto out_close;
- 
- 	while (1) {
- 		nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
- 		if (nfds < 0)
--			return nfds;
-+			goto out_close;
- 		for (i = 0; i < nfds; i++) {
- 			/* signal fd */
- 			if (events[i].data.fd == sigfd) {
- 				sread = read(sigfd, &fdsi, sizeof(fdsi));
- 				if (sread != sizeof(fdsi))
--					return -EIO;
-+					goto out_close;
- 				switch (fdsi.ssi_signo) {
- 				case SIGINT:
- 				case SIGTERM:
- 				case SIGQUIT:
--					return 0;
-+					ret = 0;
-+					goto out_close;
- 				/* Unexpected signal */
- 				default:
--					return -EIO;
-+					goto out_close;
- 				}
- 				/* timer fd */
- 			} else if (events[i].data.fd == timerfd) {
- 				sread = read(timerfd, &expirations, sizeof(uint64_t));
- 				if (sread != sizeof(uint64_t))
--					return -EIO;
-+					goto out_close;
- 				if (!expirations)
- 					continue;
- 				dump_all_adapter_data(ctx);
-@@ -328,7 +331,9 @@ static int monitor_wait_loop(struct opticsmon_ctx *ctx, int sigfd, int timerfd)
- 			}
- 		}
- 	}
--	return 0;
-+out_close:
-+	close(epfd);
-+	return ret;
- }
- 
- static int monitor_mode(struct opticsmon_ctx *ctx)
--- 
-2.55.0
-
-
-From 1f339a9e7ee60611b5055735a0296326c792b704 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 16 Apr 2026 13:08:27 +0200
-Subject: [PATCH 04/23] opticsmon: Return errors from monitor_wait_loop() in
- monitor_mode()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Don't ignore the return value of monitor_wait_loop() but instead forward
-it to the caller.
-
-Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool")
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/opticsmon.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c
-index a7fa9fc2..6d7595b1 100644
---- a/opticsmon/opticsmon.c
-+++ b/opticsmon/opticsmon.c
-@@ -381,7 +381,7 @@ static int monitor_mode(struct opticsmon_ctx *ctx)
- 		goto close_timerfd;
- 	}
- 
--	monitor_wait_loop(ctx, sigfd, timerfd);
-+	ret = monitor_wait_loop(ctx, sigfd, timerfd);
- 
- 	link_mon_nl_waitfd_destroy(&ctx->lctx);
- 	util_fmt_exit();
--- 
-2.55.0
-
-
-From 6847b6a8cf60510a63c5e4f32ca429ca9f5d24a7 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 16 Apr 2026 11:46:59 +0200
-Subject: [PATCH 05/23] opticsmon: Fix error path free of struct optics in
- ethtool_nl_get_optics()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When ethtool_nl_get_optics() fails after ethtool_nl_cb() has allocated
-oi->raw this memory would leak because only the struct optics* itself
-was freed. Fix this by using optics_free() and relying on free(oi->raw)
-being a no-op for NULL pointers in combination with using util_zalloc()
-to handle errors both before and after oi->raw was allocated.
-
-Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool")
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/ethtool.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/opticsmon/ethtool.c b/opticsmon/ethtool.c
-index 103644a1..a448eb25 100644
---- a/opticsmon/ethtool.c
-+++ b/opticsmon/ethtool.c
-@@ -272,7 +272,7 @@ int ethtool_nl_get_optics(struct ethtool_nl_ctx *ctx, const char *netdev, struct
- 	return rc;
- 
- out_err_free_oi:
--	free(*oi);
-+	optics_free(*oi);
- 	*oi = NULL;
- 	return rc;
- }
--- 
-2.55.0
-
-
-From 3696d6bd0858006bace1819c3ba436491f750c7b Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 16 Apr 2026 14:40:47 +0200
-Subject: [PATCH 06/23] opticsmon: Handle error return of ethtool_nl_connect()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Don't just ignore the return of ethtool_nl_connect(). This would also
-otherwise lead to invalid socket accesses later. Also make
-ethtool_nl_connect() return negative error values instead of
-EXIT_FAILURE.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/ethtool.c   | 6 +++---
- opticsmon/opticsmon.c | 4 +++-
- 2 files changed, 6 insertions(+), 4 deletions(-)
-
-diff --git a/opticsmon/ethtool.c b/opticsmon/ethtool.c
-index a448eb25..ac1a07fb 100644
---- a/opticsmon/ethtool.c
-+++ b/opticsmon/ethtool.c
-@@ -56,13 +56,13 @@ int ethtool_nl_connect(struct ethtool_nl_ctx *ctx)
- 	sk = nl_socket_alloc();
- 	if (!sk) {
- 		nl_perror(NLE_NOMEM, "alloc");
--		return EXIT_FAILURE;
-+		return -ENOMEM;
- 	}
- 
- 	rc = genl_connect(sk);
- 	if (rc) {
- 		nl_perror(rc, "connect");
--		rc = EXIT_FAILURE;
-+		rc = -EIO;
- 		goto err_free;
- 	}
- 
-@@ -72,7 +72,7 @@ int ethtool_nl_connect(struct ethtool_nl_ctx *ctx)
- 			fprintf(stderr, "Ethtool netlink family not found\n");
- 		else
- 			nl_perror(ethtool_id, "ctrl resolve");
--		rc = EXIT_FAILURE;
-+		rc = -EIO;
- 		goto err_close;
- 	}
- 	ctx->sk = sk;
-diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c
-index 6d7595b1..c50275d4 100644
---- a/opticsmon/opticsmon.c
-+++ b/opticsmon/opticsmon.c
-@@ -398,7 +398,9 @@ int main(int argc, char **argv)
- 	int ret;
- 
- 	parse_cmdline(argc, argv, &ctx.opts);
--	ethtool_nl_connect(&ctx.ethtool_ctx);
-+	ret = ethtool_nl_connect(&ctx.ethtool_ctx);
-+	if (ret)
-+		return ret;
- 	if (ctx.opts.monitor)
- 		ret = monitor_mode(&ctx);
- 	else
--- 
-2.55.0
-
-
-From 8b38bf37b06ad81d932f3545330c3daa64695bbe Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 30 Apr 2026 17:13:16 +0200
-Subject: [PATCH 07/23] opticsmon: Fix wrong size check for
- OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The code accesses OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET so the size needs
-to be one larger for the LOS to be accessible.
-
-Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool")
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/optics_info.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/opticsmon/optics_info.c b/opticsmon/optics_info.c
-index fc041da3..00d8d723 100644
---- a/opticsmon/optics_info.c
-+++ b/opticsmon/optics_info.c
-@@ -66,7 +66,7 @@ bool optics_los_implemented(struct optics *oi)
- 	} else if (type == OPTICS_TYPE_QSFP28) {
- 		if (oi->size < OPTICS_QSFP28_LOS_OFFSET + 1)
- 			return false;
--		if (oi->size < OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET)
-+		if (oi->size < OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET + 1)
- 			return false;
- 		implemented = oi->raw[OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET];
- 		/*
--- 
-2.55.0
-
-
-From e7bc4a5d3103f745cad575a3acf48baf27a4d762 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Mon, 4 May 2026 13:41:34 +0200
-Subject: [PATCH 08/23] opticsmon: Enforce 1 second as minimal interval
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-So far it was possible for the user to specify an interval of 0 which
-would result in not re-arming the timer at all thus disabling interval
-based data collection. While this would still do optics data collection
-on startup and link changes the intention is to collect data at least
-every 24 hours. If interval is given as 0 treat this as minimum update
-interval of 1 second.
-
-Fixes: c34adb9cabee ("opticsmon: Introduce opticsmon tool")
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- opticsmon/opticsmon.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/opticsmon/opticsmon.c b/opticsmon/opticsmon.c
-index c50275d4..f86056d4 100644
---- a/opticsmon/opticsmon.c
-+++ b/opticsmon/opticsmon.c
-@@ -96,6 +96,8 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
- 			}
- 			if (seconds < 86400)
- 				opts->interval_seconds = seconds;
-+			if (seconds < 1)
-+				opts->interval_seconds = 1;
- 			break;
- 		case 'h':
- 			util_prg_print_help();
--- 
-2.55.0
-
-
-From e8550a4f8dc61822c1816da5b17d18544868ee06 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Tue, 9 Dec 2025 17:53:57 +0100
-Subject: [PATCH 09/23] opticsmon: zpcimon: Rename opticsmon to zpcimon
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The opticsmon tool started out as a tool for monitoring the health of
-optical modules in directly attached PCI NICs. In the future however it
-will also monitor the health of other PCI devices. In particular in
-a first step it will monitor the health of directly attached NVMe
-devices.
-
-To reflect this broadening of its scope rename opticsmon to zpcimon. Add
-zpcimon.service and install it both under the new name and symlinked as
-opticsmon.service for backwards compatibility. Since users are expected
-to mostly just enable the service this keeps old instructions just
-working.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- .gitignore                                    |  8 +++++---
- Makefile                                      |  2 +-
- README.md                                     | 10 +++++-----
- scripts/dbginfo.sh                            |  2 +-
- systemd/Makefile                              |  5 ++++-
- ...pticsmon.service.in => zpcimon.service.in} |  6 +++---
- {opticsmon => zpcimon}/Makefile               | 20 ++++++++++---------
- .../autocompletion_generator_host.c           |  3 ++-
- {opticsmon => zpcimon}/ethtool.c              |  0
- {opticsmon => zpcimon}/ethtool.h              |  0
- {opticsmon => zpcimon}/link_mon.c             |  0
- {opticsmon => zpcimon}/link_mon.h             |  0
- {opticsmon => zpcimon}/optics_info.c          |  0
- {opticsmon => zpcimon}/optics_info.h          |  0
- {opticsmon => zpcimon}/optics_sclp.c          |  0
- {opticsmon => zpcimon}/optics_sclp.h          |  0
- opticsmon/opticsmon.8 => zpcimon/zpcimon.8    | 10 +++++-----
- opticsmon/opticsmon.c => zpcimon/zpcimon.c    |  5 ++---
- .../opticsmon_cli.h => zpcimon/zpcimon_cli.h  |  0
- 19 files changed, 39 insertions(+), 32 deletions(-)
- rename systemd/{opticsmon.service.in => zpcimon.service.in} (66%)
- rename {opticsmon => zpcimon}/Makefile (79%)
- rename {opticsmon => zpcimon}/autocompletion_generator_host.c (72%)
- rename {opticsmon => zpcimon}/ethtool.c (100%)
- rename {opticsmon => zpcimon}/ethtool.h (100%)
- rename {opticsmon => zpcimon}/link_mon.c (100%)
- rename {opticsmon => zpcimon}/link_mon.h (100%)
- rename {opticsmon => zpcimon}/optics_info.c (100%)
- rename {opticsmon => zpcimon}/optics_info.h (100%)
- rename {opticsmon => zpcimon}/optics_sclp.c (100%)
- rename {opticsmon => zpcimon}/optics_sclp.h (100%)
- rename opticsmon/opticsmon.8 => zpcimon/zpcimon.8 (88%)
- rename opticsmon/opticsmon.c => zpcimon/zpcimon.c (98%)
- rename opticsmon/opticsmon_cli.h => zpcimon/zpcimon_cli.h (100%)
-
-diff --git a/.gitignore b/.gitignore
-index 36a2c851..37ec4d8b 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -102,9 +102,11 @@ lsstp/_lsstp
- lsstp/lsstp.bash
- mon_tools/mon_fsstatd
- mon_tools/mon_procd
--opticsmon/opticsmon
--opticsmon/_opticsmon
--opticsmon/opticsmon.bash
-+zpcimon/zpcimon
-+zpcimon/zpcimon.bash
-+zpcimon/_zpcimon
-+zpcimon/opticsmon.bash
-+zpcimon/_opticsmon
- osasnmpd/osasnmpd
- qetharp/qetharp
- qethqoat/qethqoat
-diff --git a/Makefile b/Makefile
-index 4dbce8cc..5aafb56c 100644
---- a/Makefile
-+++ b/Makefile
-@@ -15,7 +15,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
- 	   vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
- 	   ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
- 	   systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
--	   lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools rust opticsmon \
-+	   lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools rust zpcimon \
- 	   zpwr zmemtopo
- 
- else
-diff --git a/README.md b/README.md
-index 91d61c5a..4045b0f8 100644
---- a/README.md
-+++ b/README.md
-@@ -316,7 +316,7 @@ build options:
- | glibc-static | `HAVE_LIBC_STATIC` | zfcpdump                               |
- | openssl      | `HAVE_OPENSSL`     | zkey, libekmfweb, libkmipclient,       |
- |              |                    | zgetdump, rust/pvattest, rust/pvimg,   |
--|              |                    | zgetdump/pvsecret, opticsmon           |
-+|              |                    | zgetdump/pvsecret, zpcimon             |
- | cryptsetup   | `HAVE_CRYPTSETUP2` | zkey-cryptsetup                        |
- | json-c       | `HAVE_JSONC`       | zkey-cryptsetup, libekmfweb,           |
- |              |                    | libkmipclient                          |
-@@ -326,7 +326,7 @@ build options:
- | libxml2      | `HAVE_LIBXML2`     | libkmipclient                          |
- | systemd      | `HAVE_SYSTEMD`     | hsavmcore                              |
- | libudev      | `HAVE_LIBUDEV`     | cpacfstatsd                            |
--| libnl3       | `HAVE_LIBNL3`      | opticsmon                              |
-+| libnl3       | `HAVE_LIBNL3`      | zpcimon                                |
- 
- This table lists additional build or install options:
- 
-@@ -374,10 +374,10 @@ the different tools are provided:
- 
-   The runtime requirements are: openssl-libs (>= 1.1.1) and libcurl.
- 
--* opticsmon:
--  For building opticsmon OpenSSL and the Netlink Library Suite (libnl3) are
-+* zpcimon:
-+  For building zpcimon OpenSSL and the Netlink Library Suite (libnl3) are
-   required.
--  Tip: you may skip the opticsmon build by adding
-+  Tip: you may skip the zpcimon build by adding
-   `HAVE_OPENSSL=0` or `HAVE_LIBNL3=0`
- 
- * osasnmpd:
-diff --git a/scripts/dbginfo.sh b/scripts/dbginfo.sh
-index e5c35bbf..ec6227f1 100755
---- a/scripts/dbginfo.sh
-+++ b/scripts/dbginfo.sh
-@@ -629,7 +629,7 @@ NETWORK_CMDS="ip -br a\
-   :nstat -az\
-   :openssl engine # deprecated in OpenSSL 3.n\
-   :openssl list --providers 2>/dev/null # redirect help on older systems\
--  :opticsmon --module-info\
-+  :opticsmon --module-info\ # Now called zpcimon but kept for compatibility
-   :route -n\
-   "
- 
-diff --git a/systemd/Makefile b/systemd/Makefile
-index 9388fd9c..29e29b63 100644
---- a/systemd/Makefile
-+++ b/systemd/Makefile
-@@ -4,7 +4,7 @@ SYSTEM_UNITS = ttyrun-getty@.service iucvtty-login@.service \
-                cpacfstatsd.service cpuplugd.service \
-                dumpconf.service cpi.service \
-                mon_fsstatd.service mon_procd.service \
--               opticsmon.service
-+               zpcimon.service
- 
- all:
- 
-@@ -19,6 +19,9 @@ install: system_units
- 	  $(INSTALL) -g $(GROUP) -o $(OWNER) \
- 	             -m 644 $$unit $(DESTDIR)$(SYSTEMDSYSTEMUNITDIR) ; \
- 	done
-+	# Make the legacy opticsmon.service a link to zpcimon.service
-+	ln -sf zpcimon.service \
-+		$(DESTDIR)$(SYSTEMDSYSTEMUNITDIR)/opticsmon.service
- 
- else
- 
-diff --git a/systemd/opticsmon.service.in b/systemd/zpcimon.service.in
-similarity index 66%
-rename from systemd/opticsmon.service.in
-rename to systemd/zpcimon.service.in
-index 335d9165..cf1ea122 100644
---- a/systemd/opticsmon.service.in
-+++ b/systemd/zpcimon.service.in
-@@ -1,5 +1,5 @@
- #
--# Systemd unit for mon_fsstatd (monitor z/VM guest file systems)
-+# Systemd unit for zpcimon PCI NIC optical module monitoring
- #
- # Copyright IBM Corp. 2024
- #
-@@ -9,11 +9,11 @@
- 
- [Unit]
- Description=Monitor health of directly attached PCI NIC optical modules
--# Documentation=man:opticsmon
-+# Documentation=man:zpcimon
- 
- [Service]
- Type=exec
--ExecStart=@usrsbin_path@/opticsmon --send-report --monitor --interval 86400
-+ExecStart=@usrsbin_path@/zpcimon --send-report --monitor --interval 86400
- KillMode=control-group
- 
- [Install]
-diff --git a/opticsmon/Makefile b/zpcimon/Makefile
-similarity index 79%
-rename from opticsmon/Makefile
-rename to zpcimon/Makefile
-index e42b6329..43fc2a04 100644
---- a/opticsmon/Makefile
-+++ b/zpcimon/Makefile
-@@ -2,8 +2,8 @@ include ../common.mak
- 
- TESTS := tests/
- 
--zsh-completions = _opticsmon
--bash-completions = opticsmon.bash
-+zsh-completions = _zpcimon
-+bash-completions = zpcimon.bash
- 
- include ../common_autocomp.mak
- 
-@@ -12,7 +12,7 @@ libs =$(rootdir)/libzpci/libzpci.a $(rootdir)/libutil/libutil.a
- ifneq (${HAVE_OPENSSL},0)
- check_dep_openssl:
- 	$(call check_dep, \
--		"opticsmon", \
-+		"zpcimon", \
- 		"openssl/evp.h", \
- 		"openssl-devel", \
- 		"HAVE_OPENSSL=0")
-@@ -22,7 +22,7 @@ endif # HAVE_OPENSSL
- ifneq (${HAVE_LIBNL3},0)
- check_dep_libnl3:
- 	$(call check_dep, \
--		"opticsmon", \
-+		"zpcimon", \
- 		"netlink/socket.h", \
- 		"libnl3-devel", \
- 		"HAVE_LIBNL3=0")
-@@ -69,20 +69,22 @@ endif
- ALL_CPPFLAGS += $(LIB_CFLAGS)
- LDLIBS += $(LIB_LFLAGS)
- 
--BUILDTARGET += opticsmon
-+BUILDTARGET += zpcimon
- 
- all: ${BUILDTARGET}
- 
--opticsmon: opticsmon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
-+zpcimon: zpcimon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
- 
- install: all
- 	$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
--	$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 opticsmon $(DESTDIR)$(BINDIR)
--	$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 opticsmon.8 \
-+	$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zpcimon $(DESTDIR)$(BINDIR)
-+	$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 zpcimon.8 \
- 		$(DESTDIR)$(MANDIR)/man8
-+	ln -sf zpcimon $(DESTDIR)$(BINDIR)/opticsmon
-+	ln -sf zpcimon.8 $(DESTDIR)$(MANDIR)/man8/opticsmon.8
- endif # HAVE_OPENSSL3=0 or HAVE_LIBNL3=0
- 
- clean:
--	rm -f *.o *~ opticsmon core
-+	rm -f *.o *~ zpcimon core
- 
- .PHONY: all install clean
-diff --git a/opticsmon/autocompletion_generator_host.c b/zpcimon/autocompletion_generator_host.c
-similarity index 72%
-rename from opticsmon/autocompletion_generator_host.c
-rename to zpcimon/autocompletion_generator_host.c
-index 4ce9fdf1..aeefab2f 100644
---- a/opticsmon/autocompletion_generator_host.c
-+++ b/zpcimon/autocompletion_generator_host.c
-@@ -6,10 +6,11 @@
- 
- #include "lib/util_autocomp.h"
- 
--#include "opticsmon_cli.h"
-+#include "zpcimon_cli.h"
- 
- int main(void)
- {
-+	generate_autocomp(opt_vec, "zpcimon");
- 	generate_autocomp(opt_vec, "opticsmon");
- 
- 	return 0;
-diff --git a/opticsmon/ethtool.c b/zpcimon/ethtool.c
-similarity index 100%
-rename from opticsmon/ethtool.c
-rename to zpcimon/ethtool.c
-diff --git a/opticsmon/ethtool.h b/zpcimon/ethtool.h
-similarity index 100%
-rename from opticsmon/ethtool.h
-rename to zpcimon/ethtool.h
-diff --git a/opticsmon/link_mon.c b/zpcimon/link_mon.c
-similarity index 100%
-rename from opticsmon/link_mon.c
-rename to zpcimon/link_mon.c
-diff --git a/opticsmon/link_mon.h b/zpcimon/link_mon.h
-similarity index 100%
-rename from opticsmon/link_mon.h
-rename to zpcimon/link_mon.h
-diff --git a/opticsmon/optics_info.c b/zpcimon/optics_info.c
-similarity index 100%
-rename from opticsmon/optics_info.c
-rename to zpcimon/optics_info.c
-diff --git a/opticsmon/optics_info.h b/zpcimon/optics_info.h
-similarity index 100%
-rename from opticsmon/optics_info.h
-rename to zpcimon/optics_info.h
-diff --git a/opticsmon/optics_sclp.c b/zpcimon/optics_sclp.c
-similarity index 100%
-rename from opticsmon/optics_sclp.c
-rename to zpcimon/optics_sclp.c
-diff --git a/opticsmon/optics_sclp.h b/zpcimon/optics_sclp.h
-similarity index 100%
-rename from opticsmon/optics_sclp.h
-rename to zpcimon/optics_sclp.h
-diff --git a/opticsmon/opticsmon.8 b/zpcimon/zpcimon.8
-similarity index 88%
-rename from opticsmon/opticsmon.8
-rename to zpcimon/zpcimon.8
-index a810792d..3c274b45 100644
---- a/opticsmon/opticsmon.8
-+++ b/zpcimon/zpcimon.8
-@@ -30,20 +30,20 @@
- .  br
- ..
- .
--.TH opticsmon 8 "Oct 2024" s390-tools zpcictl
-+.TH zpcimon 8 "Oct 2024" s390-tools zpcictl
- .
- .SH NAME
--opticsmon - Monitor optical modules for directly attached PCI based NICs
-+zpcimon - Monitor optical modules for directly attached PCI based NICs
- .
- .
- .SH SYNOPSIS
--.B "opticsmon"
-+.B "zpcimon"
- .I "OPTIONS"
- .
- .
- .SH DESCRIPTION
- Use
--.B opticsmon
-+.B zpcimon
- to monitor the health of the optical modules of directly attached PCI based
- NICs. When executed without the \fB--monitor\fR option it will collect optical
- module data from all available PCI network interface physical functions and
-@@ -80,7 +80,7 @@ on".
- 
- .B Example: Extract module information for the first adapter
- 
--.CL opticsmon --module-info | jq -r '.adapters[0].netdevs[0].optics.module_info' | base64 -d | hexdump -C
-+.CL zpcimon --module-info | jq -r '.adapters[0].netdevs[0].optics.module_info' | base64 -d | hexdump -C
- .PP
- .PP
- .
-diff --git a/opticsmon/opticsmon.c b/zpcimon/zpcimon.c
-similarity index 98%
-rename from opticsmon/opticsmon.c
-rename to zpcimon/zpcimon.c
-index f86056d4..7df87e81 100644
---- a/opticsmon/opticsmon.c
-+++ b/zpcimon/zpcimon.c
-@@ -31,7 +31,7 @@
- #include "link_mon.h"
- #include "optics_info.h"
- #include "optics_sclp.h"
--#include "opticsmon_cli.h"
-+#include "zpcimon_cli.h"
- 
- #define API_LEVEL 1
- 
-@@ -52,8 +52,7 @@ struct opticsmon_ctx {
- };
- 
- static const struct util_prg prg = {
--	.desc = "Use opticsmon to monitor the health of the optical modules\n"
--		"of directly attached PCI based NICs",
-+	.desc = "Use zpcimon to monitor the health of PCI devices",
- 	.copyright_vec = { {
- 				   .owner = "IBM Corp.",
- 				   .pub_first = 2024,
-diff --git a/opticsmon/opticsmon_cli.h b/zpcimon/zpcimon_cli.h
-similarity index 100%
-rename from opticsmon/opticsmon_cli.h
-rename to zpcimon/zpcimon_cli.h
--- 
-2.55.0
-
-
-From 8a4a4e05579eb697721b59b8e718cdb1d96aeb5f Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Wed, 17 Jun 2026 21:45:35 +0200
-Subject: [PATCH 10/23] libutil/util_fmt: Add util_fmt_type_to_name()
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add a function to get the textual name of an enum util_fmt_t value. To
-make this robust to changes in the order of elements in the format array
-initialize this using named indices.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- include/lib/util_fmt.h | 10 ++++++++++
- libutil/util_fmt.c     | 30 +++++++++++++++++++++++++-----
- 2 files changed, 35 insertions(+), 5 deletions(-)
-
-diff --git a/include/lib/util_fmt.h b/include/lib/util_fmt.h
-index 1d3b9af9..ac57cd4f 100644
---- a/include/lib/util_fmt.h
-+++ b/include/lib/util_fmt.h
-@@ -157,6 +157,16 @@ void util_fmt_exit(void);
-  */
- bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type);
- 
-+/**
-+ * util_fmt_type_to_name() - Get name of given format type identifier.
-+ * @type: Format type identifier
-+ *
-+ * Get the name corresponding to the given format type identifier.
-+ *
-+ * Return: name of the format type
-+ */
-+const char *util_fmt_type_to_name(enum util_fmt_t type);
-+
- /**
-  * util_fmt_set_indent() - Set indentation parameters.
-  * @base    : Base indentation level to apply to all output lines (default 0)
-diff --git a/libutil/util_fmt.c b/libutil/util_fmt.c
-index 31bbe704..f4e05fae 100644
---- a/libutil/util_fmt.c
-+++ b/libutil/util_fmt.c
-@@ -89,11 +89,26 @@ static const struct {
- 	const char *name;
- 	enum util_fmt_t fmt;
- } formats[] = {
--	{ "json", FMT_JSON },
--	{ "json-seq", FMT_JSONSEQ },
--	{ "jsonl", FMT_JSONL },
--	{ "pairs", FMT_PAIRS },
--	{ "csv",  FMT_CSV },
-+	[FMT_JSON] = {
-+		.name = "json",
-+		.fmt = FMT_JSON
-+	},
-+	[FMT_JSONSEQ] = {
-+		.name = "json-seq",
-+		.fmt = FMT_JSONSEQ
-+	},
-+	[FMT_JSONL] = {
-+		.name = "jsonl",
-+		.fmt = FMT_JSONL
-+	},
-+	[FMT_PAIRS] = {
-+		.name = "pairs",
-+		.fmt = FMT_PAIRS
-+	},
-+	[FMT_CSV] = {
-+		.name = "csv",
-+		.fmt = FMT_CSV
-+	},
- };
- 
- /* Signal mask for blocking INT and TERM signals. */
-@@ -112,6 +127,11 @@ bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type)
- 	return false;
- }
- 
-+const char *util_fmt_type_to_name(enum util_fmt_t type)
-+{
-+	return formats[type].name;
-+}
-+
- bool util_fmt_is_json(enum util_fmt_t type)
- {
- 	switch (type) {
--- 
-2.55.0
-
-
-From 2c63c69af448fd84222645f53aa98cdfd54c7130 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Wed, 17 Jun 2026 21:48:47 +0200
-Subject: [PATCH 11/23] zpcimon: Allow setting output format and use JSON Lines
- in systemd unit
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Introduce separate '--format' option to set output format. Use the new
-JSON Lines format explicitly in the systemd unit. Since JSON Lines
-format only uses printable characters this removes the need for passing
-'-a' to systemctl status. At the same time JSON-SEQ is more easily
-parsable using 'jq --seq' so keep it the default for easier scripting.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- systemd/zpcimon.service.in |  2 +-
- zpcimon/zpcimon.8          |  8 +++++++
- zpcimon/zpcimon.c          | 43 ++++++++++++++++++++++++++++++++++++--
- zpcimon/zpcimon_cli.h      |  9 ++++++++
- 4 files changed, 59 insertions(+), 3 deletions(-)
-
-diff --git a/systemd/zpcimon.service.in b/systemd/zpcimon.service.in
-index cf1ea122..9be0caa4 100644
---- a/systemd/zpcimon.service.in
-+++ b/systemd/zpcimon.service.in
-@@ -13,7 +13,7 @@ Description=Monitor health of directly attached PCI NIC optical modules
- 
- [Service]
- Type=exec
--ExecStart=@usrsbin_path@/zpcimon --send-report --monitor --interval 86400
-+ExecStart=@usrsbin_path@/zpcimon --send-report --monitor --format jsonl --interval 86400
- KillMode=control-group
- 
- [Install]
-diff --git a/zpcimon/zpcimon.8 b/zpcimon/zpcimon.8
-index 3c274b45..9b16fa91 100644
---- a/zpcimon/zpcimon.8
-+++ b/zpcimon/zpcimon.8
-@@ -84,6 +84,14 @@ on".
- .PP
- .PP
- .
-+.SS Output Format Options
-+.OD format "" <FORMAT>
-+Set the output format out of json, json-seq, jsonl, pairs, and csv. Note that
-+only json-seq and jsonl sequence formats are supported for monitoring mode as
-+they handle a continuous stream of updates well. While they are not supported
-+in query mode.
-+.PP
-+.
- .SS General Options
- .OD help "h" ""
- Print usage information, then exit.
-diff --git a/zpcimon/zpcimon.c b/zpcimon/zpcimon.c
-index 7df87e81..98a2871a 100644
---- a/zpcimon/zpcimon.c
-+++ b/zpcimon/zpcimon.c
-@@ -40,6 +40,8 @@ struct options {
- 	bool report;
- 	bool module_info;
- 	bool quiet;
-+	enum util_fmt_t format;
-+	bool explicit_format;
- 
- 	uint32_t interval_seconds;
- };
-@@ -63,6 +65,7 @@ static const struct util_prg prg = {
- 
- static void parse_cmdline(int argc, char *argv[], struct options *opts)
- {
-+	enum util_fmt_t fmt;
- 	uint32_t seconds;
- 	int cmd, ret;
- 
-@@ -85,6 +88,12 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
- 		case OPT_DUMP:
- 			opts->module_info = true;
- 			break;
-+		case OPT_FORMAT:
-+			if (!util_fmt_name_to_type(optarg, &fmt))
-+				errx(EXIT_FAILURE, "Unknown format %s", optarg);
-+			opts->format = fmt;
-+			opts->explicit_format = true;
-+			break;
- 		case 'i':
- 			ret = sscanf(optarg, "%u", &seconds);
- 			if (ret != 1) {
-@@ -224,7 +233,7 @@ static void dump_all_adapter_data(struct opticsmon_ctx *ctx)
- 
- static int oneshot_mode(struct opticsmon_ctx *ctx)
- {
--	util_fmt_init(stdout, FMT_JSON, FMT_DEFAULT, API_LEVEL);
-+	util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL);
- 	if (!ctx->opts.quiet)
- 		util_fmt_obj_start(FMT_LIST, "adapters");
- 	dump_all_adapter_data(ctx);
-@@ -375,7 +384,7 @@ static int monitor_mode(struct opticsmon_ctx *ctx)
- 		goto close_timerfd;
- 	}
- 
--	util_fmt_init(stdout, FMT_JSONSEQ, FMT_DEFAULT, API_LEVEL);
-+	util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL);
- 	ret = link_mon_nl_waitfd_create(&ctx->lctx, on_link_change, ctx);
- 	if (ret) {
- 		fprintf(stderr, "Failed to create link monitoring socket\n");
-@@ -393,12 +402,42 @@ close_timerfd:
- 	return ret;
- }
- 
-+static bool is_supported_fmt(enum util_fmt_t fmt, bool monitor)
-+{
-+	switch (fmt) {
-+	case FMT_JSON:
-+	case FMT_PAIRS:
-+		return monitor ? false : true;
-+	case FMT_JSONL:
-+	case FMT_JSONSEQ:
-+		return monitor ? true : false;
-+	default:
-+		return false;
-+	}
-+}
-+
-+static int set_format(struct options *opts)
-+{
-+	if (!opts->explicit_format)
-+		opts->format = (opts->monitor) ? FMT_JSONSEQ : FMT_JSON;
-+
-+	if (!is_supported_fmt(opts->format, opts->monitor)) {
-+		warnx("Format %s is not supported in %s mode",
-+		      util_fmt_type_to_name(opts->format), (opts->monitor) ? "monitor" : "query");
-+		return -EINVAL;
-+	}
-+	return 0;
-+}
-+
- int main(int argc, char **argv)
- {
- 	struct opticsmon_ctx ctx = { .opts = { .interval_seconds = 86400 } };
- 	int ret;
- 
- 	parse_cmdline(argc, argv, &ctx.opts);
-+	ret = set_format(&ctx.opts);
-+	if (ret)
-+		return ret;
- 	ret = ethtool_nl_connect(&ctx.ethtool_ctx);
- 	if (ret)
- 		return ret;
-diff --git a/zpcimon/zpcimon_cli.h b/zpcimon/zpcimon_cli.h
-index c69f349a..f5a0dc3e 100644
---- a/zpcimon/zpcimon_cli.h
-+++ b/zpcimon/zpcimon_cli.h
-@@ -7,9 +7,11 @@
- #ifndef OPTICSMON_CLI_H
- #define OPTICSMON_CLI_H
- 
-+#include "lib/util_fmt.h"
- #include "lib/util_opt.h"
- 
- #define OPT_DUMP 128
-+#define OPT_FORMAT 129
- 
- static struct util_opt opt_vec[] = {
- 	UTIL_OPT_SECTION("OPERATION OPTIONS"),
-@@ -41,6 +43,13 @@ static struct util_opt opt_vec[] = {
- 			"in the absence of link state changes. A value larger than "
- 			"24 hours (86400 seconds) is clamped down to 24 hours.",
- 	},
-+	UTIL_OPT_SECTION("OUTPUT FORMAT OPTIONS"),
-+	{
-+		.option = { "format", required_argument, NULL, OPT_FORMAT },
-+		.argument = "FORMAT",
-+		.flags = UTIL_OPT_FLAG_NOSHORT,
-+		.desc = "Output format (" FMT_TYPE_NAMES ")",
-+	},
- 	UTIL_OPT_SECTION("GENERAL OPTIONS"),
- 	UTIL_OPT_HELP,
- 	UTIL_OPT_VERSION,
--- 
-2.55.0
-
-
-From f9ef8a010669e651d736e23a1dd76e124483677a Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Mon, 13 Apr 2026 13:52:37 +0200
-Subject: [PATCH 12/23] util_time: zpcimon: Use a constant for seconds per day
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Replace the magic value 86400 with a new util_time.h constant
-SEC_PER_DAY.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- include/lib/util_time.h | 2 ++
- zpcimon/zpcimon.c       | 3 ++-
- 2 files changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/include/lib/util_time.h b/include/lib/util_time.h
-index 42b9741a..21e2d78e 100644
---- a/include/lib/util_time.h
-+++ b/include/lib/util_time.h
-@@ -19,6 +19,8 @@
- 
- #define MSEC_PER_SEC	1000L
- 
-+#define SEC_PER_DAY	(24 * 60 * 60)
-+
- /**
-  * Convert nanoseconds to microseconds
-  *
-diff --git a/zpcimon/zpcimon.c b/zpcimon/zpcimon.c
-index 98a2871a..40b6edd7 100644
---- a/zpcimon/zpcimon.c
-+++ b/zpcimon/zpcimon.c
-@@ -24,6 +24,7 @@
- #include "lib/util_opt.h"
- #include "lib/util_fmt.h"
- #include "lib/util_libc.h"
-+#include "lib/util_time.h"
- 
- #include <openssl/evp.h>
- 
-@@ -102,7 +103,7 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
- 					optarg);
- 				exit(EXIT_FAILURE);
- 			}
--			if (seconds < 86400)
-+			if (seconds < SEC_PER_DAY)
- 				opts->interval_seconds = seconds;
- 			if (seconds < 1)
- 				opts->interval_seconds = 1;
--- 
-2.55.0
-
-
-From 113e9ebfef67253f4faee798d2fe785f182f9eec Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 9 Apr 2026 15:32:47 +0200
-Subject: [PATCH 13/23] zpcimon: Split optics monitoring out into separate
- monitor
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Introduce the concept of a generic zPCI device monitor by creating the
-zpcimon_ops operations struct turning all optics specific calls into
-abstract monitor calls. Handle monitors as a static array of zpcimon_ops
-based monitors of which the now split out optics monitor is currently
-the only one. All operations are in principle optional though a monitor
-which provides an init operation must also provide the corresponding
-destroy operation.
-
-Keep the base64 based JSON pair as non optics specific for later re-use
-and make it just skip the output in the very unlikely case that encoding
-fails. In follow on commits a monitor for NVMe devices collecting SMART
-data will be added.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- zpcimon/Makefile    |   2 +-
- zpcimon/opticsmon.c | 177 +++++++++++++++++++
- zpcimon/opticsmon.h |  20 +++
- zpcimon/zpcimon.c   | 406 ++++++++++++++++++++++----------------------
- zpcimon/zpcimon.h   |  52 ++++++
- 5 files changed, 454 insertions(+), 203 deletions(-)
- create mode 100644 zpcimon/opticsmon.c
- create mode 100644 zpcimon/opticsmon.h
- create mode 100644 zpcimon/zpcimon.h
-
-diff --git a/zpcimon/Makefile b/zpcimon/Makefile
-index 43fc2a04..cc0a8af0 100644
---- a/zpcimon/Makefile
-+++ b/zpcimon/Makefile
-@@ -73,7 +73,7 @@ BUILDTARGET += zpcimon
- 
- all: ${BUILDTARGET}
- 
--zpcimon: zpcimon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
-+zpcimon: zpcimon.o opticsmon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
- 
- install: all
- 	$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
-diff --git a/zpcimon/opticsmon.c b/zpcimon/opticsmon.c
-new file mode 100644
-index 00000000..4da456f1
---- /dev/null
-+++ b/zpcimon/opticsmon.c
-@@ -0,0 +1,177 @@
-+/*
-+ * zpcimon - Report monitoring data to firmware
-+ *
-+ * 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.
-+ */
-+#include <errno.h>
-+#include <linux/if.h>
-+#include <stdbool.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+
-+#include "lib/pci_list.h"
-+#include "lib/util_fmt.h"
-+#include "lib/util_libc.h"
-+
-+#include "ethtool.h"
-+#include "link_mon.h"
-+#include "optics_info.h"
-+#include "optics_sclp.h"
-+#include "opticsmon.h"
-+#include "zpcimon.h"
-+
-+static void optics_json_print(struct options *opts, struct zpci_netdev *nd, struct optics *oi)
-+{
-+	util_fmt_obj_start(FMT_DEFAULT, "netdev");
-+	util_fmt_pair(FMT_QUOTE, "name", nd->name);
-+	util_fmt_pair(FMT_QUOTE, "operstate", zpci_operstate_str(nd->operstate));
-+	util_fmt_obj_start(FMT_DEFAULT, "optics");
-+	util_fmt_pair(FMT_QUOTE, "type", optics_type_str(optics_type(oi)));
-+	util_fmt_pair(FMT_QUOTE, "rx_los", optics_los_str(optics_rx_los(oi)));
-+	util_fmt_pair(FMT_QUOTE, "tx_los", optics_los_str(optics_tx_los(oi)));
-+	util_fmt_pair(FMT_QUOTE, "tx_fault", optics_los_str(optics_tx_fault(oi)));
-+	if (opts->module_info)
-+		zpcimon_json_base64_pair("module_info", oi->raw, (int)oi->size);
-+	util_fmt_obj_end();
-+	util_fmt_obj_end();
-+}
-+
-+static int opticsmon_collect_adapter_data(struct zpcimon_ctx *ctx, struct zpci_dev *zdev)
-+{
-+	struct options *opts = &ctx->opts;
-+	struct optics **ois;
-+	int num_ois = 0;
-+	char *pci_addr;
-+	int i, rc;
-+
-+	/* Filter non-NIC devices and VFs */
-+	if (zpci_is_vf(zdev) || !zdev->num_netdevs)
-+		return -ENODEV;
-+	ois = (struct optics **)util_zalloc(sizeof(ois[0]) * zdev->num_netdevs);
-+	for (i = 0; i < zdev->num_netdevs; i++) {
-+		rc = ethtool_nl_get_optics(&ctx->opticsmon_ctx.ethtool_ctx, zdev->netdevs[i].name,
-+					   &ois[i]);
-+		if (rc)
-+			goto free_ois;
-+		num_ois++;
-+	}
-+	if (!opts->quiet) {
-+		util_fmt_obj_start(FMT_DEFAULT, "adapter");
-+		util_fmt_pair(FMT_QUOTE, "pft", zpci_pft_str(zdev));
-+		util_fmt_obj_start(FMT_DEFAULT, "ids");
-+		util_fmt_pair(FMT_QUOTE, "fid", "0x%0x", zdev->fid);
-+		if (zdev->uid_is_unique)
-+			util_fmt_pair(FMT_QUOTE, "uid", "0x%0x", zdev->uid);
-+		pci_addr = zpci_pci_addr(zdev);
-+		util_fmt_pair(FMT_QUOTE, "pci_address", pci_addr);
-+		free(pci_addr);
-+		util_fmt_obj_end();
-+		util_fmt_obj_start(FMT_LIST, "netdevs");
-+		for (i = 0; i < zdev->num_netdevs; i++)
-+			optics_json_print(opts, &zdev->netdevs[i], ois[i]);
-+		util_fmt_obj_end(); /* netdevs list */
-+		util_fmt_obj_end(); /* adapter */
-+		fflush(stdout);
-+	}
-+	if (opts->report) {
-+		for (i = 0; i < zdev->num_netdevs; i++) {
-+			rc = sclp_issue_optics_report(zdev, ois[i]);
-+			if (rc == -ENOTSUP) {
-+				fprintf(stderr, "Skipping %s which does not support reporting\n",
-+					zdev->netdevs[i].name);
-+			} else if (rc < 0) {
-+				fprintf(stderr, "Error issuing SCLP for optics data failed: %s\n",
-+					strerror(-rc));
-+			}
-+		}
-+	}
-+free_ois:
-+	for (i = 0; i < num_ois; i++)
-+		optics_free(ois[i]);
-+	free((void *)ois);
-+	return rc;
-+}
-+
-+static void on_link_change(struct zpci_netdev *change_netdev, void *arg)
-+{
-+	struct zpcimon_ctx *ctx = arg;
-+	struct zpci_dev *zdev = NULL;
-+	struct zpci_netdev *netdev;
-+	int reloads = 1;
-+
-+	do {
-+		if (ctx->zpci_list) {
-+			zdev = zpci_find_by_netdev(ctx->zpci_list, change_netdev->name,
-+						   &netdev);
-+			if (zdev) {
-+				/* Skip data collection if operational state is
-+				 * unchanged
-+				 */
-+				if (netdev->operstate == change_netdev->operstate)
-+					return;
-+				/* Update operation state for VFs even though
-+				 * they are skipped just for a consistent view
-+				 */
-+				netdev->operstate = change_netdev->operstate;
-+				/* Only collect optics data for PFs */
-+				if (!zpci_is_vf(zdev))
-+					opticsmon_collect_adapter_data(ctx, zdev);
-+				return;
-+			}
-+		}
-+		/* Could be uninitalized list or a new device, retry after reload  */
-+		zpci_list_reload(&ctx->zpci_list);
-+		reloads--;
-+	} while (reloads > 0);
-+}
-+
-+static int opticsmon_open_monitor(struct zpcimon_ctx *ctx)
-+{
-+	int ret;
-+
-+	ret = link_mon_nl_waitfd_create(&ctx->opticsmon_ctx.lctx, on_link_change, ctx);
-+	if (ret) {
-+		fprintf(stderr, "Failed to create link monitoring socket\n");
-+		ret = -EIO;
-+	}
-+	return ret;
-+}
-+
-+static int opticsmon_get_monitor_fd(struct zpcimon_ctx *ctx)
-+{
-+	return link_mon_nl_waitfd_getfd(&ctx->opticsmon_ctx.lctx);
-+}
-+
-+static void opticsmon_monitor_fd_handle(struct zpcimon_ctx *ctx)
-+{
-+	link_mon_nl_waitfd_read(&ctx->opticsmon_ctx.lctx);
-+}
-+
-+static void opticsmon_close_monitor(struct zpcimon_ctx *ctx)
-+{
-+	link_mon_nl_waitfd_destroy(&ctx->opticsmon_ctx.lctx);
-+}
-+
-+static int opticsmon_init(struct zpcimon_ctx *ctx)
-+{
-+	return ethtool_nl_connect(&ctx->opticsmon_ctx.ethtool_ctx);
-+}
-+
-+static void opticsmon_destroy(struct zpcimon_ctx *ctx)
-+{
-+	ethtool_nl_close(&ctx->opticsmon_ctx.ethtool_ctx);
-+}
-+
-+const struct zpcimon_ops opticsmon_ops = {
-+	.collect_adapter_data = opticsmon_collect_adapter_data,
-+	.open_monitor = opticsmon_open_monitor,
-+	.get_monitor_fd = opticsmon_get_monitor_fd,
-+	.monitor_fd_handle = opticsmon_monitor_fd_handle,
-+	.close_monitor = opticsmon_close_monitor,
-+	.init = opticsmon_init,
-+	.destroy = opticsmon_destroy,
-+};
-diff --git a/zpcimon/opticsmon.h b/zpcimon/opticsmon.h
-new file mode 100644
-index 00000000..04798201
---- /dev/null
-+++ b/zpcimon/opticsmon.h
-@@ -0,0 +1,20 @@
-+/*
-+ * Copyright IBM Corp. 2025
-+ *
-+ * 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 ZPCIMON_OPTICSMON_H
-+#define ZPCIMON_OPTICSMON_H
-+#include "ethtool.h"
-+#include "link_mon.h"
-+
-+struct options;
-+
-+struct opticsmon_ctx {
-+	struct ethtool_nl_ctx ethtool_ctx;
-+	struct link_mon_nl_ctx lctx;
-+};
-+
-+extern const struct zpcimon_ops opticsmon_ops;
-+#endif /* ZPCIMON_OPTICSMON_H */
-diff --git a/zpcimon/zpcimon.c b/zpcimon/zpcimon.c
-index 40b6edd7..32550ff0 100644
---- a/zpcimon/zpcimon.c
-+++ b/zpcimon/zpcimon.c
-@@ -1,57 +1,47 @@
- /*
-- * opticsmon - Report optics monitoring data to firmware
-+ * zpcimon - Report monitoring data to firmware
-  *
-  * 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.
-  */
-+#include <errno.h>
-+#include <signal.h>
-+#include <stdbool.h>
-+#include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
--#include <stdbool.h>
--#include <errno.h>
- 
-+#include <linux/if.h>
- #include <sys/epoll.h>
- #include <sys/signalfd.h>
--#include <signal.h>
- #include <sys/timerfd.h>
--#include <time.h>
--#include <linux/if.h>
- 
--#include "lib/util_list.h"
-+#include <openssl/evp.h>
-+
- #include "lib/pci_list.h"
--#include "lib/util_prg.h"
--#include "lib/util_opt.h"
- #include "lib/util_fmt.h"
- #include "lib/util_libc.h"
-+#include "lib/util_opt.h"
-+#include "lib/util_prg.h"
- #include "lib/util_time.h"
-+#include "lib/zt_common.h"
- 
--#include <openssl/evp.h>
--
--#include "ethtool.h"
--#include "link_mon.h"
--#include "optics_info.h"
--#include "optics_sclp.h"
-+#include "opticsmon.h"
-+#include "zpcimon.h"
- #include "zpcimon_cli.h"
- 
- #define API_LEVEL 1
- 
--struct options {
--	bool monitor;
--	bool report;
--	bool module_info;
--	bool quiet;
--	enum util_fmt_t format;
--	bool explicit_format;
--
--	uint32_t interval_seconds;
-+struct zpcimon_monitor {
-+	const struct zpcimon_ops *ops;
-+	uint32_t initialized : 1;
-+	uint32_t opened : 1;
- };
- 
--struct opticsmon_ctx {
--	struct options opts;
--	struct ethtool_nl_ctx ethtool_ctx;
--	struct link_mon_nl_ctx lctx;
--	struct util_list *zpci_list;
-+static struct zpcimon_monitor monitors[] = {
-+	{.ops = &opticsmon_ops, .initialized = 0, .opened = 0},
- };
- 
- static const struct util_prg prg = {
-@@ -122,171 +112,131 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
- 	} while (cmd != -1);
- }
- 
--static int module_info_pair(struct optics *oi)
-+void zpcimon_json_base64_pair(char *name, uint8_t *buf, int len)
- {
--	size_t b64_calclen, b64len;
--	int rc = EXIT_SUCCESS;
-+	int b64_calclen, b64len;
- 	char *b64;
- 
--	b64_calclen = (oi->size / 3) * 4;
--	if (oi->size % 3 > 0)
-+	b64_calclen = (len / 3) * 4;
-+	if (len % 3 > 0)
- 		b64_calclen += 4;
- 
- 	b64 = util_zalloc(b64_calclen + 1); /* adds NUL byte */
--	b64len = EVP_EncodeBlock((unsigned char *)b64, oi->raw, oi->size);
-+	b64len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)buf, len);
- 	if (b64len != b64_calclen) {
--		fprintf(stderr, "encoding base64 via openssl failed\n");
--		rc = EXIT_FAILURE;
-+		warnx("encoding base64 via openssl failed\n");
- 		goto out;
- 	}
--	util_fmt_pair(FMT_QUOTE, "module_info", b64);
-+	util_fmt_pair(FMT_QUOTE, name, b64);
- out:
- 	free(b64);
--	return rc;
--}
--
--static void optics_json_print(struct opticsmon_ctx *ctx, struct zpci_netdev *nd, struct optics *oi)
--{
--	util_fmt_obj_start(FMT_DEFAULT, "netdev");
--	util_fmt_pair(FMT_QUOTE, "name", nd->name);
--	util_fmt_pair(FMT_QUOTE, "operstate", zpci_operstate_str(nd->operstate));
--	util_fmt_obj_start(FMT_DEFAULT, "optics");
--	util_fmt_pair(FMT_QUOTE, "type", optics_type_str(optics_type(oi)));
--	util_fmt_pair(FMT_QUOTE, "rx_los", optics_los_str(optics_rx_los(oi)));
--	util_fmt_pair(FMT_QUOTE, "tx_los", optics_los_str(optics_tx_los(oi)));
--	util_fmt_pair(FMT_QUOTE, "tx_fault", optics_los_str(optics_tx_fault(oi)));
--	if (ctx->opts.module_info)
--		module_info_pair(oi);
--	util_fmt_obj_end();
--	util_fmt_obj_end();
--}
--
--static int dump_adapter_data(struct opticsmon_ctx *ctx, struct zpci_dev *zdev)
--{
--	struct optics **ois;
--	int num_ois = 0;
--	char *pci_addr;
--	int i, rc;
--
--	ois = util_zalloc(sizeof(ois[0]) * zdev->num_netdevs);
--	for (i = 0; i < zdev->num_netdevs; i++) {
--		rc = ethtool_nl_get_optics(&ctx->ethtool_ctx, zdev->netdevs[i].name, &ois[i]);
--		if (rc)
--			goto free_ois;
--		num_ois++;
--	}
--	if (!ctx->opts.quiet) {
--		util_fmt_obj_start(FMT_DEFAULT, "adapter");
--		util_fmt_pair(FMT_QUOTE, "pft", zpci_pft_str(zdev));
--		util_fmt_obj_start(FMT_DEFAULT, "ids");
--		util_fmt_pair(FMT_QUOTE, "fid", "0x%0x", zdev->fid);
--		if (zdev->uid_is_unique)
--			util_fmt_pair(FMT_QUOTE, "uid", "0x%0x", zdev->uid);
--		pci_addr = zpci_pci_addr(zdev);
--		util_fmt_pair(FMT_QUOTE, "pci_address", pci_addr);
--		free(pci_addr);
--		util_fmt_obj_end();
--		util_fmt_obj_start(FMT_LIST, "netdevs");
--		for (i = 0; i < zdev->num_netdevs; i++)
--			optics_json_print(ctx, &zdev->netdevs[i], ois[i]);
--		util_fmt_obj_end(); /* netdevs list */
--		util_fmt_obj_end(); /* adapter */
--		fflush(stdout);
--	}
--	if (ctx->opts.report) {
--		for (i = 0; i < zdev->num_netdevs; i++) {
--			rc = sclp_issue_optics_report(zdev, ois[i]);
--			if (rc == -ENOTSUP) {
--				fprintf(stderr, "Skipping %s which does not support reporting\n",
--					zdev->netdevs[i].name);
--			} else if (rc < 0) {
--				fprintf(stderr, "Error issuing SCLP for optics data failed: %s\n",
--					strerror(-rc));
--			}
--		}
--	}
--free_ois:
--	for (i = 0; i < num_ois; i++)
--		optics_free(ois[i]);
--	free(ois);
--	return rc;
- }
- 
--static void zpci_list_reload(struct util_list **zpci_list)
-+void zpci_list_reload(struct util_list **zpci_list)
- {
- 	if (*zpci_list)
- 		zpci_free_dev_list(*zpci_list);
- 	*zpci_list = zpci_dev_list();
- }
- 
--static void dump_all_adapter_data(struct opticsmon_ctx *ctx)
-+static void collect_all_adapter_data(struct zpcimon_ctx *ctx)
- {
- 	struct zpci_dev *zdev;
-+	int i;
- 
- 	zpci_list_reload(&ctx->zpci_list);
- 	util_list_iterate(ctx->zpci_list, zdev) {
--		/* Filter non-NIC devices and VFs */
--		if (zpci_is_vf(zdev) || !zdev->num_netdevs)
--			continue;
--		dump_adapter_data(ctx, zdev);
-+		for (i = 0; i < (int)ARRAY_SIZE(monitors); i++)
-+			if (monitors[i].ops->collect_adapter_data)
-+				monitors[i].ops->collect_adapter_data(ctx, zdev);
- 	}
- }
- 
--static int oneshot_mode(struct opticsmon_ctx *ctx)
-+#define MAX_EVENTS 8
-+
-+static int monitor_epoll_mon_fds_prepare(struct zpcimon_ctx *ctx, int epfd, int mon_fds[])
- {
--	util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL);
--	if (!ctx->opts.quiet)
--		util_fmt_obj_start(FMT_LIST, "adapters");
--	dump_all_adapter_data(ctx);
--	if (!ctx->opts.quiet)
--		util_fmt_obj_end();
--	util_fmt_exit();
-+	struct epoll_event ev;
-+	int mon_idx;
- 
--	return EXIT_SUCCESS;
-+	for (mon_idx = 0; mon_idx < (int)ARRAY_SIZE(monitors); mon_idx++) {
-+		if (!monitors[mon_idx].ops->get_monitor_fd) {
-+			mon_fds[mon_idx] = -1;
-+			continue;
-+		}
-+		mon_fds[mon_idx] = monitors[mon_idx].ops->get_monitor_fd(ctx);
-+		if (mon_fds[mon_idx] < 0)
-+			return -EIO;
-+		ev.events = EPOLLIN;
-+		ev.data.fd = mon_fds[mon_idx];
-+		if (epoll_ctl(epfd, EPOLL_CTL_ADD, mon_fds[mon_idx], &ev) == -1)
-+			return -EIO;
-+	}
-+	return 0;
- }
- 
--void on_link_change(struct zpci_netdev *netdev, void *arg)
-+static void monitor_epoll_mon_fds(struct zpcimon_ctx *ctx, struct epoll_event event,
-+				  const int mon_fds[])
- {
--	struct opticsmon_ctx *ctx = arg;
--	struct zpci_netdev *found_netdev;
--	struct zpci_dev *zdev = NULL;
--	int reloads = 1;
-+	int mon_idx;
- 
--	do {
--		if (ctx->zpci_list) {
--			zdev = zpci_find_by_netdev(ctx->zpci_list, netdev->name, &found_netdev);
--			if (zdev) {
--				/* Skip data collection if operational state is
--				 * unchanged
--				 */
--				if (found_netdev->operstate == netdev->operstate)
--					return;
--				/* Update operation state for VFs even though
--				 * they are skipped just for a consistent view
--				 */
--				found_netdev->operstate = netdev->operstate;
--				/* Only collect optics data for PFs */
--				if (!zpci_is_vf(zdev))
--					dump_adapter_data(ctx, zdev);
--				return;
--			}
--		}
--		/* Could be uninitalized list or a new device, retry after reload  */
--		zpci_list_reload(&ctx->zpci_list);
--		reloads--;
--	} while (reloads > 0);
-+	for (mon_idx = 0; mon_idx < (int)ARRAY_SIZE(monitors); mon_idx++) {
-+		if (event.data.fd != mon_fds[mon_idx])
-+			continue;
-+		if (!monitors[mon_idx].ops->monitor_fd_handle)
-+			continue;
-+		monitors[mon_idx].ops->monitor_fd_handle(ctx);
-+	}
- }
- 
--#define MAX_EVENTS 8
--
--static int monitor_wait_loop(struct opticsmon_ctx *ctx, int sigfd, int timerfd)
-+static int monitor_epoll(struct zpcimon_ctx *ctx, const int mon_fds[], int epfd, int sigfd,
-+			 int timerfd)
- {
- 	struct epoll_event events[MAX_EVENTS];
--	int i, nlfd, epfd, nfds, ret = -EIO;
- 	struct signalfd_siginfo fdsi;
--	struct epoll_event ev;
- 	uint64_t expirations;
- 	ssize_t sread;
-+	int i, nfds;
-+
-+	nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
-+	if (nfds < 0)
-+		return nfds;
-+	for (i = 0; i < nfds; i++) {
-+		/* signal fd */
-+		if (events[i].data.fd == sigfd) {
-+			sread = read(sigfd, &fdsi, sizeof(fdsi));
-+			if (sread != sizeof(fdsi))
-+				return -EIO;
-+			switch (fdsi.ssi_signo) {
-+			case SIGINT:
-+			case SIGTERM:
-+			case SIGQUIT:
-+				return -EINTR;
-+			/* Unexpected signal */
-+			default:
-+				return -EIO;
-+			}
-+			/* timer fd */
-+		} else if (events[i].data.fd == timerfd) {
-+			sread = read(timerfd, &expirations, sizeof(uint64_t));
-+			if (sread != sizeof(uint64_t))
-+				return -EIO;
-+			if (!expirations)
-+				continue;
-+			collect_all_adapter_data(ctx);
-+			/* netlink fd */
-+		} else {
-+			monitor_epoll_mon_fds(ctx, events[i], mon_fds);
-+		}
-+	}
-+	return 0;
-+}
-+
-+static int monitor_wait_loop(struct zpcimon_ctx *ctx, int sigfd, int timerfd)
-+{
-+	int mon_fds[ARRAY_SIZE(monitors)];
-+	struct epoll_event ev;
-+	int epfd, ret = -EIO;
- 
- 	epfd = epoll_create1(EPOLL_CLOEXEC);
- 	if (epfd < 0)
-@@ -302,52 +252,57 @@ static int monitor_wait_loop(struct opticsmon_ctx *ctx, int sigfd, int timerfd)
- 	if (epoll_ctl(epfd, EPOLL_CTL_ADD, timerfd, &ev) == -1)
- 		goto out_close;
- 
--	nlfd = link_mon_nl_waitfd_getfd(&ctx->lctx);
--	ev.events = EPOLLIN;
--	ev.data.fd = nlfd;
--	if (epoll_ctl(epfd, EPOLL_CTL_ADD, nlfd, &ev) == -1)
-+	ret = monitor_epoll_mon_fds_prepare(ctx, epfd, mon_fds);
-+	if (ret)
- 		goto out_close;
- 
- 	while (1) {
--		nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
--		if (nfds < 0)
--			goto out_close;
--		for (i = 0; i < nfds; i++) {
--			/* signal fd */
--			if (events[i].data.fd == sigfd) {
--				sread = read(sigfd, &fdsi, sizeof(fdsi));
--				if (sread != sizeof(fdsi))
--					goto out_close;
--				switch (fdsi.ssi_signo) {
--				case SIGINT:
--				case SIGTERM:
--				case SIGQUIT:
--					ret = 0;
--					goto out_close;
--				/* Unexpected signal */
--				default:
--					goto out_close;
--				}
--				/* timer fd */
--			} else if (events[i].data.fd == timerfd) {
--				sread = read(timerfd, &expirations, sizeof(uint64_t));
--				if (sread != sizeof(uint64_t))
--					goto out_close;
--				if (!expirations)
--					continue;
--				dump_all_adapter_data(ctx);
--				/* netlink fd */
--			} else if (events[i].data.fd == nlfd) {
--				link_mon_nl_waitfd_read(&ctx->lctx);
--			}
--		}
-+		ret = monitor_epoll(ctx, mon_fds, epfd, sigfd, timerfd);
-+		if (ret)
-+			break;
- 	}
- out_close:
-+	/* Getting interrupted by a signal is not an error */
-+	if (ret == -EINTR)
-+		ret = 0;
- 	close(epfd);
- 	return ret;
- }
- 
--static int monitor_mode(struct opticsmon_ctx *ctx)
-+static void zpcimon_close_monitor(struct zpcimon_ctx *ctx)
-+{
-+	int i;
-+
-+	for (i = 0; i < (int)ARRAY_SIZE(monitors); i++) {
-+		if (!monitors[i].ops->close_monitor || !monitors[i].opened)
-+			continue;
-+		monitors[i].ops->close_monitor(ctx);
-+		monitors[i].opened = 0;
-+	}
-+}
-+
-+static int zpcimon_open_monitor(struct zpcimon_ctx *ctx)
-+{
-+	int i, ret = -ENXIO;
-+
-+	for (i = 0; i < (int)ARRAY_SIZE(monitors); i++) {
-+		if (!monitors[i].ops->open_monitor || monitors[i].opened)
-+			continue;
-+		if (monitors[i].opened)
-+			goto error;
-+		ret = monitors[i].ops->open_monitor(ctx);
-+		if (ret)
-+			goto error;
-+		monitors[i].opened = 1;
-+	}
-+	return 0;
-+
-+error:
-+	zpcimon_close_monitor(ctx);
-+	return ret;
-+}
-+
-+static int monitor_mode(struct zpcimon_ctx *ctx)
- {
- 	struct itimerspec timerspec;
- 	int sigfd, timerfd, ret;
-@@ -386,20 +341,67 @@ static int monitor_mode(struct opticsmon_ctx *ctx)
- 	}
- 
- 	util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL);
--	ret = link_mon_nl_waitfd_create(&ctx->lctx, on_link_change, ctx);
--	if (ret) {
--		fprintf(stderr, "Failed to create link monitoring socket\n");
--		goto close_timerfd;
--	}
-+	ret = zpcimon_open_monitor(ctx);
-+	if (ret < 0)
-+		goto cleanup_fmt;
- 
- 	ret = monitor_wait_loop(ctx, sigfd, timerfd);
- 
--	link_mon_nl_waitfd_destroy(&ctx->lctx);
-+	zpcimon_close_monitor(ctx);
-+cleanup_fmt:
- 	util_fmt_exit();
--close_signalfd:
--	close(sigfd);
- close_timerfd:
- 	close(timerfd);
-+close_signalfd:
-+	close(sigfd);
-+	return ret;
-+}
-+
-+static int oneshot_mode(struct zpcimon_ctx *ctx)
-+{
-+	util_fmt_init(stdout, ctx->opts.format, FMT_DEFAULT, API_LEVEL);
-+	if (!ctx->opts.quiet)
-+		util_fmt_obj_start(FMT_LIST, "adapters");
-+
-+	collect_all_adapter_data(ctx);
-+
-+	if (!ctx->opts.quiet)
-+		util_fmt_obj_end();
-+	util_fmt_exit();
-+
-+	return EXIT_SUCCESS;
-+}
-+
-+static void zpcimon_destroy(struct zpcimon_ctx *ctx)
-+{
-+	int i;
-+
-+	for (i = 0; i < (int)ARRAY_SIZE(monitors); i++) {
-+		if (!monitors[i].ops->destroy || !monitors[i].initialized)
-+			continue;
-+		monitors[i].ops->destroy(ctx);
-+		monitors[i].initialized = false;
-+	}
-+}
-+
-+static int zpcimon_init(struct zpcimon_ctx *ctx)
-+{
-+	int i, ret = -ENXIO;
-+
-+	for (i = 0; i < (int)ARRAY_SIZE(monitors); i++) {
-+		if (!monitors[i].ops->init)
-+			continue;
-+		if (monitors[i].initialized)
-+			goto error;
-+		ret = monitors[i].ops->init(ctx);
-+		if (ret)
-+			goto error;
-+		monitors[i].initialized = 1;
-+	}
-+	return 0;
-+
-+error:
-+	zpcimon_destroy(ctx);
- 	return ret;
- }
- 
-@@ -432,21 +434,21 @@ static int set_format(struct options *opts)
- 
- int main(int argc, char **argv)
- {
--	struct opticsmon_ctx ctx = { .opts = { .interval_seconds = 86400 } };
-+	struct zpcimon_ctx ctx = { .opts = { .interval_seconds = SEC_PER_DAY } };
- 	int ret;
- 
- 	parse_cmdline(argc, argv, &ctx.opts);
- 	ret = set_format(&ctx.opts);
- 	if (ret)
- 		return ret;
--	ret = ethtool_nl_connect(&ctx.ethtool_ctx);
-+	ret = zpcimon_init(&ctx);
- 	if (ret)
- 		return ret;
- 	if (ctx.opts.monitor)
- 		ret = monitor_mode(&ctx);
- 	else
- 		ret = oneshot_mode(&ctx);
--	ethtool_nl_close(&ctx.ethtool_ctx);
-+	zpcimon_destroy(&ctx);
- 
- 	if (ctx.zpci_list)
- 		zpci_free_dev_list(ctx.zpci_list);
-diff --git a/zpcimon/zpcimon.h b/zpcimon/zpcimon.h
-new file mode 100644
-index 00000000..768d5921
---- /dev/null
-+++ b/zpcimon/zpcimon.h
-@@ -0,0 +1,52 @@
-+/*
-+ * 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 ZPCIMON_ZPCIMON_H
-+#define ZPCIMON_ZPCIMON_H
-+#include <stdbool.h>
-+#include <stdint.h>
-+
-+#include "lib/util_fmt.h"
-+
-+#include "opticsmon.h"
-+
-+#define API_LEVEL 1
-+
-+struct options {
-+	uint32_t interval_seconds;
-+
-+	bool monitor;
-+	bool report;
-+	bool quiet;
-+	enum util_fmt_t format;
-+	bool explicit_format;
-+
-+	/* Optics Monitoring Specific */
-+	bool module_info;
-+};
-+
-+struct zpcimon_ctx {
-+	struct options opts;
-+	struct util_list *zpci_list;
-+	struct opticsmon_ctx opticsmon_ctx;
-+};
-+
-+struct zpcimon_ops {
-+	int (*collect_adapter_data)(struct zpcimon_ctx *ctx, struct zpci_dev *zdev);
-+
-+	int (*open_monitor)(struct zpcimon_ctx *ctx);
-+	int (*get_monitor_fd)(struct zpcimon_ctx *ctx);
-+	void (*monitor_fd_handle)(struct zpcimon_ctx *ctx);
-+	void (*close_monitor)(struct zpcimon_ctx *ctx);
-+
-+	int (*init)(struct zpcimon_ctx *ctx);
-+	void (*destroy)(struct zpcimon_ctx *ctx);
-+};
-+
-+void zpci_list_reload(struct util_list **zpci_list);
-+
-+void zpcimon_json_base64_pair(char *name, uint8_t *buf, int len);
-+#endif /* ZPCIMON_ZPCIMON_H */
--- 
-2.55.0
-
-
-From 78dd82d129c9ef0338619dfa3061c6db9cec3f9d Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 18 Jun 2026 16:40:09 +0200
-Subject: [PATCH 14/23] libzpci: Extract get_device_node() from zpcictl to
- libzpci
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The get_device_node() function for getting the name of an NVMe's
-controller device e.g. "nvme0" as implemented in zpcictl is generally
-useful and will be needed for NVMe SMART data collection in zpcimon as
-well. Move it to libzpci and rename it to zpci_get_nvme_device_node() to
-account for the change in namespace.
-
-It would be tempting to pass a struct zpci_dev* instead of a const char*
-but as zpcictl uses an incompatible struct zpci_device* this will
-require a larger rework. Prioritize minimizing code duplication for now.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- include/lib/pci_list.h |  4 ++++
- libzpci/pci_list.c     | 46 +++++++++++++++++++++++++++++++++++++++++-
- zpcictl/zpcictl.c      | 33 ++----------------------------
- 3 files changed, 51 insertions(+), 32 deletions(-)
-
-diff --git a/include/lib/pci_list.h b/include/lib/pci_list.h
-index 5b2918bc..226a82d9 100644
---- a/include/lib/pci_list.h
-+++ b/include/lib/pci_list.h
-@@ -17,6 +17,8 @@
- 
- #include "util_list.h"
- 
-+#define PCI_BDF_LEN 13 /* DDDD:BB:dd.f\0 */
-+
- enum zpci_pft {
- 	ZPCI_PFT_UNCLASSIFIED = 0x00,
- 
-@@ -96,4 +98,6 @@ operstate_t zpci_operstate_from_str(const char *oper_str);
- struct zpci_dev *zpci_find_by_netdev(struct util_list *zpci_list, char *netdev_name,
- 				     struct zpci_netdev **netdev);
- 
-+char *zpci_get_nvme_device_node(const char *pci_addr);
-+
- #endif /* LIB_ZPCI_PCI_LIST_H */
-diff --git a/libzpci/pci_list.c b/libzpci/pci_list.c
-index e0d56e44..e81bb4b8 100644
---- a/libzpci/pci_list.c
-+++ b/libzpci/pci_list.c
-@@ -20,6 +20,7 @@
- #include "lib/util_list.h"
- #include "lib/util_path.h"
- #include "lib/util_scandir.h"
-+#include "lib/util_sys.h"
- 
- /**
-  * Get the function type name for the given device
-@@ -137,7 +138,7 @@ const char *zpci_operstate_str(operstate_t state)
- static int zpci_populate_from_slot_dir(struct zpci_dev *zdev, const char *slot_dir,
- 				       const char *slot_name)
- {
--	char buf_addr[11]; /* "dddd:bb:dd\0" */
-+	char buf_addr[PCI_BDF_LEN];
- 	uint8_t bus, df;
- 	uint32_t domain;
- 	int val, rc;
-@@ -387,3 +388,46 @@ struct zpci_dev *zpci_find_by_netdev(struct util_list *zpci_list, char *netdev_n
- 	}
- 	return NULL;
- }
-+
-+/**
-+ * Get the NVMe device file name given a PCI address
-+ *
-+ * This function retrieves the NVMe device file "/dev/nvmeX"
-+ * for a given PCI address. The device name can be used to construct
-+ * the path /dev/nvmeX which is the NVMe's controller's character
-+ * device used for example to retrieve S.M.A.R.T. data.
-+ *
-+ * @param[in]	pci_addr	The "DDDD:bb:dd.f" format PCI address
-+ *
-+ * @return The NVMe device file name if one is found NULL otherwise
-+ */
-+char *zpci_get_nvme_device_node(const char *pci_addr)
-+{
-+	char *path, *dev = NULL;
-+	char dev_addr[PCI_BDF_LEN];
-+	struct dirent **de_vec;
-+	int count, i;
-+
-+	path = util_path_sysfs("bus/pci/devices/%s/nvme", pci_addr);
-+	count = util_scandir(&de_vec, alphasort, path, "nvme*");
-+	if (count == -1) {
-+		warnx("Could not read directory %s: %s", path, strerror(errno));
-+		goto exit_path;
-+	}
-+
-+	for (i = 0; i < count; i++) {
-+		util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name);
-+		if (util_sys_get_dev_addr(dev, dev_addr) != 0)
-+			goto free_continue;
-+		if (strcmp(dev_addr, pci_addr) == 0)
-+			break;
-+free_continue:
-+		free(dev);
-+		dev = NULL;
-+	}
-+
-+	util_scandir_free(de_vec, count);
-+exit_path:
-+	free(path);
-+	return dev;
-+}
-diff --git a/zpcictl/zpcictl.c b/zpcictl/zpcictl.c
-index 421403ac..8c8ce482 100644
---- a/zpcictl/zpcictl.c
-+++ b/zpcictl/zpcictl.c
-@@ -18,8 +18,8 @@
- #include "lib/util_opt.h"
- #include "lib/util_path.h"
- #include "lib/util_prg.h"
--#include "lib/util_scandir.h"
- #include "lib/util_sys.h"
-+#include "lib/pci_list.h"
- #include "lib/pci_sclp.h"
- 
- #include "zpcictl.h"
-@@ -187,35 +187,6 @@ static void sysfs_write_value(struct zpci_device *pdev, const char *attr,
- 	free(path);
- }
- 
--static void get_device_node(struct zpci_device *pdev)
--{
--	struct dirent **de_vec;
--	char *path, *dev;
--	char slot[13];
--	int count, i;
--
--	path = util_path_sysfs("bus/pci/devices/%s/nvme", pdev->slot);
--	count = util_scandir(&de_vec, alphasort, path, "nvme*");
--	if (count == -1) {
--		warnx("Could not read directory %s: %s", path, strerror(errno));
--		free(path);
--		return;
--	}
--
--	for (i = 0; i < count; i++) {
--		util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name);
--		if (util_sys_get_dev_addr(dev, slot) != 0)
--			continue;
--		if (strcmp(slot, pdev->slot) == 0) {
--			pdev->device = dev;
--			break;
--		}
--	}
--
--	util_scandir_free(de_vec, count);
--	free(path);
--}
--
- static int device_exists(char *dev)
- {
- 	char *path;
-@@ -258,7 +229,7 @@ static void get_device_info(struct zpci_device *pdev, char *dev)
- 	 * S.M.A.R.T. data at a later point.
- 	 */
- 	if (!pdev->device && pdev->class == PCI_CLASS_NVME)
--		get_device_node(pdev);
-+		pdev->device = zpci_get_nvme_device_node(pdev->slot);
- }
- 
- /*
--- 
-2.55.0
-
-
-From a9dbb8a1a2bcfefeffee0c80ec73a801c543c7e7 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Mon, 22 Jun 2026 12:36:30 +0200
-Subject: [PATCH 15/23] zpcimon: Factor out JSON printing of common PCI adapter
- attributes
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Some of the attributes printed as JSON by opticsmon are common to all
-PCI adapters factor these out into reusable helper functions
-zpci_adapter_json_print_start() and zpci_adapter_json_print_end().
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- zpcimon/opticsmon.c | 14 ++------------
- zpcimon/zpcimon.c   | 21 +++++++++++++++++++++
- zpcimon/zpcimon.h   |  2 ++
- 3 files changed, 25 insertions(+), 12 deletions(-)
-
-diff --git a/zpcimon/opticsmon.c b/zpcimon/opticsmon.c
-index 4da456f1..2faa21d0 100644
---- a/zpcimon/opticsmon.c
-+++ b/zpcimon/opticsmon.c
-@@ -45,7 +45,6 @@ static int opticsmon_collect_adapter_data(struct zpcimon_ctx *ctx, struct zpci_d
- 	struct options *opts = &ctx->opts;
- 	struct optics **ois;
- 	int num_ois = 0;
--	char *pci_addr;
- 	int i, rc;
- 
- 	/* Filter non-NIC devices and VFs */
-@@ -60,21 +59,12 @@ static int opticsmon_collect_adapter_data(struct zpcimon_ctx *ctx, struct zpci_d
- 		num_ois++;
- 	}
- 	if (!opts->quiet) {
--		util_fmt_obj_start(FMT_DEFAULT, "adapter");
--		util_fmt_pair(FMT_QUOTE, "pft", zpci_pft_str(zdev));
--		util_fmt_obj_start(FMT_DEFAULT, "ids");
--		util_fmt_pair(FMT_QUOTE, "fid", "0x%0x", zdev->fid);
--		if (zdev->uid_is_unique)
--			util_fmt_pair(FMT_QUOTE, "uid", "0x%0x", zdev->uid);
--		pci_addr = zpci_pci_addr(zdev);
--		util_fmt_pair(FMT_QUOTE, "pci_address", pci_addr);
--		free(pci_addr);
--		util_fmt_obj_end();
-+		zpci_adapter_json_print_start(zdev);
- 		util_fmt_obj_start(FMT_LIST, "netdevs");
- 		for (i = 0; i < zdev->num_netdevs; i++)
- 			optics_json_print(opts, &zdev->netdevs[i], ois[i]);
- 		util_fmt_obj_end(); /* netdevs list */
--		util_fmt_obj_end(); /* adapter */
-+		zpci_adapter_json_print_end();
- 		fflush(stdout);
- 	}
- 	if (opts->report) {
-diff --git a/zpcimon/zpcimon.c b/zpcimon/zpcimon.c
-index 32550ff0..e30f251e 100644
---- a/zpcimon/zpcimon.c
-+++ b/zpcimon/zpcimon.c
-@@ -112,6 +112,27 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
- 	} while (cmd != -1);
- }
- 
-+void zpci_adapter_json_print_start(struct zpci_dev *zdev)
-+{
-+	char *pci_addr;
-+
-+	util_fmt_obj_start(FMT_DEFAULT, "adapter");
-+	util_fmt_pair(FMT_QUOTE, "pft", zpci_pft_str(zdev));
-+	util_fmt_obj_start(FMT_DEFAULT, "ids");
-+	util_fmt_pair(FMT_QUOTE, "fid", "0x%0x", zdev->fid);
-+	if (zdev->uid_is_unique)
-+		util_fmt_pair(FMT_QUOTE, "uid", "0x%0x", zdev->uid);
-+	pci_addr = zpci_pci_addr(zdev);
-+	util_fmt_pair(FMT_QUOTE, "pci_address", pci_addr);
-+	free(pci_addr);
-+	util_fmt_obj_end();
-+}
-+
-+void zpci_adapter_json_print_end(void)
-+{
-+	util_fmt_obj_end(); /* adapter */
-+}
-+
- void zpcimon_json_base64_pair(char *name, uint8_t *buf, int len)
- {
- 	int b64_calclen, b64len;
-diff --git a/zpcimon/zpcimon.h b/zpcimon/zpcimon.h
-index 768d5921..cb124056 100644
---- a/zpcimon/zpcimon.h
-+++ b/zpcimon/zpcimon.h
-@@ -48,5 +48,7 @@ struct zpcimon_ops {
- 
- void zpci_list_reload(struct util_list **zpci_list);
- 
-+void zpci_adapter_json_print_start(struct zpci_dev *zdev);
-+void zpci_adapter_json_print_end(void);
- void zpcimon_json_base64_pair(char *name, uint8_t *buf, int len);
- #endif /* ZPCIMON_ZPCIMON_H */
--- 
-2.55.0
-
-
-From 2eceedeb111453949ac78685c21c0f6a05f02bcd Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Mon, 22 Jun 2026 12:43:07 +0200
-Subject: [PATCH 16/23] zpcimon: Add NVMe SMART data monitor
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add a new monitor which uses libnvme to collect SMART data from NVMes.
-This monitor only implements the .collect_adapter_data operation since
-it carries no state across data collections. Nevertheless for future
-symmetry and possible future expansion also add an empty struct
-nvmemon_ctx.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- README.md              |  7 +--
- include/lib/pci_sclp.h |  2 +
- zpcimon/Makefile       | 22 +++++++++-
- zpcimon/nvmemon.c      | 98 ++++++++++++++++++++++++++++++++++++++++++
- zpcimon/nvmemon.h      | 13 ++++++
- zpcimon/zpcimon.8      | 26 +++++++----
- zpcimon/zpcimon.c      |  5 +++
- zpcimon/zpcimon.h      |  4 ++
- zpcimon/zpcimon_cli.h  |  8 ++++
- 9 files changed, 172 insertions(+), 13 deletions(-)
- create mode 100644 zpcimon/nvmemon.c
- create mode 100644 zpcimon/nvmemon.h
-
-diff --git a/README.md b/README.md
-index 4045b0f8..ab3dcd4e 100644
---- a/README.md
-+++ b/README.md
-@@ -327,6 +327,7 @@ build options:
- | systemd      | `HAVE_SYSTEMD`     | hsavmcore                              |
- | libudev      | `HAVE_LIBUDEV`     | cpacfstatsd                            |
- | libnl3       | `HAVE_LIBNL3`      | zpcimon                                |
-+| libnvme      | `HAVE_LIBNVME`     | zpcimon                                |
- 
- This table lists additional build or install options:
- 
-@@ -375,10 +376,10 @@ the different tools are provided:
-   The runtime requirements are: openssl-libs (>= 1.1.1) and libcurl.
- 
- * zpcimon:
--  For building zpcimon OpenSSL and the Netlink Library Suite (libnl3) are
--  required.
-+  For building zpcimon OpenSSL, the Netlink Library Suite (libnl3),
-+  and libnvme are required.
-   Tip: you may skip the zpcimon build by adding
--  `HAVE_OPENSSL=0` or `HAVE_LIBNL3=0`
-+  `HAVE_OPENSSL=0` or `HAVE_LIBNL3=0` or `HAVE_LIBNVME=0`.
- 
- * osasnmpd:
-   You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)
-diff --git a/include/lib/pci_sclp.h b/include/lib/pci_sclp.h
-index 688a7b76..c075b264 100644
---- a/include/lib/pci_sclp.h
-+++ b/include/lib/pci_sclp.h
-@@ -21,9 +21,11 @@
- #define SCLP_ERRNOTIFY_AQ_DECONF		1
- #define SCLP_ERRNOTIFY_AQ_REPORT_ERR		2
- #define SCLP_ERRNOTIFY_AQ_OPTICS_DATA		3
-+#define SCLP_ERRNOTIFY_AQ_NVME_SMART_DATA	4
- 
- #define SCLP_ERRNOTIFY_ID_ZPCICTL		0x4713
- #define SCLP_ERRNOTIFY_ID_OPTICSMON		0x4714
-+#define SCLP_ERRNOTIFY_ID_NVMEMON		0x4715
- 
- #define SCLP_ERRNOTIFY_DATA_SIZE		4054
- 
-diff --git a/zpcimon/Makefile b/zpcimon/Makefile
-index cc0a8af0..ce815a31 100644
---- a/zpcimon/Makefile
-+++ b/zpcimon/Makefile
-@@ -29,6 +29,16 @@ check_dep_libnl3:
- BUILDTARGET += check_dep_libnl3
- endif # HAVE_LIBNL3
- 
-+ifneq (${HAVE_LIBNVME},0)
-+check_dep_libnvme:
-+	$(call check_dep, \
-+		"zpcimon", \
-+		"libnvme.h", \
-+		"libnvme-devel", \
-+		"HAVE_LIBNVME=0")
-+BUILDTARGET += check_dep_libnvme
-+endif # HAVE_LIBNVME
-+
- ifeq (${HAVE_OPENSSL},0)
- 
- all:
-@@ -44,6 +54,13 @@ all:
- install:
- 	$(SKIP) HAVE_LIBNL3=0
- 
-+else ifeq (${HAVE_LIBNVME},0)
-+all:
-+	$(SKIP) HAVE_LIBNVME=0
-+
-+install:
-+	$(SKIP) HAVE_LIBNVME=0
-+
- else
- 
- ifneq ($(shell sh -c 'command -v pkg-config'),)
-@@ -58,12 +75,15 @@ LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libnl-genl-3.0)
- LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libnl-route-3.0)
- 
- LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libcrypto)
-+LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libnvme)
- else
- LIB_CFLAGS += -I /usr/include/libnl3/
- LIB_LFLAGS += -lnl-route-3 -lnl-genl-3 -lnl-3
- 
- LIB_CFLAGS += -I /usr/include/openssl/
- LIB_LFLAGS += -lcrypto
-+
-+LIB_LFLAGS += -lnvme
- endif
- 
- ALL_CPPFLAGS += $(LIB_CFLAGS)
-@@ -73,7 +93,7 @@ BUILDTARGET += zpcimon
- 
- all: ${BUILDTARGET}
- 
--zpcimon: zpcimon.o opticsmon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
-+zpcimon: zpcimon.o nvmemon.o opticsmon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
- 
- install: all
- 	$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
-diff --git a/zpcimon/nvmemon.c b/zpcimon/nvmemon.c
-new file mode 100644
-index 00000000..85a5d0ad
---- /dev/null
-+++ b/zpcimon/nvmemon.c
-@@ -0,0 +1,98 @@
-+/*
-+ * zpcimon - Report monitoring data to firmware
-+ *
-+ * Copyright IBM Corp. 2025
-+ *
-+ * s390-tools is free software; you can redistribute it and/or modify
-+ * it under the terms of the MIT license. See LICENSE for details.
-+ */
-+#include <err.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <stdbool.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <libnvme.h>
-+
-+#include "lib/pci_list.h"
-+#include "lib/pci_sclp.h"
-+#include "lib/util_fmt.h"
-+
-+#include "nvmemon.h"
-+#include "zpcimon.h"
-+
-+static void nvme_json_print(struct zpcimon_ctx *ctx, struct zpci_dev *zdev, const char *name,
-+			    struct nvme_smart_log *log)
-+{
-+	zpci_adapter_json_print_start(zdev);
-+	util_fmt_obj_start(FMT_DEFAULT, "nvmedev");
-+	util_fmt_pair(FMT_QUOTE, "dev", name);
-+	if (ctx->opts.smart_blob)
-+		zpcimon_json_base64_pair("smart-log-raw", (uint8_t *)log, sizeof(*log));
-+	util_fmt_obj_end();
-+	zpci_adapter_json_print_end();
-+	fflush(stdout);
-+}
-+
-+static int sclp_issue_nvme_smart_report(struct zpci_dev *zdev, const uint8_t *smart, int smart_len)
-+{
-+	char *pci_addr;
-+	int rc;
-+
-+	if (zdev->pft != ZPCI_PFT_NVME)
-+		return -ENOTSUP;
-+	pci_addr = zpci_pci_addr(zdev);
-+	rc = zpci_sclp_issue_action(pci_addr, SCLP_ERRNOTIFY_AQ_NVME_SMART_DATA,
-+				    (char *)smart, smart_len, SCLP_ERRNOTIFY_ID_NVMEMON);
-+	free(pci_addr);
-+	return rc;
-+}
-+
-+static int nvmemon_collect_adapter_data(struct zpcimon_ctx *ctx, struct zpci_dev *zdev)
-+{
-+	struct nvme_smart_log log = {};
-+	int nvme_fd, rc = -ENODEV;
-+	char *dev, *pci_addr;
-+
-+	if (zdev->pft != ZPCI_PFT_NVME)
-+		return -ENODEV;
-+
-+	pci_addr = zpci_pci_addr(zdev);
-+	dev = zpci_get_nvme_device_node(pci_addr);
-+	if (!dev)
-+		goto exit_free_addr;
-+
-+	nvme_fd = openat(AT_FDCWD, dev, O_RDONLY);
-+	if (nvme_fd < 0) {
-+		warn("Failed to open %s", dev);
-+		rc = -errno;
-+		goto exit_free_dev;
-+	}
-+
-+	rc = nvme_get_log_smart(nvme_fd, NVME_NSID_ALL, false, &log);
-+	if (rc) {
-+		warnx("Getting NVMe SMART log failed %d", rc);
-+		goto exit_close;
-+	}
-+	if (!ctx->opts.quiet)
-+		nvme_json_print(ctx, zdev, dev, &log);
-+	if (ctx->opts.report) {
-+		rc = sclp_issue_nvme_smart_report(zdev, (uint8_t *)&log, sizeof(log));
-+		if (rc < 0 && rc != -ENOTSUP)
-+			warnx("Error issuing SCLP for NVMe SMART log failed");
-+	}
-+
-+exit_close:
-+	close(nvme_fd);
-+exit_free_dev:
-+	free(dev);
-+exit_free_addr:
-+	free(pci_addr);
-+	return rc;
-+}
-+
-+const struct zpcimon_ops nvmemon_ops = {
-+	.collect_adapter_data = nvmemon_collect_adapter_data,
-+};
-diff --git a/zpcimon/nvmemon.h b/zpcimon/nvmemon.h
-new file mode 100644
-index 00000000..0658bcaa
---- /dev/null
-+++ b/zpcimon/nvmemon.h
-@@ -0,0 +1,13 @@
-+/*
-+ * Copyright IBM Corp. 2025
-+ *
-+ * 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 ZPCIMON_NVMEMON_H
-+#define ZPCIMON_NVMEMON_H
-+
-+struct nvmemon_ctx {};
-+
-+extern const struct zpcimon_ops nvmemon_ops;
-+#endif /* ZPCIMON_NVMEMON_H */
-diff --git a/zpcimon/zpcimon.8 b/zpcimon/zpcimon.8
-index 9b16fa91..6cc6ab29 100644
---- a/zpcimon/zpcimon.8
-+++ b/zpcimon/zpcimon.8
-@@ -33,7 +33,7 @@
- .TH zpcimon 8 "Oct 2024" s390-tools zpcictl
- .
- .SH NAME
--zpcimon - Monitor optical modules for directly attached PCI based NICs
-+zpcimon - Monitor health of directly attached PCI devices including NVMes and NICs.
- .
- .
- .SH SYNOPSIS
-@@ -45,26 +45,29 @@ zpcimon - Monitor optical modules for directly attached PCI based NICs
- Use
- .B zpcimon
- to monitor the health of the optical modules of directly attached PCI based
--NICs. When executed without the \fB--monitor\fR option it will collect optical
--module data from all available PCI network interface physical functions and
--print a summary in JSON format. Add the \fB--send-report\fR option to report
--this data to the support element.
--
-+NICs as well as the health of NVMe devices using their SMART data. When
-+executed without the \fB--monitor\fR option it will collect health data from
-+all available and relevant PCI devices and print a summary in JSON format. Add
-+the \fB--send-report\fR option to report this data to the support element.
- 
- .
- .
- .SH OPTIONS
- .SS Operation Options
- .OD monitor "m"
--Run continuously and report on link state changes and periodically
-+Run continuously and monitor all supported devices. On link state changes
-+optical module data is collected and NVMe SMART data is collected on hotplug.
-+Moreover every
-+.B --interval
-+seconds data from all adapters is collected as a whole system snapshot.
- .PP
- .
- .OD send-report "r"
--Report the optics health data to the Support Element (SE)
-+Report the optics and NVMe health data to the Support Element (SE)
- .PP
- .
- .OD quiet "q"
--Be quiet and don't print optics health summary
-+Be quiet and don't print health summaries.
- .PP
- .
- .OD interval "i" "seconds"
-@@ -84,6 +87,11 @@ on".
- .PP
- .PP
- .
-+.OD smart-log-raw ""
-+Include a base64 encoded binary dump of each NVMe's SMART data. This matches
-+"nvme smart-log --output-format=binary /dev/nvmeX".
-+.PP
-+.
- .SS Output Format Options
- .OD format "" <FORMAT>
- Set the output format out of json, json-seq, jsonl, pairs, and csv. Note that
-diff --git a/zpcimon/zpcimon.c b/zpcimon/zpcimon.c
-index e30f251e..625a1363 100644
---- a/zpcimon/zpcimon.c
-+++ b/zpcimon/zpcimon.c
-@@ -28,6 +28,7 @@
- #include "lib/util_time.h"
- #include "lib/zt_common.h"
- 
-+#include "nvmemon.h"
- #include "opticsmon.h"
- #include "zpcimon.h"
- #include "zpcimon_cli.h"
-@@ -42,6 +43,7 @@ struct zpcimon_monitor {
- 
- static struct zpcimon_monitor monitors[] = {
- 	{.ops = &opticsmon_ops, .initialized = 0, .opened = 0},
-+	{.ops = &nvmemon_ops, .initialized  = 0, .opened = 0},
- };
- 
- static const struct util_prg prg = {
-@@ -79,6 +81,9 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
- 		case OPT_DUMP:
- 			opts->module_info = true;
- 			break;
-+		case OPT_SMART_DUMP:
-+			opts->smart_blob = true;
-+			break;
- 		case OPT_FORMAT:
- 			if (!util_fmt_name_to_type(optarg, &fmt))
- 				errx(EXIT_FAILURE, "Unknown format %s", optarg);
-diff --git a/zpcimon/zpcimon.h b/zpcimon/zpcimon.h
-index cb124056..da22eabe 100644
---- a/zpcimon/zpcimon.h
-+++ b/zpcimon/zpcimon.h
-@@ -11,6 +11,7 @@
- 
- #include "lib/util_fmt.h"
- 
-+#include "nvmemon.h"
- #include "opticsmon.h"
- 
- #define API_LEVEL 1
-@@ -26,12 +27,15 @@ struct options {
- 
- 	/* Optics Monitoring Specific */
- 	bool module_info;
-+	/* NVMe Monitoring Specific */
-+	bool smart_blob;
- };
- 
- struct zpcimon_ctx {
- 	struct options opts;
- 	struct util_list *zpci_list;
- 	struct opticsmon_ctx opticsmon_ctx;
-+	struct nvmemon_ctx nvmemon_ctx;
- };
- 
- struct zpcimon_ops {
-diff --git a/zpcimon/zpcimon_cli.h b/zpcimon/zpcimon_cli.h
-index f5a0dc3e..3a0f21a1 100644
---- a/zpcimon/zpcimon_cli.h
-+++ b/zpcimon/zpcimon_cli.h
-@@ -12,6 +12,7 @@
- 
- #define OPT_DUMP 128
- #define OPT_FORMAT 129
-+#define OPT_SMART_DUMP 130
- 
- static struct util_opt opt_vec[] = {
- 	UTIL_OPT_SECTION("OPERATION OPTIONS"),
-@@ -35,6 +36,13 @@ static struct util_opt opt_vec[] = {
- 			"This matches 'ethtool --module-info <netdev> raw on'",
- 		.flags = UTIL_OPT_FLAG_NOSHORT,
- 	},
-+	{
-+		.option = { "smart-log-raw", no_argument, NULL, OPT_SMART_DUMP },
-+		.desc = "Include a base64 encoded binary dump of the "
-+			"SMART log data for each NVMe. "
-+			"This matches 'nvme smart-log --raw-binary <dev>'",
-+		.flags = UTIL_OPT_FLAG_NOSHORT,
-+	},
- 	UTIL_OPT_SECTION("OPTIONS WITH ARGUMENTS"),
- 	{
- 		.option = { "interval", required_argument, NULL, 'i' },
--- 
-2.55.0
-
-
-From f1a11a01dff9632c07ba9ec3c001bed1b0ef2ffd Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Tue, 21 Apr 2026 11:44:09 +0200
-Subject: [PATCH 17/23] zpcimon: Add JSON output for SMART data details
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This uses the same format as:
-
-   nvme smart-log --output-format=json /dev/nvmeX
-
-One complication being that several values in the SMART data use
-unsigned 128 bit integers. Both GCC and Clang support __uint128_t as
-a C extension but don't offer printf() support for it. Just like
-nvme-cli add a custom uint128_t to string function..
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- zpcimon/nvmemon.c | 106 +++++++++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 104 insertions(+), 2 deletions(-)
-
-diff --git a/zpcimon/nvmemon.c b/zpcimon/nvmemon.c
-index 85a5d0ad..a516b4aa 100644
---- a/zpcimon/nvmemon.c
-+++ b/zpcimon/nvmemon.c
-@@ -23,14 +23,116 @@
- #include "nvmemon.h"
- #include "zpcimon.h"
- 
-+/**
-+ * Reads a CPU native 128 bit unsigned integer from the binary buffer @data
-+ * containing the value in the 128 bit little endian format used by the
-+ * NVMe standard.
-+ *
-+ * @return the 128 bit value encoded in the data buffer.
-+ */
-+static __uint128_t nvme_le128_to_cpu(const __u8 data[16])
-+{
-+	__uint128_t u;
-+	int i;
-+
-+	u = data[0];
-+	for (i = 1; i < (int)sizeof(u); i++)
-+		u |= (__uint128_t)data[i] << (8 * i);
-+	return u;
-+}
-+
-+#define MAX_UINT128_DECIMAL_LEN (41) /* length of 2^128-1 in decimal + 0 byte */
-+
-+/**
-+ * Write the decimal string representation of the passed unsigned 128 bit value @val into
-+ * the buffer @buf for output in JSON. The representation does not include
-+ * quotes.
-+ */
-+static void nvme_u128_to_json_val(__uint128_t val, char buf[MAX_UINT128_DECIMAL_LEN])
-+{
-+	const char *digit_ascii = "0123456789";
-+	int pos = MAX_UINT128_DECIMAL_LEN - 1;
-+	int mod_ten;
-+	int len;
-+
-+	/* Write digits right to left at the end of res */
-+	do {
-+		mod_ten = val % 10;
-+		val /= 10;
-+		buf[pos--] = digit_ascii[mod_ten];
-+	} while (val);
-+	/* Move digits to the front */
-+	len = MAX_UINT128_DECIMAL_LEN - 1 - pos;
-+	memmove(buf, &buf[pos + 1], len);
-+	buf[len] = '\0';
-+}
-+
-+static void nvme_json_print_smart_log(struct zpcimon_ctx *ctx, struct nvme_smart_log *log)
-+{
-+	char u128_num_buf[MAX_UINT128_DECIMAL_LEN];
-+	unsigned int temperature;
-+
-+	/* While some fields in struct nvme_smart_log are __leXX
-+	 * temperature is an array of two u8 of the little endian data
-+	 * in Kelvin.
-+	 */
-+	temperature = log->temperature[1] << 8 | log->temperature[0];
-+
-+	util_fmt_obj_start(FMT_DEFAULT, "smart-log");
-+	util_fmt_pair(FMT_DEFAULT, "critical_warning", "%d", log->critical_warning);
-+	util_fmt_pair(FMT_DEFAULT, "temperature", "%d", temperature);
-+	util_fmt_pair(FMT_DEFAULT, "avail_spare", "%d", log->avail_spare);
-+	util_fmt_pair(FMT_DEFAULT, "spare_thresh", "%d", log->spare_thresh);
-+	util_fmt_pair(FMT_DEFAULT, "percent_used", "%d", log->percent_used);
-+	util_fmt_pair(FMT_DEFAULT, "endurance_grp_critical_warning_summary", "%d",
-+		      log->endu_grp_crit_warn_sumry);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->data_units_read), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "data_units_read", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->data_units_written), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "data_units_written", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->host_reads), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "host_read_commands", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->host_writes), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "host_write_commands", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->ctrl_busy_time), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "controller_busy_time", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->power_cycles), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "power_cycles", "%s", u128_num_buf);
-+	/* 2^128 hours is 2.8*10^24 times the age of the universe ;) */
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->power_on_hours), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "power_on_hours", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->unsafe_shutdowns), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "unsafe_shutdowns", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->media_errors), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "media_errors", "%s", u128_num_buf);
-+	nvme_u128_to_json_val(nvme_le128_to_cpu(log->num_err_log_entries), u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "num_err_log_entries", "%s", u128_num_buf);
-+	util_fmt_pair(FMT_DEFAULT, "warning_temp_time", "%d", le32toh(log->warning_temp_time));
-+	util_fmt_pair(FMT_DEFAULT, "critical_comp_time", "%d", le32toh(log->critical_comp_time));
-+	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_1", "%d", le16toh(log->temp_sensor[0]));
-+	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_2", "%d", le16toh(log->temp_sensor[1]));
-+	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_3", "%d", le16toh(log->temp_sensor[2]));
-+	util_fmt_pair(FMT_DEFAULT, "thm_temp1_trans_count", "%d",
-+		      le32toh(log->thm_temp1_trans_count));
-+	util_fmt_pair(FMT_DEFAULT, "thm_temp2_trans_count", "%d",
-+		      le32toh(log->thm_temp2_trans_count));
-+	util_fmt_pair(FMT_DEFAULT, "thm_temp1_total_time", "%d",
-+		      le32toh(log->thm_temp1_total_time));
-+	util_fmt_pair(FMT_DEFAULT, "thm_temp2_total_time", "%d",
-+		      le32toh(log->thm_temp2_total_time));
-+	util_fmt_obj_end(); /* smart-log */
-+
-+	if (ctx->opts.smart_blob)
-+		zpcimon_json_base64_pair("smart-log-raw", (uint8_t *)log, sizeof(*log));
-+}
-+
- static void nvme_json_print(struct zpcimon_ctx *ctx, struct zpci_dev *zdev, const char *name,
- 			    struct nvme_smart_log *log)
- {
- 	zpci_adapter_json_print_start(zdev);
- 	util_fmt_obj_start(FMT_DEFAULT, "nvmedev");
- 	util_fmt_pair(FMT_QUOTE, "dev", name);
--	if (ctx->opts.smart_blob)
--		zpcimon_json_base64_pair("smart-log-raw", (uint8_t *)log, sizeof(*log));
-+	nvme_json_print_smart_log(ctx, log);
- 	util_fmt_obj_end();
- 	zpci_adapter_json_print_end();
- 	fflush(stdout);
--- 
-2.55.0
-
-
-From 4fd607ae5ca9ec3714ca2354475f9a8b8caace09 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 23 Apr 2026 14:20:47 +0200
-Subject: [PATCH 18/23] zpcimon: Monitor for hotplug of NVMes to trigger SMART
- collection
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Use libudev to monitor for "change" events in the "nvme" subsystem that
-use the "pcie" transport to trigger NVMe SMART data collection. Only
-collect data from the NVMe referenced by the udev event.
-
-Assisted-by: IBM Bob:1.0.1
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- README.md         |   2 +-
- zpcimon/Makefile  |  18 ++++++++
- zpcimon/nvmemon.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
- zpcimon/nvmemon.h |   7 ++-
- 4 files changed, 135 insertions(+), 2 deletions(-)
-
-diff --git a/README.md b/README.md
-index ab3dcd4e..35bb7ada 100644
---- a/README.md
-+++ b/README.md
-@@ -325,7 +325,7 @@ build options:
- |              |                    | rust/pvattest, rust/pvsecret,          |
- | libxml2      | `HAVE_LIBXML2`     | libkmipclient                          |
- | systemd      | `HAVE_SYSTEMD`     | hsavmcore                              |
--| libudev      | `HAVE_LIBUDEV`     | cpacfstatsd                            |
-+| libudev      | `HAVE_LIBUDEV`     | cpacfstatsd, zpcimon                   |
- | libnl3       | `HAVE_LIBNL3`      | zpcimon                                |
- | libnvme      | `HAVE_LIBNVME`     | zpcimon                                |
- 
-diff --git a/zpcimon/Makefile b/zpcimon/Makefile
-index ce815a31..a9792164 100644
---- a/zpcimon/Makefile
-+++ b/zpcimon/Makefile
-@@ -39,6 +39,16 @@ check_dep_libnvme:
- BUILDTARGET += check_dep_libnvme
- endif # HAVE_LIBNVME
- 
-+ifneq (${HAVE_LIBUDEV},0)
-+check_dep_libudev:
-+	$(call check_dep, \
-+		"zpcimon", \
-+		"libudev.h", \
-+		"systemd-devel", \
-+		"HAVE_LIBNVME=0")
-+BUILDTARGET += check_dep_libudev
-+endif # HAVE_LIBUDEV
-+
- ifeq (${HAVE_OPENSSL},0)
- 
- all:
-@@ -61,6 +71,12 @@ all:
- install:
- 	$(SKIP) HAVE_LIBNVME=0
- 
-+else ifeq (${HAVE_LIBUDEV},0)
-+all:
-+	$(SKIP) HAVE_LIBUDEV=0
-+
-+install:
-+	$(SKIP) HAVE_LIBUDEV=0
- else
- 
- ifneq ($(shell sh -c 'command -v pkg-config'),)
-@@ -76,6 +92,7 @@ LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libnl-route-3.0)
- 
- LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libcrypto)
- LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libnvme)
-+LIB_LFLAGS += $(shell $(PKG_CONFIG) --silence-errors --libs libudev)
- else
- LIB_CFLAGS += -I /usr/include/libnl3/
- LIB_LFLAGS += -lnl-route-3 -lnl-genl-3 -lnl-3
-@@ -84,6 +101,7 @@ LIB_CFLAGS += -I /usr/include/openssl/
- LIB_LFLAGS += -lcrypto
- 
- LIB_LFLAGS += -lnvme
-+LIB_LFLAGS += -ludev
- endif
- 
- ALL_CPPFLAGS += $(LIB_CFLAGS)
-diff --git a/zpcimon/nvmemon.c b/zpcimon/nvmemon.c
-index a516b4aa..14f088c0 100644
---- a/zpcimon/nvmemon.c
-+++ b/zpcimon/nvmemon.c
-@@ -15,6 +15,7 @@
- #include <string.h>
- #include <unistd.h>
- #include <libnvme.h>
-+#include <libudev.h>
- 
- #include "lib/pci_list.h"
- #include "lib/pci_sclp.h"
-@@ -195,6 +196,115 @@ exit_free_addr:
- 	return rc;
- }
- 
-+static int nvmemon_open_monitor(struct zpcimon_ctx *ctx)
-+{
-+	struct nvmemon_ctx *nctx = &ctx->nvmemon_ctx;
-+	int ret = -EINVAL;
-+
-+	nctx->udev = udev_new();
-+	if (!nctx->udev)
-+		return -ENOMEM;
-+
-+	nctx->mon = udev_monitor_new_from_netlink(nctx->udev, "kernel");
-+	if (!nctx->mon) {
-+		ret = -ENOMEM;
-+		goto error_udev;
-+	}
-+
-+	if (udev_monitor_filter_add_match_subsystem_devtype(nctx->mon, "nvme", NULL) < 0)
-+		goto error_mon;
-+
-+	/* Note: This explicit udev_monitor_enable_receiving() is deprecated and not needed anymore
-+	 * in udev v257+. It's harmless though so we do it for easier backporting.
-+	 */
-+	if (udev_monitor_enable_receiving(nctx->mon) < 0)
-+		goto error_mon;
-+
-+	return 0;
-+
-+error_mon:
-+	udev_monitor_unref(nctx->mon);
-+	nctx->mon = NULL;
-+error_udev:
-+	udev_unref(nctx->udev);
-+	nctx->udev = NULL;
-+	return ret;
-+}
-+
-+static int nvmemon_get_monitor_fd(struct zpcimon_ctx *ctx)
-+{
-+	struct nvmemon_ctx *nctx = &ctx->nvmemon_ctx;
-+
-+	if (!nctx->mon)
-+		return -1;
-+	return udev_monitor_get_fd(nctx->mon);
-+}
-+
-+static void nvmemon_monitor_fd_handle(struct zpcimon_ctx *ctx)
-+{
-+	const char *action, *transport, *event_pci_addr;
-+	struct nvmemon_ctx *nctx = &ctx->nvmemon_ctx;
-+	struct udev_device *dev, *pci_dev;
-+	struct zpci_dev *zdev;
-+	char *zdev_pci_addr;
-+
-+	dev = udev_monitor_receive_device(nctx->mon);
-+	if (!dev)
-+		return;
-+
-+	action = udev_device_get_action(dev);
-+	transport = udev_device_get_property_value(dev, "NVME_TRTYPE");
-+
-+	/* Change events are late enough that the /dev/nvmeX is ready for
-+	 * reading SMART data and we're only interested in directly PCIe
-+	 * attached NVMes
-+	 */
-+	if (action && strcmp(action, "change") == 0 && transport &&
-+	    strcmp(transport, "pcie") == 0) {
-+		pci_dev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
-+		if (!pci_dev)
-+			goto out;
-+		event_pci_addr = udev_device_get_sysname(pci_dev);
-+		if (!event_pci_addr)
-+			goto out;
-+
-+		zpci_list_reload(&ctx->zpci_list);
-+		if (ctx->zpci_list) {
-+			util_list_iterate(ctx->zpci_list, zdev) {
-+				if (zdev->pft != ZPCI_PFT_NVME)
-+					continue;
-+				zdev_pci_addr = zpci_pci_addr(zdev);
-+				if (strcmp(zdev_pci_addr, event_pci_addr) == 0) {
-+					free(zdev_pci_addr);
-+					nvmemon_collect_adapter_data(ctx, zdev);
-+					break;
-+				}
-+				free(zdev_pci_addr);
-+			}
-+		}
-+	}
-+out:
-+	udev_device_unref(dev);
-+}
-+
-+static void nvmemon_close_monitor(struct zpcimon_ctx *ctx)
-+{
-+	struct nvmemon_ctx *nctx = &ctx->nvmemon_ctx;
-+
-+	if (nctx->mon) {
-+		udev_monitor_unref(nctx->mon);
-+		nctx->mon = NULL;
-+	}
-+	if (nctx->udev) {
-+		udev_unref(nctx->udev);
-+		nctx->udev = NULL;
-+	}
-+}
-+
- const struct zpcimon_ops nvmemon_ops = {
- 	.collect_adapter_data = nvmemon_collect_adapter_data,
-+	.open_monitor = nvmemon_open_monitor,
-+	.get_monitor_fd = nvmemon_get_monitor_fd,
-+	.monitor_fd_handle = nvmemon_monitor_fd_handle,
-+	.close_monitor = nvmemon_close_monitor,
- };
-diff --git a/zpcimon/nvmemon.h b/zpcimon/nvmemon.h
-index 0658bcaa..b5a31193 100644
---- a/zpcimon/nvmemon.h
-+++ b/zpcimon/nvmemon.h
-@@ -7,7 +7,12 @@
- #ifndef ZPCIMON_NVMEMON_H
- #define ZPCIMON_NVMEMON_H
- 
--struct nvmemon_ctx {};
-+#include <libudev.h>
-+
-+struct nvmemon_ctx {
-+	struct udev *udev;
-+	struct udev_monitor *mon;
-+};
- 
- extern const struct zpcimon_ops nvmemon_ops;
- #endif /* ZPCIMON_NVMEMON_H */
--- 
-2.55.0
-
-
-From f96f09a5c9c7ba81132aa6bc25df7abf3e9031f4 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 30 Apr 2026 15:33:43 +0200
-Subject: [PATCH 19/23] nvmemon: libzpci: Skip SCLP on NVMes with non-IBM
- subsystem vendor ID
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The SCLP Write Event Data Action Qualifier 4 is only available for
-NVMes with subsystem vendor ID matching IBM. Add both IDs to struct
-zpci_dev in libzpci. Also add them to the libzpci_example output
-and adjust its output to multiline to handle more data.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- include/lib/pci_list.h    |  4 ++++
- libzpci/libzpci_example.c | 12 ++++++++----
- libzpci/pci_list.c        | 10 ++++++++++
- zpcimon/nvmemon.c         |  2 +-
- 4 files changed, 23 insertions(+), 5 deletions(-)
-
-diff --git a/include/lib/pci_list.h b/include/lib/pci_list.h
-index 226a82d9..204b710d 100644
---- a/include/lib/pci_list.h
-+++ b/include/lib/pci_list.h
-@@ -18,6 +18,7 @@
- #include "util_list.h"
- 
- #define PCI_BDF_LEN 13 /* DDDD:BB:dd.f\0 */
-+#define PCI_VENDOR_ID_IBM 0x1014
- 
- enum zpci_pft {
- 	ZPCI_PFT_UNCLASSIFIED = 0x00,
-@@ -67,6 +68,9 @@ struct zpci_dev {
- 	bool uid_is_unique;
- 	/* Configuration state 0 - Standby, 1 Configured */
- 	bool conf;
-+	/* Common PCI attributes */
-+	uint16_t subsystem_vendor;
-+	uint16_t subsystem_device;
- 
- 	/* Associated netdevs if any */
- 	int num_netdevs;
-diff --git a/libzpci/libzpci_example.c b/libzpci/libzpci_example.c
-index 583846b4..a9b8509e 100644
---- a/libzpci/libzpci_example.c
-+++ b/libzpci/libzpci_example.c
-@@ -12,13 +12,17 @@ static void zpci_print(struct zpci_dev *zdev)
- 	int i;
- 
- 	if (!zdev->conf) {
--		printf("fid: %8x address: %s\n", zdev->fid, pci_addr);
-+		printf("fid:\t%4x address: %s\n", zdev->fid, pci_addr);
- 	} else {
--		printf("fid: %8x address: %s uid: %4x%s pchid: %4x vfn: %4d port: %1d pft: %s ",
-+		printf("fid:\t%4x address: %s uid: %4x%s pchid: %4x vfn: %4d\n",
- 		       zdev->fid, pci_addr, zdev->uid, (zdev->uid_is_unique) ? " (unique)" : "",
--		       zdev->pchid, zdev->vfn, zdev->port, zpci_pft_str(zdev));
-+		       zdev->pchid, zdev->vfn);
-+		printf("\n");
-+		printf("\tport: %1d pft: %s subsystem_device: %4x subsystem_vendor: %4x\n",
-+		       zdev->port, zpci_pft_str(zdev), zdev->subsystem_device,
-+		       zdev->subsystem_vendor);
- 		if (zdev->num_netdevs) {
--			printf("netdevs: ");
-+			printf("\tnetdevs: ");
- 			for (i = 0; i < zdev->num_netdevs; i++) {
- 				printf("%s (%s)", zdev->netdevs[i].name,
- 				       zpci_operstate_str(zdev->netdevs[i].operstate));
-diff --git a/libzpci/pci_list.c b/libzpci/pci_list.c
-index e81bb4b8..a125bf71 100644
---- a/libzpci/pci_list.c
-+++ b/libzpci/pci_list.c
-@@ -262,6 +262,16 @@ static int zpci_populate_from_dev_dir(struct zpci_dev *zdev)
- 		goto out_path;
- 	zdev->pft = val;
- 
-+	rc = util_file_read_i(&val, 16, "%s/subsystem_device", path);
-+	if (rc)
-+		goto out_path;
-+	zdev->subsystem_device = val;
-+
-+	rc = util_file_read_i(&val, 16, "%s/subsystem_vendor", path);
-+	if (rc)
-+		goto out_path;
-+	zdev->subsystem_vendor = val;
-+
- 	if (util_path_is_readable("%s/net", path)) {
- 		rc = zpci_populate_netdevices(zdev, path);
- 		if (rc)
-diff --git a/zpcimon/nvmemon.c b/zpcimon/nvmemon.c
-index 14f088c0..bd5ef1a7 100644
---- a/zpcimon/nvmemon.c
-+++ b/zpcimon/nvmemon.c
-@@ -144,7 +144,7 @@ static int sclp_issue_nvme_smart_report(struct zpci_dev *zdev, const uint8_t *sm
- 	char *pci_addr;
- 	int rc;
- 
--	if (zdev->pft != ZPCI_PFT_NVME)
-+	if (zdev->pft != ZPCI_PFT_NVME || zdev->subsystem_vendor != PCI_VENDOR_ID_IBM)
- 		return -ENOTSUP;
- 	pci_addr = zpci_pci_addr(zdev);
- 	rc = zpci_sclp_issue_action(pci_addr, SCLP_ERRNOTIFY_AQ_NVME_SMART_DATA,
--- 
-2.55.0
-
-
-From 1da328921b419445d24f569e7cf85082bec9c688 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Fri, 26 Jun 2026 15:13:22 +0200
-Subject: [PATCH 20/23] dbginfo.sh: Let zpcimon log both optical module and
- SMART data
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Add zpcimon data collection with both SMART log and optical module data.
-Do so in the Z device subsystem commands section to account for the fact
-that zpcimon is no longer network specific. At the same time keep the
-existing opticsmon invocation for compatibility when executed on systems
-without zpcimon.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Reviewed-by: Jörn Siglen <siglen@de.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- scripts/dbginfo.sh | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/scripts/dbginfo.sh b/scripts/dbginfo.sh
-index ec6227f1..a5e3866e 100755
---- a/scripts/dbginfo.sh
-+++ b/scripts/dbginfo.sh
-@@ -515,6 +515,7 @@ CMDS="${CMDS}\
-   :lspci -vvv\
-   :lstape\
-   :smc_dbg\
-+  :zpcimon --module-info --smart-log-raw\
-   "
- 
- # block device and other scsi device commands (in non alphabetical order)
--- 
-2.55.0
-
-
-From 7586a1ad593f99bd7eb2daec39f01d4aeee3cf08 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 23 Jul 2026 16:55:50 +0200
-Subject: [PATCH 21/23] zpcimon: Add missing include for __packed attribute
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-The __packed attribute is used without including the necessary
-zt_common.h header, add it. Note that luckily the struct as it currently
-exists doesn't actually required __packed as the natural alignment
-leaves no holes. Still if in the future the reserved field is split up
-it would need it and this keeps it consistent with the kernel
-declaration.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- zpcimon/optics_sclp.h | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/zpcimon/optics_sclp.h b/zpcimon/optics_sclp.h
-index b211e9ac..4b295bc5 100644
---- a/zpcimon/optics_sclp.h
-+++ b/zpcimon/optics_sclp.h
-@@ -1,6 +1,7 @@
- #include <stdint.h>
- 
- #include "lib/pci_list.h"
-+#include "lib/zt_common.h"
- 
- #include "optics_info.h"
- 
--- 
-2.55.0
-
-
-From 0f0e8cf33b807caebb9d8e8a652c0e7326ea48d7 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 23 Jul 2026 16:55:53 +0200
-Subject: [PATCH 22/23] zpcimon: Make optics_los_implemente() static
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Sparse noted that optics_los_implemente() can be static. Make it so.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- zpcimon/optics_info.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/zpcimon/optics_info.c b/zpcimon/optics_info.c
-index 00d8d723..b3bc3535 100644
---- a/zpcimon/optics_info.c
-+++ b/zpcimon/optics_info.c
-@@ -53,7 +53,7 @@ enum optics_type optics_type(struct optics *oi)
- 	};
- }
- 
--bool optics_los_implemented(struct optics *oi)
-+static bool optics_los_implemented(struct optics *oi)
- {
- 	enum optics_type type = optics_type(oi);
- 	uint8_t implemented;
--- 
-2.55.0
-
-
-From 91123e5d45ed9fd227d6e9c590ec82484dbb7bc7 Mon Sep 17 00:00:00 2001
-From: Niklas Schnelle <schnelle@linux.ibm.com>
-Date: Thu, 23 Jul 2026 16:55:54 +0200
-Subject: [PATCH 23/23] lib/zt_common.h: zpcimon: Add __force and use it to
- annotate le32toh() conversions
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-When using sparse on zpcimon several warnings like the one below are
-generated:
-
-  warning: incorrect type in argument 1 (different base types)
-     expected unsigned int [usertype] __bsx
-     got restricted __le32 [usertype] warning_temp_time
-
-This is because several members in struct nvme_smart_log are marked as
-__le32. These members are correctly converted to host endianness before
-use via le32toh() respectively le16toh(). Since these functions take
-their parameters as plain uint32_t or uint16_t however the implicit
-conversion triggers the above warning. Fix this by adding the __force
-attribute and using it to mark type conversions in the leXXtoh() calls.
-
-Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
-Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
-Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
----
- include/lib/zt_common.h |  5 +++++
- zpcimon/nvmemon.c       | 24 +++++++++++++++---------
- 2 files changed, 20 insertions(+), 9 deletions(-)
-
-diff --git a/include/lib/zt_common.h b/include/lib/zt_common.h
-index c5363fe2..78f2a9b8 100644
---- a/include/lib/zt_common.h
-+++ b/include/lib/zt_common.h
-@@ -72,6 +72,11 @@
- #define __section(x) __attribute__((__section__(#x)))
- #define __noinline __attribute__((__noinline__))
- #define __big_endian
-+#ifdef __CHECKER__
-+# define __force __attribute__((force))
-+#else
-+# define __force
-+#endif
- /* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
-  * __always_inline. Therefore undefine it first to allow the headers
-  * to be included first.
-diff --git a/zpcimon/nvmemon.c b/zpcimon/nvmemon.c
-index bd5ef1a7..1e4c1aa8 100644
---- a/zpcimon/nvmemon.c
-+++ b/zpcimon/nvmemon.c
-@@ -20,6 +20,7 @@
- #include "lib/pci_list.h"
- #include "lib/pci_sclp.h"
- #include "lib/util_fmt.h"
-+#include "lib/zt_common.h"
- 
- #include "nvmemon.h"
- #include "zpcimon.h"
-@@ -108,19 +109,24 @@ static void nvme_json_print_smart_log(struct zpcimon_ctx *ctx, struct nvme_smart
- 	util_fmt_pair(FMT_DEFAULT, "media_errors", "%s", u128_num_buf);
- 	nvme_u128_to_json_val(nvme_le128_to_cpu(log->num_err_log_entries), u128_num_buf);
- 	util_fmt_pair(FMT_DEFAULT, "num_err_log_entries", "%s", u128_num_buf);
--	util_fmt_pair(FMT_DEFAULT, "warning_temp_time", "%d", le32toh(log->warning_temp_time));
--	util_fmt_pair(FMT_DEFAULT, "critical_comp_time", "%d", le32toh(log->critical_comp_time));
--	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_1", "%d", le16toh(log->temp_sensor[0]));
--	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_2", "%d", le16toh(log->temp_sensor[1]));
--	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_3", "%d", le16toh(log->temp_sensor[2]));
-+	util_fmt_pair(FMT_DEFAULT, "warning_temp_time", "%d",
-+		      le32toh((__force uint32_t)log->warning_temp_time));
-+	util_fmt_pair(FMT_DEFAULT, "critical_comp_time", "%d",
-+		      le32toh((__force uint32_t)log->critical_comp_time));
-+	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_1", "%d",
-+		      le16toh((__force uint16_t)log->temp_sensor[0]));
-+	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_2", "%d",
-+		      le16toh((__force uint16_t)log->temp_sensor[1]));
-+	util_fmt_pair(FMT_DEFAULT, "temperature_sensor_3", "%d",
-+		      le16toh((__force uint16_t)log->temp_sensor[2]));
- 	util_fmt_pair(FMT_DEFAULT, "thm_temp1_trans_count", "%d",
--		      le32toh(log->thm_temp1_trans_count));
-+		      le32toh((__force uint32_t)log->thm_temp1_trans_count));
- 	util_fmt_pair(FMT_DEFAULT, "thm_temp2_trans_count", "%d",
--		      le32toh(log->thm_temp2_trans_count));
-+		      le32toh((__force uint32_t)log->thm_temp2_trans_count));
- 	util_fmt_pair(FMT_DEFAULT, "thm_temp1_total_time", "%d",
--		      le32toh(log->thm_temp1_total_time));
-+		      le32toh((__force uint32_t)log->thm_temp1_total_time));
- 	util_fmt_pair(FMT_DEFAULT, "thm_temp2_total_time", "%d",
--		      le32toh(log->thm_temp2_total_time));
-+		      le32toh((__force uint32_t)log->thm_temp2_total_time));
- 	util_fmt_obj_end(); /* smart-log */
- 
- 	if (ctx->opts.smart_blob)
--- 
-2.55.0
-

diff --git a/s390utils-2.44.0-fedora.patch b/s390utils-2.44.0-fedora.patch
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/s390utils-2.44.0-fedora.patch

diff --git a/s390utils.spec b/s390utils.spec
index dc48027..11dbcc4 100644
--- a/s390utils.spec
+++ b/s390utils.spec
@@ -16,8 +16,8 @@
 
 Name:           s390utils
 Summary:        Utilities and daemons for IBM z Systems
-Version:        2.43.1
-Release:        2%{?dist}
+Version:        2.44.0
+Release:        1%{?dist}
 Epoch:          2
 # MIT covers nearly all the files, except init files (LGPL-2.1-or-later)
 #
@@ -78,7 +78,7 @@ Patch0:         s390-tools-zipl-invert-script-options.patch
 Patch1:         s390-tools-zipl-blscfg-rpm-nvr-sort.patch
 
 # upstream fixes/updates
-Patch100:       s390utils-%{version}-fedora.patch
+#Patch100:       s390utils-%%{version}-fedora.patch
 
 # https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval
 ExcludeArch:    %{ix86}
@@ -104,7 +104,6 @@ Requires:       s390utils-ziomon = %{epoch}:%{version}-%{release}
 Requires:       s390utils-se-data = %{epoch}:%{version}-%{release}
 %endif
 
-BuildRequires:  git
 BuildRequires:  make
 BuildRequires:  gcc-c++
 BuildRequires:  glib2-devel
@@ -125,8 +124,7 @@ The s390utils packages contain a set of user space utilities that should to
 be used together with the zSeries (s390) Linux kernel and device drivers.
 
 %prep
-# git_am method needed for the patchset with file renamings
-%autosetup -n s390-tools-%{version} -p1 -S git_am
+%autosetup -n s390-tools-%{version} -p1
 
 %if 0%{?rhel}
 pushd rust
@@ -1147,6 +1145,9 @@ User-space development files for the s390/s390x architecture.
 
 
 %changelog
+* Fri Jul 31 2026 Dan Horák <dan[at]danny.cz> - 2:2.44.0-1
+- rebased to 2.44.0 (rhbz#2509807)
+
 * Mon Jul 27 2026 Dan Horák <dan[at]danny.cz> - 2:2.43.1-2
 - include zpcimon feature
 

diff --git a/sources b/sources
index 4ef4b94..55b8768 100644
--- a/sources
+++ b/sources
@@ -1,2 +1,2 @@
-SHA512 (s390-tools-2.43.1.tar.gz) = 4e3811a4813a8b5ba307a79686302c00531da02b1f83c5d9ccbc28f6d5159a18eacd5581bca56a58947ddf688116231dc14338085d40231539ce97858ba00605
-SHA512 (s390-tools-2.43.1-rust-vendor.tar.xz) = e7357303fb2243b23034dd16d7c4ef641ab141ad4b3301b7245f2c1886db3413a7a03e7ac718549532f3ca50da3fdd0408e99c3254b5aa1bad89c5cfe4ff842c
+SHA512 (s390-tools-2.44.0.tar.gz) = 6f2f7fa45573b1a2515c4ea143ff0877711713724c737f9aaa4f853f6142f215628c10d1827f94cf54a50c1fec757fd3710f3e4b60f6125b0ee952002e43dbf7
+SHA512 (s390-tools-2.44.0-rust-vendor.tar.xz) = 7c0708a6593d9a2ff307e9e46c63f191532170db43f7f5e4f68c64673dbb7f1dae5663f60236d54b0c67d9bbc3b523aedcdf8747377e63f82f3767586fa3e8c4

                 reply	other threads:[~2026-07-31 15:24 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178551145592.1.14776496512583733006.rpms-s390utils-a05200ed603b@fedoraproject.org \
    --to=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox