From f9fbe79e4f04108bd1e894a22c57cbfa87d12f41 Mon Sep 17 00:00:00 2001 From: Niklas Schnelle Date: Mon, 31 Oct 2022 14:11:39 +0100 Subject: [PATCH] ipl_tools: Fix chreipl node for NVMes with CONFIG_NVME_MULTIPATH When the kernel is build with CONFIG_NVME_MULTIPATH enabled and an NVMe where the driver exposes its controller separately is used, chreipl node on a mount point of the NVMe fails. The failure occurs because chreipl tries to get the function_id from the NVMe's nvmeXnY block device via the path '/sys/block/nvmeXnY/device/device/function_id' which does not exist. The underlying problem is that with NVMe multipath support the PCI function is not associated directly with a particular NVMe namespace but instead with the entire NVMe device which may host multiple NVMe namespaces. The correct way to get from the block device to the underlying PCI device and its function ID is then to extract the device name i.e. the 'nvmeX' part from 'nvmeXnY' and use that to get the function ID via '/sys/class/nvme/nvme/device/function_id'. Fixes: 0472b5ea5c97 ("ipl-tools: Add nvme device support to lsreipl/chreipl") Reviewed-by: Gerald Schaefer Signed-off-by: Niklas Schnelle Signed-off-by: Steffen Eiden --- ipl_tools/ipl_tools.h | 1 + ipl_tools/nvme.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ipl_tools/ipl_tools.h b/ipl_tools/ipl_tools.h index 576d33a8..cd9167f0 100644 --- a/ipl_tools/ipl_tools.h +++ b/ipl_tools/ipl_tools.h @@ -75,6 +75,7 @@ extern void fcp_busid_get(const char *device, char *devno); * NVME */ #define FID_MAX_LEN 11 /* 8 characters + 0x + null */ +#define NVME_DEV_MAX_LEN 15 /* "nvme" + u32 in decimal + null */ #define NVME_PATH_MAX (PATH_MAX + NAME_MAX + 1) extern void nvme_fid_get(const char *device, char *fid); diff --git a/ipl_tools/nvme.c b/ipl_tools/nvme.c index 2a959729..05c2b87c 100644 --- a/ipl_tools/nvme.c +++ b/ipl_tools/nvme.c @@ -18,15 +18,31 @@ #include "lib/util_file.h" #include "ipl_tools.h" +static void nvme_dev_from_bdev(char *dev_name) +{ + char *delim = strrchr(dev_name, 'n'); + + if (delim) + *delim = 0; +} + /* * Return the fid of a device */ void nvme_fid_get(const char *device, char *fid) { char path[PATH_MAX], buf[FID_MAX_LEN]; + char nvme_dev[NVME_DEV_MAX_LEN]; - snprintf(path, PATH_MAX, "/sys/block/%s/device/device/function_id", - device); + /* + * An NVMe may present multiple namespaces and thus block devices, even + * before partitioning, so we need the nvme part of the block + * device name to get to the PCI function ID. + */ + util_strlcpy(nvme_dev, device, sizeof(nvme_dev)); + nvme_dev_from_bdev(nvme_dev); + + snprintf(path, PATH_MAX, "/sys/class/nvme/%s/device/function_id", nvme_dev); if (util_file_read_line(buf, FID_MAX_LEN, path)) ERR_EXIT_ERRNO("Could not read from \"%s\"", path);