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<X>/device/function_id'.

Fixes: 0472b5ea5c ("ipl-tools: Add nvme device support to lsreipl/chreipl")
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Niklas Schnelle
2022-10-31 14:11:39 +01:00
committed by Steffen Eiden
parent 3cc0b4cdea
commit f9fbe79e4f
2 changed files with 19 additions and 2 deletions

View File

@@ -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);

View File

@@ -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<NUM> 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);