From c4ea783e4d1ec07b04448edfe525731541ec8680 Mon Sep 17 00:00:00 2001 From: Nicolas Frayer Date: Thu, 18 Jun 2026 11:11:04 +0200 Subject: [PATCH] ieee1275/powerpc: implements fibre channel discovery for ofpathname Resolves: #RHEL-53369 Signed-off-by: Nicolas Frayer --- ...-implements-fibre-channel-discovery-.patch | 120 ++++ ...lement-FCP-methods-for-WWPN-and-LUNs.patch | 143 +++++ ...ge-the-logic-of-ieee1275_get_devargs.patch | 63 ++ ...enable-NVMeoF-logical-device-transla.patch | 547 ++++++++++++++++++ ...rt-added-for-multiple-nvme-bootpaths.patch | 218 +++++++ 0543-ieee1275-add-support-for-NVMeoFC.patch | 457 +++++++++++++++ grub.patches | 6 + grub2.spec | 6 +- 8 files changed, 1559 insertions(+), 1 deletion(-) create mode 100644 0538-ieee1275-powerpc-implements-fibre-channel-discovery-.patch create mode 100644 0539-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch create mode 100644 0540-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch create mode 100644 0541-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch create mode 100644 0542-ieee1275-support-added-for-multiple-nvme-bootpaths.patch create mode 100644 0543-ieee1275-add-support-for-NVMeoFC.patch diff --git a/0538-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/0538-ieee1275-powerpc-implements-fibre-channel-discovery-.patch new file mode 100644 index 0000000..4daabf4 --- /dev/null +++ b/0538-ieee1275-powerpc-implements-fibre-channel-discovery-.patch @@ -0,0 +1,120 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +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 +Signed-off-by: Avnish Chouhan +Reviewed-by: Leo Sandoval +Reviewed-by: Sudhakar Kuppusamy +Part-of: +--- + 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 + { diff --git a/0539-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch b/0539-ieee1275-implement-FCP-methods-for-WWPN-and-LUNs.patch new file mode 100644 index 0000000..3af7ccf --- /dev/null +++ b/0539-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 +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 +Signed-off-by: Avnish Chouhan +Reviewed-by: Leo Sandoval +Reviewed-by: Sudhakar Kuppusamy +Part-of: +--- + 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 diff --git a/0540-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch b/0540-ieee1275-change-the-logic-of-ieee1275_get_devargs.patch new file mode 100644 index 0000000..af670f4 --- /dev/null +++ b/0540-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 +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 +Signed-off-by: Avnish Chouhan +Reviewed-by: Leo Sandoval +Reviewed-by: Sudhakar Kuppusamy +Part-of: +--- + 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 (); diff --git a/0541-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch b/0541-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch new file mode 100644 index 0000000..10bab3e --- /dev/null +++ b/0541-ieee1275-ofpath-enable-NVMeoF-logical-device-transla.patch @@ -0,0 +1,547 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +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 +Signed-off-by: Avnish Chouhan +Signed-off-by: Michael Chang +Reviewed-by: Leo Sandoval +Reviewed-by: Sudhakar Kuppusamy +Part-of: +--- + 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 */ diff --git a/0542-ieee1275-support-added-for-multiple-nvme-bootpaths.patch b/0542-ieee1275-support-added-for-multiple-nvme-bootpaths.patch new file mode 100644 index 0000000..2f0f867 --- /dev/null +++ b/0542-ieee1275-support-added-for-multiple-nvme-bootpaths.patch @@ -0,0 +1,218 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +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 +Reviewed-by: Leo Sandoval +Reviewed-by: Sudhakar Kuppusamy +Part-of: +--- + 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 + #include + #include ++#include ++#include ++ ++#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 */ diff --git a/0543-ieee1275-add-support-for-NVMeoFC.patch b/0543-ieee1275-add-support-for-NVMeoFC.patch new file mode 100644 index 0000000..2b97802 --- /dev/null +++ b/0543-ieee1275-add-support-for-NVMeoFC.patch @@ -0,0 +1,457 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +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 +Signed-off-by: Avnish Chouhan +Reviewed-by: Leo Sandoval +Reviewed-by: Sudhakar Kuppusamy +Part-of: +--- + 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 + #include + ++#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) + { diff --git a/grub.patches b/grub.patches index 0535f0b..1f9dba0 100644 --- a/grub.patches +++ b/grub.patches @@ -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 diff --git a/grub2.spec b/grub2.spec index 895156c..6f395d9 100644 --- a/grub2.spec +++ b/grub2.spec @@ -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 2.06-129 +- ieee1275/powerpc: implements fibre channel discovery for ofpathname +- Resolves: #RHEL-53369 + * Fri Jun 05 2026 Nicolas Frayer 2.06-128 - CentOS: Sign grub with 802 - Resolves: #RHEL-182487