public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/grub2] rawhide: ieee1275/powerpc: implements fibre channel discovery for ofpathname
@ 2026-06-26 18:05 Nicolas Frayer
  0 siblings, 0 replies; only message in thread
From: Nicolas Frayer @ 2026-06-26 18:05 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/grub2
            Branch : rawhide
            Commit : d09439013e18832d91f0e3c24c3c424577f08859
            Author : Nicolas Frayer <nfrayer@redhat.com>
            Date   : 2026-06-26T11:38:51+02:00
            Stats  : +1558/-1 in 8 file(s)
            URL    : https://src.fedoraproject.org/rpms/grub2/c/d09439013e18832d91f0e3c24c3c424577f08859?branch=rawhide

            Log:
            ieee1275/powerpc: implements fibre channel discovery for ofpathname

Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>

---
diff --git a/0439-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/0439-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
new file mode 100644
index 0000000..5846c02
--- /dev/null
+++ b/0439-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
@@ -0,0 +1,120 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Avnish Chouhan <avnish@linux.ibm.com>
+Date: Thu, 25 Jun 2026 18:23:36 +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 72772c87a66f..53cf39cd176d 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
+     {

diff --git a/0440-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch b/0440-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch
new file mode 100644
index 0000000..af8c87e
--- /dev/null
+++ b/0440-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch
@@ -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 71237b256003..042f98797546 100644
+--- a/grub-core/disk/ieee1275/ofdisk.c
++++ b/grub-core/disk/ieee1275/ofdisk.c
+@@ -224,7 +224,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

diff --git a/0441-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch b/0441-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch
new file mode 100644
index 0000000..949a590
--- /dev/null
+++ b/0441-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch
@@ -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 65616254e021..0c9047769860 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 ();

diff --git a/0442-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch b/0442-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch
new file mode 100644
index 0000000..71b811b
--- /dev/null
+++ b/0442-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch
@@ -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 53cf39cd176d..94bfa8e268dc 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 */

diff --git a/0443-ieee1275-support-added-for-multiple-nvme-bootpaths.patch b/0443-ieee1275-support-added-for-multiple-nvme-bootpaths.patch
new file mode 100644
index 0000000..06c68e5
--- /dev/null
+++ b/0443-ieee1275-support-added-for-multiple-nvme-bootpaths.patch
@@ -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 94bfa8e268dc..8252fd38b32a 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 de712211cf09..2eda02bf5f20 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 dbf3c216d413..857ccbbe9c38 100644
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -240,6 +240,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 */

diff --git a/0444-ieee1275-add-support-for-NVMeoFC.patch b/0444-ieee1275-add-support-for-NVMeoFC.patch
new file mode 100644
index 0000000..9142ea1
--- /dev/null
+++ b/0444-ieee1275-add-support-for-NVMeoFC.patch
@@ -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 042f98797546..bbd61a32bee3 100644
+--- a/grub-core/disk/ieee1275/ofdisk.c
++++ b/grub-core/disk/ieee1275/ofdisk.c
+@@ -27,6 +27,10 @@
+ #include <grub/env.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;
+ 
+@@ -221,117 +225,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)
+     {

diff --git a/grub.patches b/grub.patches
index 74f0ace..50bb055 100644
--- a/grub.patches
+++ b/grub.patches
@@ -435,3 +435,9 @@ Patch0435: 0435-util-grub-editenv-remove-stale-env_block-on-unsuppor.patch
 Patch0436: 0436-Change-login-error-message.patch
 Patch0437: 0437-mdraid-fix-metadata-1.0-detection-in-userspace-utils-on-IEEE1275.patch
 Patch0438: 0438-grub-install-use-search.fs_uuid-for-RAID1-on-IEEE1275.patch
+Patch0439: 0439-ieee1275-powerpc-implements-fibre-channel-discovery-.patch
+Patch0440: 0440-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch
+Patch0441: 0441-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch
+Patch0442: 0442-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch
+Patch0443: 0443-ieee1275-support-added-for-multiple-nvme-bootpaths.patch
+Patch0444: 0444-ieee1275-add-support-for-NVMeoFC.patch

diff --git a/grub2.spec b/grub2.spec
index 8fa47b5..c951083 100644
--- a/grub2.spec
+++ b/grub2.spec
@@ -17,7 +17,7 @@
 Name:		grub2
 Epoch:		1
 Version:	2.12
-Release:	66%{?dist}
+Release:	67%{?dist}
 Summary:	Bootloader with support for Linux, Multiboot and more
 License:	GPL-3.0-or-later
 URL:		http://www.gnu.org/software/grub/
@@ -625,6 +625,9 @@ fi
 %endif
 
 %changelog
+* Thu Jun 25 2026 Nicolas Frayer <nfrayer@redhat.com> - 2.12-67
+- ieee1275/powerpc: implements fibre channel discovery for ofpathname
+
 * Thu Jun 25 2026 Leo Sandoval <lsandova@redhat.com> - 2.12-66
 - spec efi postttrans: remove mountpoint check
 - Resolves: #2492140

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-26 18:05 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-26 18:05 [rpms/grub2] rawhide: ieee1275/powerpc: implements fibre channel discovery for ofpathname Nicolas Frayer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox