grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
From: Avnish Chouhan <avnish@linux.ibm.com>
To: grub-devel@gnu.org
Cc: daniel.kiper@oracle.com, brking@linux.ibm.com,
	meghanaprakash@in.ibm.com,  mchang@suse.com,
	Avnish Chouhan <avnish@linux.ibm.com>,
	Diego Domingos <diegodo@br.ibm.com>
Subject: [PATCH v6 5/6] ieee1275: ofpath enable NVMeoF logical device translate
Date: Wed, 30 Jul 2025 11:04:04 +0530	[thread overview]
Message-ID: <20250730053405.41417-6-avnish@linux.ibm.com> (raw)
In-Reply-To: <20250730053405.41417-1-avnish@linux.ibm.com>

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>
---
 grub-core/osdep/linux/ofpath.c | 415 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 include/grub/util/ofpath.h     | 28 ++++++++++++++++++++++++++++
 1 file changed, 434 insertions(+), 9 deletions(-)

diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
index 64f95a2..dd81e6b 100644
--- a/grub-core/osdep/linux/ofpath.c
+++ b/grub-core/osdep/linux/ofpath.c
@@ -37,6 +37,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <ctype.h>
+#include <dirent.h>
 
 #ifdef __sparc__
 typedef enum
@@ -136,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)
@@ -312,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,
@@ -382,7 +468,244 @@ 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");
+      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");
+  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,
@@ -391,6 +714,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;
@@ -410,15 +735,90 @@ 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;
+            }
+
+          sysfs_path = of_find_fc_host (nvmeof_info->host_wwpn);
+          if (!sysfs_path)
+            {
+              free (nvmedev);
+              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);
@@ -429,7 +829,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)
@@ -779,11 +1178,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 b43c523..85172bc 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 */
-- 
2.39.3


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

  parent reply	other threads:[~2025-07-30  5:36 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-30  5:33 [PATCH v6 0/6] NVMeoFC support on Grub Avnish Chouhan
2025-07-30  5:34 ` [PATCH v6 1/6] ieee1275/powerpc: implements fibre channel discovery for ofpathname Avnish Chouhan
2025-07-30  5:34 ` [PATCH v6 2/6] ieee1275: implement FCP methods for WWPN and LUNs Avnish Chouhan
2025-07-30  5:34 ` [PATCH v6 3/6] ieee1275: change the logic of ieee1275_get_devargs() Avnish Chouhan
2025-07-30  5:34 ` [PATCH v6 4/6] ieee1275: add support for NVMeoFC Avnish Chouhan
2025-07-30  5:34 ` Avnish Chouhan [this message]
2025-07-30  5:34 ` [PATCH v6 6/6] ieee1275: support added for multiple nvme bootpaths Avnish Chouhan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250730053405.41417-6-avnish@linux.ibm.com \
    --to=avnish@linux.ibm.com \
    --cc=brking@linux.ibm.com \
    --cc=daniel.kiper@oracle.com \
    --cc=diegodo@br.ibm.com \
    --cc=grub-devel@gnu.org \
    --cc=mchang@suse.com \
    --cc=meghanaprakash@in.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).