ieee1275/powerpc: implements fibre channel discovery for ofpathname

Resolves: #RHEL-53369

Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
This commit is contained in:
Nicolas Frayer 2026-06-18 11:11:04 +02:00
parent eb2783a08c
commit c4ea783e4d
8 changed files with 1559 additions and 1 deletions

View File

@ -0,0 +1,120 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Thu, 18 Jun 2026 10:49:54 +0200
Subject: [PATCH] ieee1275/powerpc: implements fibre channel discovery for
ofpathname
grub-ofpathname doesn't work with fibre channel because there is no
function currently implemented for it.
This patch enables it by prividing a function that looks for the port
name, building the entire path for OF devices.
Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Part-of: <https://gitlab.freedesktop.org/gnu-grub/grub/-/merge_requests/146>
---
grub-core/osdep/linux/ofpath.c | 58 +++++++++++++++++++++---------------------
1 file changed, 29 insertions(+), 29 deletions(-)
diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
index cc849d9c94c3..9ba1db74aadf 100644
--- a/grub-core/osdep/linux/ofpath.c
+++ b/grub-core/osdep/linux/ofpath.c
@@ -351,36 +351,36 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi
return ret;
}
-
+#define BNAME_SIZE 150
static void
-of_fc_port_name(const char *path, const char *subpath, char *port_name)
+of_fc_port_name (const char *path, const char *subpath, char *port_name)
{
char *bname, *basepath, *p;
int fd;
- bname = xmalloc(sizeof(char)*150);
- basepath = xmalloc(strlen(path));
+ bname = xmalloc (sizeof (char) * BNAME_SIZE);
+ basepath = xmalloc (strlen (path));
/* Generate the path to get port name information from the drive */
- strncpy(basepath,path,subpath-path);
- basepath[subpath-path-1] = '\0';
- p = get_basename(basepath);
- snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p);
+ strncpy (basepath, path, subpath-path);
+ basepath[subpath-path - 1] = '\0';
+ p = get_basename (basepath);
+ snprintf (bname, sizeof (char) * BNAME_SIZE, "%s/fc_transport/%s/port_name", basepath, p);
/* Read the information from the port name */
fd = open (bname, O_RDONLY);
if (fd < 0)
grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno));
- if (read(fd,port_name,sizeof(char)*19) < 0)
+ if (read (fd, port_name, sizeof (char) *19) < 0)
grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno));
- sscanf(port_name,"0x%s",port_name);
-
- close(fd);
+ sscanf (port_name, "0x%s", port_name);
- free(bname);
- free(basepath);
+ close (fd);
+
+ free (bname);
+ free (basepath);
}
#ifdef __sparc__
@@ -610,16 +610,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
digit_string = trailing_digits (device);
if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0)
{
- if(strstr(of_path,"vfc-client"))
- {
- char * port_name = xmalloc(sizeof(char)*17);
- of_fc_port_name(sysfs_path, p, port_name);
-
- snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
- free(port_name);
- }
+ if (strstr (of_path, "vfc-client"))
+ {
+ char * port_name = xmalloc (sizeof (char) * 17);
+ of_fc_port_name (sysfs_path, p, port_name);
+
+ snprintf (disk, sizeof (disk), "/%s@%s", disk_name, port_name);
+ free (port_name);
+ }
else
- {
+ {
unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun;
if (*digit_string == '\0')
{
@@ -634,12 +634,12 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
"/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1));
}
}
- } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){
- char * port_name = xmalloc(sizeof(char)*17);
- of_fc_port_name(sysfs_path, p, port_name);
-
- snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name);
- free(port_name);
+ } else if (strstr (of_path, "fibre-channel") || (strstr (of_path, "vfc-client"))){
+ char * port_name = xmalloc (sizeof (char) * 17);
+ of_fc_port_name (sysfs_path, p, port_name);
+
+ snprintf (disk, sizeof (disk), "/%s@%s", disk_name, port_name);
+ free (port_name);
}
else
{

View File

@ -0,0 +1,143 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Mon, 23 Feb 2026 19:14:07 +0530
Subject: [PATCH] ieee1275: implement FCP methods for WWPN and LUNs
This patch enables the fcp-targets and fcp-luns methods which are
responsible to get WWPNs and LUNs for fibre channel devices.
Those methods are specially necessary if the boot directory and grub
installation are in different FCP disks, allowing the dev_iterate()
to find the WWPNs and LUNs when called by searchfs.uuid tool.
Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Part-of: <https://gitlab.freedesktop.org/gnu-grub/grub/-/merge_requests/146>
---
grub-core/disk/ieee1275/ofdisk.c | 111 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 110 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
index abb5082cdbfc..a16300a94745 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -223,7 +223,116 @@ dev_iterate_real (const char *name, const char *path)
static void
dev_iterate (const struct grub_ieee1275_devalias *alias)
{
- if (grub_strcmp (alias->type, "vscsi") == 0)
+ if (grub_strcmp (alias->type, "fcp") == 0)
+ {
+ /*
+ * If we are dealing with fcp devices, we need
+ * to find the WWPNs and LUNs to iterate them
+ */
+ grub_ieee1275_ihandle_t ihandle;
+ grub_uint64_t *ptr_targets, *ptr_luns, k, l;
+ unsigned int i, j, pos;
+ char *buf, *bufptr;
+ struct set_fcp_targets_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_cell_t ihandle;
+ grub_ieee1275_cell_t catch_result;
+ grub_ieee1275_cell_t nentries;
+ grub_ieee1275_cell_t table;
+ } args_targets;
+
+ struct set_fcp_luns_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_cell_t ihandle;
+ grub_ieee1275_cell_t wwpn_h;
+ grub_ieee1275_cell_t wwpn_l;
+ grub_ieee1275_cell_t catch_result;
+ grub_ieee1275_cell_t nentries;
+ grub_ieee1275_cell_t table;
+ } args_luns;
+
+ struct args_ret
+ {
+ grub_uint64_t addr;
+ grub_uint64_t len;
+ };
+
+ if (grub_ieee1275_open (alias->path, &ihandle))
+ {
+ grub_dprintf ("disk", "failed to open the disk while iterating FCP disk path=%s\n", alias->path);
+ return;
+ }
+
+ /* Setup the fcp-targets method to call via pfw*/
+ INIT_IEEE1275_COMMON (&args_targets.common, "call-method", 2, 3);
+ args_targets.method = (grub_ieee1275_cell_t) "fcp-targets";
+ args_targets.ihandle = ihandle;
+
+ /* Setup the fcp-luns method to call via pfw */
+ INIT_IEEE1275_COMMON (&args_luns.common, "call-method", 4, 3);
+ args_luns.method = (grub_ieee1275_cell_t) "fcp-luns";
+ args_luns.ihandle = ihandle;
+ if (IEEE1275_CALL_ENTRY_FN (&args_targets) == -1)
+ {
+ grub_dprintf ("disk", "failed to get the targets while iterating FCP disk path=%s\n", alias->path);
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+ buf = grub_malloc (grub_strlen (alias->path) + 32 + 32);
+ if (!buf)
+ {
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+ bufptr = grub_stpcpy (buf, alias->path);
+
+ /*
+ * Iterate over entries returned by pfw. Each entry contains a
+ * pointer to wwpn table and his length.
+ */
+ struct args_ret *targets_table = (struct args_ret *) (args_targets.table);
+ for (i = 0; i < args_targets.nentries; i++)
+ {
+ ptr_targets = (grub_uint64_t*) targets_table[i].addr;
+ /* Iterate over all wwpns in given table */
+ for(k = 0; k < targets_table[i].len; k++)
+ {
+ args_luns.wwpn_l = (grub_ieee1275_cell_t) (*ptr_targets);
+ args_luns.wwpn_h = (grub_ieee1275_cell_t) (*ptr_targets >> 32);
+ pos = grub_snprintf (bufptr, 32, "/disk@%" PRIxGRUB_UINT64_T,
+ grub_get_unaligned64 (*ptr_targets++));
+ /* Get the luns for given wwpn target */
+ if (IEEE1275_CALL_ENTRY_FN (&args_luns) == -1)
+ {
+ grub_dprintf ("disk", "failed to get the LUNS while iterating FCP disk path=%s\n", buf);
+ grub_ieee1275_close (ihandle);
+ grub_free (buf);
+ return;
+ }
+ struct args_ret *luns_table = (struct args_ret *) (args_luns.table);
+
+ /* Iterate over all LUNs */
+ for(j = 0; j < args_luns.nentries; j++)
+ {
+ ptr_luns = (grub_uint64_t*) luns_table[j].addr;
+ for(l = 0; l < luns_table[j].len; l++)
+ {
+ grub_snprintf (&bufptr[pos], 30, ",%" PRIxGRUB_UINT64_T,
+ grub_get_unaligned64 (*ptr_luns++));
+ dev_iterate_real (buf, buf);
+ }
+ }
+ }
+ }
+ grub_ieee1275_close (ihandle);
+ grub_free (buf);
+ return;
+ }
+ else if (grub_strcmp (alias->type, "vscsi") == 0)
{
static grub_ieee1275_ihandle_t ihandle;
struct set_color_args

View File

@ -0,0 +1,63 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Mon, 23 Feb 2026 19:14:08 +0530
Subject: [PATCH] ieee1275: change the logic of ieee1275_get_devargs()
Usually grub will parse the PFW arguments by searching for the first occurence of the character ':'.
However, we can have this char more than once on NQN.
This patch changes the logic to find the last occurence of this char so we can get the proper values
for NVMeoFC
Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Part-of: <https://gitlab.freedesktop.org/gnu-grub/grub/-/merge_requests/146>
---
grub-core/kern/ieee1275/openfw.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c
index 0278054c61e6..de0b8c299285 100644
--- a/grub-core/kern/ieee1275/openfw.c
+++ b/grub-core/kern/ieee1275/openfw.c
@@ -324,7 +324,7 @@ grub_claimmap (grub_addr_t addr, grub_size_t size)
static char *
grub_ieee1275_get_devargs (const char *path)
{
- char *colon = grub_strchr (path, ':');
+ char *colon = grub_strrchr (path, ':');
if (! colon)
return 0;
@@ -339,6 +339,21 @@ grub_ieee1275_get_devname (const char *path)
char *colon = grub_strchr (path, ':');
int pathlen = grub_strlen (path);
struct grub_ieee1275_devalias curalias;
+
+ /* Check some special cases */
+ if (grub_strstr (path, "nvme-of"))
+ {
+ char *namespace_split = grub_strstr (path, "/namespace@");
+ if (namespace_split)
+ {
+ colon = grub_strchr (namespace_split, ':');
+ }
+ else
+ {
+ colon = NULL;
+ }
+ }
+
if (colon)
pathlen = (int)(colon - path);
@@ -579,7 +594,7 @@ grub_ieee1275_get_boot_dev (void)
return NULL;
}
- bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64);
+ bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64 + 256);
if (! bootpath)
{
grub_print_error ();

View File

@ -0,0 +1,547 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Mon, 23 Feb 2026 19:14:10 +0530
Subject: [PATCH] ieee1275: ofpath enable NVMeoF logical device translate
This patch adds code to enable the translation of logical devices to the of NVMeoFC paths.
Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Part-of: <https://gitlab.freedesktop.org/gnu-grub/grub/-/merge_requests/146>
---
grub-core/osdep/linux/ofpath.c | 431 ++++++++++++++++++++++++++++++++++++++++-
include/grub/util/ofpath.h | 28 +++
2 files changed, 450 insertions(+), 9 deletions(-)
diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
index 9ba1db74aadf..54094a87576b 100644
--- a/grub-core/osdep/linux/ofpath.c
+++ b/grub-core/osdep/linux/ofpath.c
@@ -137,7 +137,7 @@ trim_newline (char *path)
*end-- = '\0';
}
-#define MAX_DISK_CAT 64
+#define MAX_DISK_CAT 512
static char *
find_obppath (const char *sysfs_path_orig)
@@ -313,6 +313,91 @@ get_basename(char *p)
return ret;
}
+int
+add_filename_to_pile (char *filename, struct ofpath_files_list_root* root)
+{
+ struct ofpath_files_list_node* file;
+
+ file = malloc (sizeof (struct ofpath_files_list_node));
+ if (!file)
+ return -1;
+
+ file->filename = malloc (sizeof (char) * 1024);
+ if (!file->filename)
+ {
+ free (file);
+ return -1;
+ }
+
+ grub_strcpy (file->filename, filename);
+ if (root->first == NULL)
+ {
+ root->items = 1;
+ root->first = file;
+ file->next = NULL;
+ }
+ else
+ {
+ root->items++;
+ file->next = root->first;
+ root->first = file;
+ }
+
+ return 0;
+}
+
+void
+find_file (char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth)
+{
+ struct dirent *ep;
+ struct stat statbuf;
+ DIR *dp;
+ int ret_val=0;
+ char* full_path;
+
+ if (depth > max_depth)
+ {
+ return;
+ }
+
+ if ((dp = opendir (directory)) == NULL)
+ {
+ return;
+ }
+
+ full_path = malloc (1024 * sizeof (char));
+ if (!full_path)
+ return;
+
+ while ((ep = readdir(dp)) != NULL)
+ {
+ snprintf (full_path, 1024, "%s/%s", directory, ep->d_name);
+ lstat (full_path, &statbuf);
+
+ if (S_ISLNK (statbuf.st_mode))
+ {
+ continue;
+ }
+
+ if (!strcmp (ep->d_name, ".") || !strcmp(ep->d_name, ".."))
+ {
+ continue;
+ }
+
+ if (!strcmp (ep->d_name, filename))
+ {
+ ret_val = add_filename_to_pile (full_path, root);
+ if (ret_val == -1)
+ continue;
+ }
+
+ find_file (filename, full_path, root, max_depth, depth+1);
+ }
+
+ free (full_path);
+ closedir (dp);
+}
+
static char *
of_path_of_vdisk(const char *sys_devname __attribute__((unused)),
const char *device,
@@ -383,7 +468,257 @@ of_fc_port_name (const char *path, const char *subpath, char *port_name)
free (basepath);
}
-#ifdef __sparc__
+void
+free_ofpath_files_list (struct ofpath_files_list_root* root)
+{
+ struct ofpath_files_list_node* node = root->first;
+ struct ofpath_files_list_node* next;
+
+ while (node!=NULL)
+ {
+ next = node->next;
+ free (node->filename);
+ free (node);
+ node = next;
+ }
+
+ free (root);
+ return;
+}
+
+char*
+of_find_fc_host (char* host_wwpn)
+{
+ FILE* fp;
+ char *buf;
+ char *ret_val;
+ char portname_filename[sizeof ("port_name")] = "port_name";
+ char devices_path[sizeof ("/sys/devices")] = "/sys/devices";
+ struct ofpath_files_list_root* portnames_file_list;
+ struct ofpath_files_list_node* node;
+
+ ret_val = malloc (sizeof (char) * 1024);
+ if (!ret_val)
+ return NULL;
+
+ portnames_file_list = malloc (sizeof (struct ofpath_files_list_root));
+ if (!portnames_file_list)
+ {
+ free (ret_val);
+ return NULL;
+ }
+
+ portnames_file_list->items = 0;
+ portnames_file_list->first = NULL;
+ find_file (portname_filename, devices_path, portnames_file_list, 10, 0);
+ node = portnames_file_list->first;
+
+ while (node != NULL)
+ {
+ fp = fopen(node->filename, "r");
+ if (!fp)
+ {
+ node = node->next;
+ continue;
+ }
+
+ buf = malloc (sizeof (char) * 512);
+ if (!buf)
+ break;
+
+ fscanf (fp, "%s", buf);
+ fclose (fp);
+
+ if ((strcmp (buf, host_wwpn) == 0) && grub_strstr (node->filename, "fc_host"))
+ {
+ free (buf);
+ grub_strcpy (ret_val, node->filename);
+ free_ofpath_files_list (portnames_file_list);
+ return ret_val;
+ }
+
+ node = node->next;
+ free (buf);
+ }
+ free_ofpath_files_list (portnames_file_list);
+ free (ret_val);
+ return NULL;
+}
+
+int
+of_path_get_nvmeof_adapter_info (char* sysfs_path,
+ struct ofpath_nvmeof_info* nvmeof_info)
+{
+ FILE *fp;
+ char *buf, *buf2, *buf3;
+
+ nvmeof_info->host_wwpn = malloc (sizeof (char) * 256);
+ nvmeof_info->target_wwpn = malloc (sizeof (char) * 256);
+ nvmeof_info->nqn = malloc (sizeof (char) * 256);
+
+ if (nvmeof_info->host_wwpn == NULL || nvmeof_info->target_wwpn == NULL || nvmeof_info->nqn == NULL)
+ {
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ return -1;
+ }
+
+ buf = malloc (sizeof (char) * 512);
+ if (!buf)
+ {
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ return -1;
+ }
+
+ snprintf (buf, 512, "%s/subsysnqn", sysfs_path);
+ if (! (fp = fopen (buf, "r")) ||
+ fscanf (fp, "%s", nvmeof_info->nqn) != 1)
+ {
+ if (fp)
+ fclose (fp);
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ free (buf);
+ return -1;
+ }
+ fclose (fp);
+
+ snprintf (buf, 512, "%s/cntlid", sysfs_path);
+ if (! (fp = fopen (buf, "r")) ||
+ fscanf (fp, "%u", &(nvmeof_info->cntlid)) != 1)
+ {
+ if (fp)
+ fclose (fp);
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ free (buf);
+ return -1;
+ }
+ fclose (fp);
+
+ snprintf (buf, 512, "%s/address", sysfs_path);
+ buf2 = NULL;
+ fp = NULL;
+ if (! (buf2 = malloc (sizeof (char) * 512)) ||
+ ! (fp = fopen (buf, "r")) ||
+ fscanf (fp, "%s", buf2) != 1)
+ {
+ if (fp)
+ fclose (fp);
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ free (buf);
+ free (buf2);
+ return -1;
+ }
+
+ fclose (fp);
+
+ if (! (buf3 = strrchr (buf2, '-')))
+ {
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ free (buf);
+ free (buf2);
+ return -1;
+ }
+ grub_memcpy (nvmeof_info->host_wwpn, buf3 + 1, 256);
+ if (! (buf3 = strchr (buf2, '-')) ||
+ ! (buf3 = strchr (buf3 + 1, '-')) ||
+ ! (buf3 = strchr (buf3 + 1, 'x')))
+ {
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ free (buf);
+ free (buf2);
+ return -1;
+ }
+ grub_memcpy (nvmeof_info->target_wwpn, buf3 + 1, 256);
+ buf3 = strchr (nvmeof_info->target_wwpn, ',');
+ if (buf3)
+ *buf3 = '\0';
+ free (buf);
+ free (buf2);
+ return 0;
+}
+
+#define OFPATH_MAX_UINT_HEX_DIGITS 8
+#define OFPATH_MAX_INT_DIGITS 10
+
+static char *
+of_path_get_nvme_controller_name_node (const char* devname)
+{
+ char *controller_node, *end;
+
+ controller_node = xstrdup (devname);
+ end = grub_strchr (controller_node + 1, 'n');
+ if (end != NULL)
+ {
+ *end = '\0';
+ }
+
+ return controller_node;
+}
+
+unsigned int
+of_path_get_nvme_nsid (const char* devname)
+{
+ unsigned int nsid;
+ char *sysfs_path, *buf;
+ FILE *fp;
+
+ buf = malloc (sizeof(char) * 512);
+ if (!buf)
+ return 0;
+
+ sysfs_path = block_device_get_sysfs_path_and_link (devname);
+ snprintf (buf, 512, "%s/%s/nsid", sysfs_path, devname);
+ fp = fopen(buf, "r");
+ if (!fp)
+ {
+ free (sysfs_path);
+ free (buf);
+ return 0;
+ }
+
+ fscanf (fp, "%u", &(nsid));
+ fclose (fp);
+
+ free (sysfs_path);
+ free (buf);
+ return nsid;
+}
+
+static char *
+nvme_get_syspath (const char *nvmedev)
+{
+ char *sysfs_path;
+
+ sysfs_path = block_device_get_sysfs_path_and_link (nvmedev);
+ if (strstr (sysfs_path, "nvme-subsystem"))
+ {
+ char *controller_node = of_path_get_nvme_controller_name_node (nvmedev);
+ char *buf = xmalloc (strlen (sysfs_path) + strlen ("/") + strlen (controller_node) + 1);
+ strcpy (buf, sysfs_path);
+ strcat (buf, "/");
+ strcat (buf, controller_node);
+ free (sysfs_path);
+ free (controller_node);
+ sysfs_path = xrealpath (buf);
+ free (buf);
+ }
+
+ return sysfs_path;
+}
+
static char *
of_path_of_nvme(const char *sys_devname __attribute__((unused)),
const char *device,
@@ -392,6 +727,8 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)),
{
char *sysfs_path, *of_path, disk[MAX_DISK_CAT];
const char *digit_string, *part_end;
+ int chars_written, ret_val;
+ struct ofpath_nvmeof_info* nvmeof_info;
digit_string = trailing_digits (device);
part_end = devicenode + strlen (devicenode) - 1;
@@ -411,15 +748,94 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)),
/* Remove the p. */
*end = '\0';
sscanf (digit_string, "%d", &part);
- snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1));
- sysfs_path = block_device_get_sysfs_path_and_link (nvmedev);
+ sysfs_path = nvme_get_syspath (nvmedev);
+
+ /* If is a NVMeoF */
+ if (strstr (sysfs_path, "nvme-fabrics"))
+ {
+ nvmeof_info = malloc (sizeof (struct ofpath_nvmeof_info));
+ if (!nvmeof_info)
+ {
+ free (nvmedev);
+ return NULL;
+ }
+
+ ret_val = of_path_get_nvmeof_adapter_info (sysfs_path, nvmeof_info);
+ if (ret_val == -1)
+ {
+ free (nvmedev);
+ free (nvmeof_info);
+ return NULL;
+ }
+
+ free (sysfs_path);
+ sysfs_path = of_find_fc_host (nvmeof_info->host_wwpn);
+ if (!sysfs_path)
+ {
+ free (nvmedev);
+ free (nvmeof_info->host_wwpn);
+ free (nvmeof_info->target_wwpn);
+ free (nvmeof_info->nqn);
+ free (nvmeof_info);
+ return NULL;
+ }
+
+ chars_written = snprintf (disk,sizeof(disk), "/nvme-of/controller@%s,%x:nqn=%s",
+ nvmeof_info->target_wwpn,0xffff,
+ nvmeof_info->nqn);
+ unsigned int nsid = of_path_get_nvme_nsid (nvmedev);
+ if (nsid)
+ {
+ snprintf (disk+chars_written, sizeof("/namespace@") + OFPATH_MAX_UINT_HEX_DIGITS + OFPATH_MAX_INT_DIGITS,
+ "/namespace@%x:%d", nsid, part);
+ }
+ free (nvmeof_info);
+ }
+ else
+ {
+ snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1));
+ }
free (nvmedev);
}
else
{
/* We do not have the parition. */
- snprintf (disk, sizeof (disk), "/disk@1");
- sysfs_path = block_device_get_sysfs_path_and_link (device);
+ sysfs_path = nvme_get_syspath (device);
+ if (strstr (sysfs_path, "nvme-fabrics"))
+ {
+ nvmeof_info = malloc (sizeof (struct ofpath_nvmeof_info));
+ if (!nvmeof_info)
+ return NULL;
+
+ ret_val = of_path_get_nvmeof_adapter_info (sysfs_path, nvmeof_info);
+ if (ret_val == -1)
+ {
+ free (nvmeof_info);
+ return NULL;
+ }
+
+ sysfs_path = of_find_fc_host (nvmeof_info->host_wwpn);
+ if (!sysfs_path)
+ {
+ free (nvmeof_info);
+ return NULL;
+ }
+
+ chars_written = snprintf (disk,sizeof(disk), "/nvme-of/controller@%s,%x:nqn=%s",
+ nvmeof_info->target_wwpn, 0xffff,
+ nvmeof_info->nqn);
+ unsigned int nsid = of_path_get_nvme_nsid (device);
+ if (nsid)
+ {
+ snprintf (disk+chars_written,sizeof("/namespace@") + sizeof(char) * OFPATH_MAX_UINT_HEX_DIGITS,
+ "/namespace@%x", nsid);
+ }
+ free (nvmeof_info);
+ }
+ else
+ {
+ snprintf (disk, sizeof (disk), "/disk@1");
+ }
}
of_path = find_obppath (sysfs_path);
@@ -430,7 +846,6 @@ of_path_of_nvme(const char *sys_devname __attribute__((unused)),
free (sysfs_path);
return of_path;
}
-#endif
static int
vendor_is_ATA(const char *path)
@@ -841,11 +1256,9 @@ grub_util_devname_to_ofpath (const char *sys_devname)
/* All the models I've seen have a devalias "floppy".
New models have no floppy at all. */
ofpath = xstrdup ("floppy");
-#ifdef __sparc__
else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm'
&& device[3] == 'e')
ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode);
-#endif
else
{
grub_util_warn (_("unknown device type %s"), device);
diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h
index b43c523cb267..7ab377c7cc43 100644
--- a/include/grub/util/ofpath.h
+++ b/include/grub/util/ofpath.h
@@ -3,4 +3,32 @@
char *grub_util_devname_to_ofpath (const char *devname);
+struct ofpath_files_list_node
+{
+ char* filename;
+ struct ofpath_files_list_node* next;
+};
+
+struct ofpath_files_list_root
+{
+ int items;
+ struct ofpath_files_list_node* first;
+};
+
+struct ofpath_nvmeof_info
+{
+ char* host_wwpn;
+ char* target_wwpn;
+ char* nqn;
+ int cntlid;
+ int nsid;
+};
+
+int of_path_get_nvmeof_adapter_info (char* sysfs_path, struct ofpath_nvmeof_info* nvmeof_info);
+unsigned int of_path_get_nvme_nsid (const char* devname);
+int add_filename_to_pile (char *filename, struct ofpath_files_list_root* root);
+void find_file (char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth);
+char* of_find_fc_host (char* host_wwpn);
+void free_ofpath_files_list (struct ofpath_files_list_root* root);
+
#endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */

View File

@ -0,0 +1,218 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Mon, 23 Feb 2026 19:14:11 +0530
Subject: [PATCH] ieee1275: support added for multiple nvme bootpaths
This patch sets mupltiple NVMe boot-devices for more robust boot.
Scenario where NVMe multipaths are available, all the available bootpaths (Max 5)
will be added as the boot-device.
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Part-of: <https://gitlab.freedesktop.org/gnu-grub/grub/-/merge_requests/146>
---
grub-core/osdep/linux/ofpath.c | 4 +-
grub-core/osdep/unix/platform.c | 122 +++++++++++++++++++++++++++++++++++++++-
include/grub/util/install.h | 3 +
include/grub/util/ofpath.h | 4 ++
4 files changed, 130 insertions(+), 3 deletions(-)
diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
index 54094a87576b..46b23820c8b8 100644
--- a/grub-core/osdep/linux/ofpath.c
+++ b/grub-core/osdep/linux/ofpath.c
@@ -209,7 +209,7 @@ find_obppath (const char *sysfs_path_orig)
}
}
-static char *
+char *
xrealpath (const char *in)
{
char *out;
@@ -697,7 +697,7 @@ of_path_get_nvme_nsid (const char* devname)
return nsid;
}
-static char *
+char *
nvme_get_syspath (const char *nvmedev)
{
char *sysfs_path;
diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c
index 55b8f4016248..8ca94e3ee0fe 100644
--- a/grub-core/osdep/unix/platform.c
+++ b/grub-core/osdep/unix/platform.c
@@ -28,6 +28,10 @@
#include <dirent.h>
#include <string.h>
#include <errno.h>
+#include <grub/util/ofpath.h>
+#include <stdbool.h>
+
+#define BOOTDEV_BUFFER 1000
static char *
get_ofpathname (const char *dev)
@@ -176,6 +180,111 @@ grub_install_register_efi (grub_device_t efidir_grub_dev,
return ret;
}
+
+char *
+add_multiple_nvme_bootdevices (const char *install_device)
+{
+ char *sysfs_path, *nvme_ns, *ptr, *non_splitter_path;
+ unsigned int nsid;
+ char *multipath_boot, *ofpath, *ext_dir;
+ struct dirent *ep, *splitter_ep;
+ DIR *dp, *splitter_dp;
+ char *cntl_id, *dirR1, *dirR2, *splitter_info_path;
+ bool is_FC = false, is_splitter = false;
+
+ nvme_ns = grub_strstr (install_device, "nvme");
+ nsid = of_path_get_nvme_nsid (nvme_ns);
+ if (nsid == 0)
+ return NULL;
+
+ sysfs_path = nvme_get_syspath (nvme_ns);
+ ofpath = xasprintf ("%s", get_ofpathname (nvme_ns));
+
+ if (grub_strstr (ofpath, "fibre-channel"))
+ {
+ char *tmp = xasprintf ("%s/device", sysfs_path);
+ free (sysfs_path);
+ sysfs_path = tmp;
+ is_FC = true;
+ }
+ else
+ {
+ char *tmp = xasprintf ("%s/subsystem", sysfs_path);
+ free (sysfs_path);
+ sysfs_path = tmp;
+ is_FC = false;
+ }
+ if (is_FC == false)
+ {
+ cntl_id = grub_strstr (nvme_ns, "e");
+ dirR1 = xasprintf ("nvme%c",cntl_id[1]);
+
+ splitter_info_path = xasprintf ("/sys/block/%s/device", nvme_ns);
+ splitter_dp = opendir (splitter_info_path);
+ if (!splitter_dp)
+ return NULL;
+
+ while ((splitter_ep = readdir (splitter_dp)) != NULL)
+ {
+ if (grub_strstr (splitter_ep->d_name, "nvme"))
+ {
+ if (grub_strstr (splitter_ep->d_name, dirR1))
+ continue;
+
+ ext_dir = grub_strchr (splitter_ep->d_name, 'e');
+ if (grub_strchr (ext_dir, 'n') == NULL)
+ {
+ dirR2 = xasprintf("%s", splitter_ep->d_name);
+ is_splitter = true;
+ break;
+ }
+ }
+ }
+ closedir (splitter_dp);
+ }
+ sysfs_path = xrealpath (sysfs_path);
+ dp = opendir (sysfs_path);
+ if (!dp)
+ return NULL;
+
+ ptr = multipath_boot = xmalloc (BOOTDEV_BUFFER);
+ if (is_splitter == false && is_FC == false)
+ {
+ non_splitter_path = xasprintf ("%s/namespace@%x:1 ", get_ofpathname (dirR1), nsid);
+ strncpy (ptr, non_splitter_path, strlen (non_splitter_path));
+ ptr += strlen (non_splitter_path);
+ free (non_splitter_path);
+ }
+ else
+ {
+ while ((ep = readdir (dp)) != NULL)
+ {
+ char *path;
+
+ if (grub_strstr (ep->d_name, "nvme") != NULL)
+ {
+ if (is_FC == false && grub_strstr (ep->d_name, dirR1) == NULL &&
+ grub_strstr (ep->d_name, dirR2) == NULL)
+ continue;
+ path = xasprintf ("%s/namespace@%x ", get_ofpathname (ep->d_name), nsid);
+ if ((strlen (multipath_boot) + strlen (path)) > BOOTDEV_BUFFER)
+ {
+ grub_util_warn (_("Maximum five entries are allowed in the bootlist"));
+ free (path);
+ break;
+ }
+ strncpy (ptr, path, strlen (path));
+ ptr += strlen (path);
+ free (path);
+ }
+ }
+ }
+ *--ptr = '\0';
+ closedir (dp);
+
+ return multipath_boot;
+}
+
void
grub_install_register_ieee1275 (int is_prep, const char *install_device,
int partno, const char *relpath)
@@ -215,8 +324,19 @@ grub_install_register_ieee1275 (int is_prep, const char *install_device,
}
*ptr = '\0';
}
+ else if (grub_strstr (install_device, "nvme"))
+ {
+ boot_device = add_multiple_nvme_bootdevices (install_device);
+ }
else
- boot_device = get_ofpathname (install_device);
+ {
+ boot_device = get_ofpathname (install_device);
+ if (grub_strstr (boot_device, "nvme-of"))
+ {
+ free (boot_device);
+ boot_device = add_multiple_nvme_bootdevices (install_device);
+ }
+ }
if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device",
boot_device, NULL }))
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index ccf799ff7169..5b4513904889 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -238,6 +238,9 @@ grub_install_register_efi (grub_device_t efidir_grub_dev,
const char *efifile_path,
const char *efi_distributor);
+char *
+add_multiple_nvme_bootdevices (const char *install_device);
+
void
grub_install_register_ieee1275 (int is_prep, const char *install_device,
int partno, const char *relpath);
diff --git a/include/grub/util/ofpath.h b/include/grub/util/ofpath.h
index 7ab377c7cc43..9f9a753dcebb 100644
--- a/include/grub/util/ofpath.h
+++ b/include/grub/util/ofpath.h
@@ -30,5 +30,9 @@ int add_filename_to_pile (char *filename, struct ofpath_files_list_root* root);
void find_file (char* filename, char* directory, struct ofpath_files_list_root* root, int max_depth, int depth);
char* of_find_fc_host (char* host_wwpn);
void free_ofpath_files_list (struct ofpath_files_list_root* root);
+char* nvme_get_syspath (const char *nvmedev);
+unsigned int of_path_get_nvme_nsid (const char* devname);
+char* xrealpath (const char *in);
+
#endif /* ! GRUB_OFPATH_MACHINE_UTIL_HEADER */

View File

@ -0,0 +1,457 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Mon, 23 Feb 2026 19:14:09 +0530
Subject: [PATCH] ieee1275: add support for NVMeoFC
This patch implements the functions to scan and discovery of NVMeoFC.
Signed-off-by: Diego Domingos <diegodo@br.ibm.com>
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Part-of: <https://gitlab.freedesktop.org/gnu-grub/grub/-/merge_requests/146>
---
grub-core/disk/ieee1275/ofdisk.c | 418 +++++++++++++++++++++++++++++----------
1 file changed, 312 insertions(+), 106 deletions(-)
diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
index a16300a94745..cf0f003f90da 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -26,6 +26,10 @@
#include <grub/time.h>
#include <grub/safemath.h>
+#define EXTEND_PATH_64 64
+#define EXTEND_PATH_512 512
+#define TABLE_SIZE 256
+
static char *last_devpath;
static grub_ieee1275_ihandle_t last_ihandle;
@@ -220,117 +224,319 @@ dev_iterate_real (const char *name, const char *path)
return;
}
+static void
+dev_iterate_fcp_disks (const struct grub_ieee1275_devalias *alias)
+ {
+ /*
+ * If we are dealing with fcp devices, we need
+ * to find the WWPNs and LUNs to iterate them
+ */
+ grub_ieee1275_ihandle_t ihandle;
+ grub_uint64_t *ptr_targets, *ptr_luns, k, l;
+ unsigned int i, j, pos;
+ char *buf, *bufptr;
+ struct set_fcp_targets_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_cell_t ihandle;
+ grub_ieee1275_cell_t catch_result;
+ grub_ieee1275_cell_t nentries;
+ grub_ieee1275_cell_t table;
+ } args_targets;
+
+ struct set_fcp_luns_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_cell_t ihandle;
+ grub_ieee1275_cell_t wwpn_h;
+ grub_ieee1275_cell_t wwpn_l;
+ grub_ieee1275_cell_t catch_result;
+ grub_ieee1275_cell_t nentries;
+ grub_ieee1275_cell_t table;
+ } args_luns;
+
+ struct args_ret
+ {
+ grub_uint64_t addr;
+ grub_uint64_t len;
+ };
+ struct args_ret *targets_table;
+ struct args_ret *luns_table;
+
+ if (grub_ieee1275_open (alias->path, &ihandle))
+ {
+ grub_dprintf ("disk", "failed to open the disk while iterating FCP disk path=%s\n", alias->path);
+ return;
+ }
+
+ /* Setup the fcp-targets method to call via pfw*/
+ INIT_IEEE1275_COMMON (&args_targets.common, "call-method", 2, 3);
+ args_targets.method = (grub_ieee1275_cell_t) "fcp-targets";
+ args_targets.ihandle = ihandle;
+
+ /* Setup the fcp-luns method to call via pfw */
+ INIT_IEEE1275_COMMON (&args_luns.common, "call-method", 4, 3);
+ args_luns.method = (grub_ieee1275_cell_t) "fcp-luns";
+ args_luns.ihandle = ihandle;
+ if (IEEE1275_CALL_ENTRY_FN (&args_targets) == -1)
+ {
+ grub_dprintf ("disk", "failed to get the targets while iterating FCP disk path=%s\n", alias->path);
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+ /* Allocate memory for building the path */
+ buf = grub_malloc (grub_strlen (alias->path) + EXTEND_PATH_64);
+ if (!buf)
+ {
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+ bufptr = grub_stpcpy (buf, alias->path);
+
+ /*
+ * Iterate over entries returned by pfw. Each entry contains a
+ * pointer to wwpn table and his length.
+ */
+ targets_table = (struct args_ret *) (args_targets.table);
+ for (i = 0; i < args_targets.nentries; i++)
+ {
+ ptr_targets = (grub_uint64_t*) (grub_addr_t) targets_table[i].addr;
+ /* Iterate over all wwpns in given table */
+ for (k = 0; k < targets_table[i].len; k++)
+ {
+ args_luns.wwpn_l = (grub_ieee1275_cell_t) (*ptr_targets);
+ args_luns.wwpn_h = (grub_ieee1275_cell_t) (*ptr_targets >> 32);
+ pos = grub_snprintf (bufptr, 32, "/disk@%" PRIxGRUB_UINT64_T,
+ grub_get_unaligned64 ((const void *) ptr_targets));
+ ptr_targets++;
+ /* Get the luns for given wwpn target */
+ if (IEEE1275_CALL_ENTRY_FN (&args_luns) == -1)
+ {
+ grub_dprintf ("disk", "failed to get the LUNS while iterating FCP disk path=%s\n", buf);
+ grub_ieee1275_close (ihandle);
+ grub_free (buf);
+ return;
+ }
+ luns_table = (struct args_ret *) (args_luns.table);
+
+ /* Iterate over all LUNs */
+ for (j = 0; j < args_luns.nentries; j++)
+ {
+ ptr_luns = (grub_uint64_t*) (grub_addr_t) luns_table[j].addr;
+ for (l = 0; l < luns_table[j].len; l++)
+ {
+ grub_snprintf (&bufptr[pos], 30, ",%" PRIxGRUB_UINT64_T,
+ grub_get_unaligned64 ((const void *) ptr_luns));
+ ptr_luns++;
+ dev_iterate_real (buf, buf);
+ }
+ }
+ }
+ }
+ grub_ieee1275_close (ihandle);
+ grub_free (buf);
+ return;
+}
+
+static void
+dev_iterate_fcp_nvmeof (const struct grub_ieee1275_devalias *alias)
+{
+ char *bufptr;
+ grub_ieee1275_ihandle_t ihandle;
+
+ /* Create the structs for the parameters passing to PFW */
+ struct nvme_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t method;
+ grub_ieee1275_cell_t ihandle;
+ grub_ieee1275_cell_t catch_result;
+ grub_ieee1275_cell_t nentries;
+ grub_ieee1275_cell_t table;
+ } nvme_discovery_controllers_args, nvme_controllers_args, nvme_namespaces_args;
+
+ /* Create the structs for the results from PFW */
+ struct discovery_controllers_table_struct
+ {
+ grub_uint64_t table[TABLE_SIZE];
+ grub_uint32_t len;
+ } discovery_controllers_table;
+
+ /*
+ * struct nvme_controllers_table_entry
+ * this the return of nvme-controllers method tables, containing:
+ * - 2-byte controller ID
+ * - 256-byte transport address string
+ * - 256-byte field containing null-terminated NVM subsystem NQN string up to 223 characters
+ */
+ struct nvme_controllers_table_entry
+ {
+ grub_uint16_t id;
+ char wwpn[TABLE_SIZE];
+ char nqn[TABLE_SIZE];
+ };
+
+ struct nvme_controllers_table_entry_real
+ {
+ grub_uint16_t id;
+ char wwpn[TABLE_SIZE];
+ char nqn[TABLE_SIZE];
+ };
+
+ struct nvme_controllers_table_entry* nvme_controllers_table;
+ grub_uint32_t nvme_controllers_table_entries;
+ char *buf;
+ unsigned int i = 0;
+ int current_buffer_index;
+ int nvme_controller_index;
+ int bufptr_pos2;
+ grub_uint32_t namespace_index = 0;
+ struct nvme_controllers_table_entry* nvme_controllers_table_buf;
+
+ nvme_controllers_table = grub_malloc (sizeof (struct nvme_controllers_table_entry) * TABLE_SIZE);
+ /* Allocate memory for building the NVMeoF path */
+ buf = grub_malloc (grub_strlen (alias->path) + EXTEND_PATH_512);
+
+ if (!buf || !nvme_controllers_table)
+ {
+ grub_free (nvme_controllers_table);
+ grub_free (buf);
+ return;
+ }
+
+ /* Copy the alias->path to buf so we can work with */
+ bufptr = grub_stpcpy (buf, alias->path);
+ grub_snprintf (bufptr, 32, "/nvme-of");
+
+ /*
+ * Open the nvme-of layer
+ * Ex. /pci@bus/fibre-channel@@dev,func/nvme-of
+ */
+ if (grub_ieee1275_open (buf, &ihandle))
+ {
+ grub_dprintf ("disk", "failed to open the disk while iterating FCP disk path=%s\n", buf);
+ grub_free (nvme_controllers_table);
+ grub_free (buf);
+ return;
+ }
+
+ /*
+ * Call to nvme-discovery-controllers method from the nvme-of layer
+ * to get a list of the NVMe discovery controllers per the binding
+ */
+ INIT_IEEE1275_COMMON (&nvme_discovery_controllers_args.common, "call-method", 2, 2);
+ nvme_discovery_controllers_args.method = (grub_ieee1275_cell_t) "nvme-discovery-controllers";
+ nvme_discovery_controllers_args.ihandle = ihandle;
+ if (IEEE1275_CALL_ENTRY_FN (&nvme_discovery_controllers_args) == -1)
+ {
+ grub_dprintf ("disk", "failed to get the targets while iterating FCP disk path=%s\n", buf);
+ grub_free (nvme_controllers_table);
+ grub_free (buf);
+ grub_ieee1275_close (ihandle);
+ return;
+ }
+
+ /* After closing the device, the info is lost. So lets copy each buffer in the buffers table */
+ discovery_controllers_table.len = (grub_uint32_t) nvme_discovery_controllers_args.nentries;
+
+ for (i = 0; i < discovery_controllers_table.len; i++)
+ {
+ discovery_controllers_table.table[i] = ((grub_uint64_t*) nvme_discovery_controllers_args.table)[i];
+ }
+ grub_ieee1275_close (ihandle);
+ grub_dprintf ("ofdisk","NVMeoF: Found %d discovery controllers\n", discovery_controllers_table.len);
+
+ /* For each nvme discovery controller */
+ for (current_buffer_index = 0; current_buffer_index < (int) discovery_controllers_table.len; current_buffer_index++)
+ {
+ grub_snprintf (bufptr, 64, "/nvme-of/controller@%" PRIxGRUB_UINT64_T ",ffff",
+ discovery_controllers_table.table[current_buffer_index]);
+ grub_dprintf ("ofdisk", "nvmeof controller=%s\n", buf);
+ if (grub_ieee1275_open (buf, &ihandle))
+ {
+ grub_dprintf ("ofdisk", "failed to open the disk while getting nvme-controllers path=%s\n", buf);
+ continue;
+ }
+ INIT_IEEE1275_COMMON (&nvme_controllers_args.common, "call-method", 2, 2);
+ nvme_controllers_args.method = (grub_ieee1275_cell_t) "nvme-controllers";
+ nvme_controllers_args.ihandle = ihandle;
+ nvme_controllers_args.catch_result = 0;
+
+ if (IEEE1275_CALL_ENTRY_FN (&nvme_controllers_args) == -1)
+ {
+ grub_dprintf ("ofdisk", "failed to get the nvme-controllers while iterating FCP disk path\n");
+ grub_ieee1275_close (ihandle);
+ continue;
+ }
+
+ /* Copy the buffer list to nvme_controllers_table */
+ nvme_controllers_table_entries = ((grub_uint32_t) nvme_controllers_args.nentries);
+ nvme_controllers_table_buf = (struct nvme_controllers_table_entry*) nvme_controllers_args.table;
+ for (i = 0; i < nvme_controllers_table_entries; i++)
+ {
+ nvme_controllers_table[i].id = (grub_uint16_t) nvme_controllers_table_buf[i].id;
+ grub_strcpy (nvme_controllers_table[i].wwpn, nvme_controllers_table_buf[i].wwpn);
+ grub_strcpy (nvme_controllers_table[i].nqn, nvme_controllers_table_buf[i].nqn);
+ }
+ grub_ieee1275_close (ihandle);
+ grub_dprintf ("ofdisk", "NVMeoF: found %d nvme controllers\n", (int) nvme_controllers_args.nentries);
+
+ /* For each nvme controller */
+ for (nvme_controller_index = 0; nvme_controller_index < (int) nvme_controllers_args.nentries; nvme_controller_index++)
+ {
+ /*
+ * Open the nvme controller
+ * /pci@bus/fibre-channel@dev,func/nvme-of/controller@transport-addr,ctlr-id:nqn=tgt-subsystem-nqn
+ */
+ bufptr_pos2 = grub_snprintf (bufptr, 512, "/nvme-of/controller@%s,ffff:nqn=%s",
+ nvme_controllers_table[nvme_controller_index].wwpn,
+ nvme_controllers_table[nvme_controller_index].nqn);
+ grub_dprintf ("ofdisk", "NVMeoF: nvmeof controller=%s\n", buf);
+ if (grub_ieee1275_open (buf, &ihandle))
+ {
+ grub_dprintf ("ofdisk", "failed to open the path=%s\n", buf);
+ continue;
+ }
+ INIT_IEEE1275_COMMON (&nvme_namespaces_args.common, "call-method", 2, 2);
+ nvme_namespaces_args.method = (grub_ieee1275_cell_t) "get-namespace-list";
+ nvme_namespaces_args.ihandle = ihandle;
+ nvme_namespaces_args.catch_result = 0;
+
+ if (IEEE1275_CALL_ENTRY_FN (&nvme_namespaces_args) == -1)
+ {
+ grub_dprintf ("ofdisk", "failed to get the nvme-namespace-list while iterating FCP disk path\n");
+ grub_ieee1275_close (ihandle);
+ continue;
+ }
+ grub_uint32_t *namespaces = (grub_uint32_t*) nvme_namespaces_args.table;
+ grub_dprintf ("ofdisk", "NVMeoF: found %d namespaces\n", (int)nvme_namespaces_args.nentries);
+ grub_ieee1275_close (ihandle);
+ namespace_index = 0;
+ for (namespace_index=0; namespace_index < nvme_namespaces_args.nentries; namespace_index++)
+ {
+ grub_snprintf (bufptr+bufptr_pos2, 512, "/namespace@%"PRIxGRUB_UINT32_T, namespaces[namespace_index]);
+ grub_dprintf ("ofdisk", "NVMeoF: namespace=%s\n", buf);
+ dev_iterate_real (buf, buf);
+ }
+ dev_iterate_real (buf, buf);
+ }
+ }
+ grub_free (buf);
+ grub_free (nvme_controllers_table);
+ return;
+}
+
static void
dev_iterate (const struct grub_ieee1275_devalias *alias)
{
if (grub_strcmp (alias->type, "fcp") == 0)
{
- /*
- * If we are dealing with fcp devices, we need
- * to find the WWPNs and LUNs to iterate them
- */
- grub_ieee1275_ihandle_t ihandle;
- grub_uint64_t *ptr_targets, *ptr_luns, k, l;
- unsigned int i, j, pos;
- char *buf, *bufptr;
- struct set_fcp_targets_args
- {
- struct grub_ieee1275_common_hdr common;
- grub_ieee1275_cell_t method;
- grub_ieee1275_cell_t ihandle;
- grub_ieee1275_cell_t catch_result;
- grub_ieee1275_cell_t nentries;
- grub_ieee1275_cell_t table;
- } args_targets;
-
- struct set_fcp_luns_args
- {
- struct grub_ieee1275_common_hdr common;
- grub_ieee1275_cell_t method;
- grub_ieee1275_cell_t ihandle;
- grub_ieee1275_cell_t wwpn_h;
- grub_ieee1275_cell_t wwpn_l;
- grub_ieee1275_cell_t catch_result;
- grub_ieee1275_cell_t nentries;
- grub_ieee1275_cell_t table;
- } args_luns;
-
- struct args_ret
- {
- grub_uint64_t addr;
- grub_uint64_t len;
- };
-
- if (grub_ieee1275_open (alias->path, &ihandle))
- {
- grub_dprintf ("disk", "failed to open the disk while iterating FCP disk path=%s\n", alias->path);
- return;
- }
-
- /* Setup the fcp-targets method to call via pfw*/
- INIT_IEEE1275_COMMON (&args_targets.common, "call-method", 2, 3);
- args_targets.method = (grub_ieee1275_cell_t) "fcp-targets";
- args_targets.ihandle = ihandle;
-
- /* Setup the fcp-luns method to call via pfw */
- INIT_IEEE1275_COMMON (&args_luns.common, "call-method", 4, 3);
- args_luns.method = (grub_ieee1275_cell_t) "fcp-luns";
- args_luns.ihandle = ihandle;
- if (IEEE1275_CALL_ENTRY_FN (&args_targets) == -1)
- {
- grub_dprintf ("disk", "failed to get the targets while iterating FCP disk path=%s\n", alias->path);
- grub_ieee1275_close (ihandle);
- return;
- }
- buf = grub_malloc (grub_strlen (alias->path) + 32 + 32);
- if (!buf)
- {
- grub_ieee1275_close (ihandle);
- return;
- }
- bufptr = grub_stpcpy (buf, alias->path);
-
- /*
- * Iterate over entries returned by pfw. Each entry contains a
- * pointer to wwpn table and his length.
- */
- struct args_ret *targets_table = (struct args_ret *) (args_targets.table);
- for (i = 0; i < args_targets.nentries; i++)
- {
- ptr_targets = (grub_uint64_t*) targets_table[i].addr;
- /* Iterate over all wwpns in given table */
- for(k = 0; k < targets_table[i].len; k++)
- {
- args_luns.wwpn_l = (grub_ieee1275_cell_t) (*ptr_targets);
- args_luns.wwpn_h = (grub_ieee1275_cell_t) (*ptr_targets >> 32);
- pos = grub_snprintf (bufptr, 32, "/disk@%" PRIxGRUB_UINT64_T,
- grub_get_unaligned64 (*ptr_targets++));
- /* Get the luns for given wwpn target */
- if (IEEE1275_CALL_ENTRY_FN (&args_luns) == -1)
- {
- grub_dprintf ("disk", "failed to get the LUNS while iterating FCP disk path=%s\n", buf);
- grub_ieee1275_close (ihandle);
- grub_free (buf);
- return;
- }
- struct args_ret *luns_table = (struct args_ret *) (args_luns.table);
-
- /* Iterate over all LUNs */
- for(j = 0; j < args_luns.nentries; j++)
- {
- ptr_luns = (grub_uint64_t*) luns_table[j].addr;
- for(l = 0; l < luns_table[j].len; l++)
- {
- grub_snprintf (&bufptr[pos], 30, ",%" PRIxGRUB_UINT64_T,
- grub_get_unaligned64 (*ptr_luns++));
- dev_iterate_real (buf, buf);
- }
- }
- }
- }
- grub_ieee1275_close (ihandle);
- grub_free (buf);
- return;
+ /* Iterate disks */
+ dev_iterate_fcp_disks (alias);
+ /* Iterate NVMeoF */
+ dev_iterate_fcp_nvmeof (alias);
}
else if (grub_strcmp (alias->type, "vscsi") == 0)
{

View File

@ -534,3 +534,9 @@ Patch0534: 0534-util-grub-mkimagexx-Stop-generating-unaligned-append.patch
Patch0535: 0535-grub-mkimage-Do-not-generate-empty-SBAT-metadata.patch
Patch0536: 0536-kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-t.patch
Patch0537: 0537-Change-login-error-message.patch
Patch0538: 0538-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
Patch0539: 0539-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch
Patch0540: 0540-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch
Patch0541: 0541-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch
Patch0542: 0542-ieee1275-support-added-for-multiple-nvme-bootpaths.patch
Patch0543: 0543-ieee1275-add-support-for-NVMeoFC.patch

View File

@ -16,7 +16,7 @@
Name: grub2
Epoch: 1
Version: 2.06
Release: 128%{?dist}
Release: 129%{?dist}
Summary: Bootloader with support for Linux, Multiboot and more
License: GPLv3+
URL: http://www.gnu.org/software/grub/
@ -543,6 +543,10 @@ fi
%endif
%changelog
* Thu Jun 18 2026 Nicolas Frayer <nfrayer@redhat.com> 2.06-129
- ieee1275/powerpc: implements fibre channel discovery for ofpathname
- Resolves: #RHEL-53369
* Fri Jun 05 2026 Nicolas Frayer <nfrayer@redhat.com> 2.06-128
- CentOS: Sign grub with 802
- Resolves: #RHEL-182487