752ceb1
From d85c76b501edda038b68bc23eee946e6cc600513 Mon Sep 17 00:00:00 2001
752ceb1
From: Eric Snowberg <eric.snowberg@oracle.com>
752ceb1
Date: Tue, 30 Jan 2018 20:49:48 -0800
752ceb1
Subject: [PATCH] sparc64: fix OF path names for sun4v systems
752ceb1
752ceb1
Fix the Open Firmware (OF) path property for sun4v SPARC systems.
752ceb1
These platforms do not have a /sas/ within their path. Over time
752ceb1
different OF addressing schemes have been supported. There
752ceb1
is no generic addressing scheme that works across every HBA.
752ceb1
752ceb1
It looks that this functionality will not work if you try to cross-install
752ceb1
SPARC GRUB2 binary using e.g. x86 grub-install. By default it should work.
752ceb1
However, we will also have other issues here, like lack of access to OF
752ceb1
firmware/paths, which make such configs unusable anyway. So, let's leave
752ceb1
this patch as is for time being. If somebody cares then he/she should fix
752ceb1
the issue(s) at some point.
752ceb1
752ceb1
Signed-off-by: Eric Snowberg <eric.snowberg@oracle.com>
752ceb1
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
752ceb1
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
752ceb1
---
752ceb1
 grub-core/osdep/linux/ofpath.c | 147 ++++++++++++++++++++++++++++++++++++++++-
752ceb1
 1 file changed, 144 insertions(+), 3 deletions(-)
752ceb1
752ceb1
diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
752ceb1
index dce4e59d081..8d7d6837f26 100644
752ceb1
--- a/grub-core/osdep/linux/ofpath.c
752ceb1
+++ b/grub-core/osdep/linux/ofpath.c
752ceb1
@@ -38,6 +38,46 @@
752ceb1
 #include <errno.h>
752ceb1
 #include <ctype.h>
752ceb1
 
752ceb1
+#ifdef __sparc__
752ceb1
+typedef enum
752ceb1
+  {
752ceb1
+    GRUB_OFPATH_SPARC_WWN_ADDR = 1,
752ceb1
+    GRUB_OFPATH_SPARC_TGT_LUN,
752ceb1
+  } ofpath_sparc_addressing;
752ceb1
+
752ceb1
+struct ofpath_sparc_hba
752ceb1
+{
752ceb1
+  grub_uint32_t device_id;
752ceb1
+  ofpath_sparc_addressing addressing;
752ceb1
+};
752ceb1
+
752ceb1
+static struct ofpath_sparc_hba sparc_lsi_hba[] = {
752ceb1
+  /* Rhea, Jasper 320, LSI53C1020/1030. */
752ceb1
+  {0x30, GRUB_OFPATH_SPARC_TGT_LUN},
752ceb1
+  /* SAS-1068E. */
752ceb1
+  {0x50, GRUB_OFPATH_SPARC_TGT_LUN},
752ceb1
+  /* SAS-1064E. */
752ceb1
+  {0x56, GRUB_OFPATH_SPARC_TGT_LUN},
752ceb1
+  /* Pandora SAS-1068E. */
752ceb1
+  {0x58, GRUB_OFPATH_SPARC_TGT_LUN},
752ceb1
+  /* Aspen, Invader, LSI SAS-3108. */
752ceb1
+  {0x5d, GRUB_OFPATH_SPARC_TGT_LUN},
752ceb1
+  /* Niwot, SAS 2108. */
752ceb1
+  {0x79, GRUB_OFPATH_SPARC_TGT_LUN},
752ceb1
+  /* Erie, Falcon, LSI SAS 2008. */
752ceb1
+  {0x72, GRUB_OFPATH_SPARC_WWN_ADDR},
752ceb1
+  /* LSI WarpDrive 6203. */
752ceb1
+  {0x7e, GRUB_OFPATH_SPARC_WWN_ADDR},
752ceb1
+  /* LSI SAS 2308. */
752ceb1
+  {0x87, GRUB_OFPATH_SPARC_WWN_ADDR},
752ceb1
+  /* LSI SAS 3008. */
752ceb1
+  {0x97, GRUB_OFPATH_SPARC_WWN_ADDR},
752ceb1
+  {0, 0}
752ceb1
+};
752ceb1
+
752ceb1
+static const int LSI_VENDOR_ID = 0x1000;
752ceb1
+#endif
752ceb1
+
752ceb1
 #ifdef OFPATH_STANDALONE
752ceb1
 #define xmalloc malloc
752ceb1
 void
752ceb1
@@ -338,6 +378,64 @@ vendor_is_ATA(const char *path)
752ceb1
   return (memcmp(bufcont, "ATA", 3) == 0);
752ceb1
 }
752ceb1
 
752ceb1
+#ifdef __sparc__
752ceb1
+static void
752ceb1
+check_hba_identifiers (const char *sysfs_path, int *vendor, int *device_id)
752ceb1
+{
752ceb1
+  char *ed = strstr (sysfs_path, "host");
752ceb1
+  size_t path_size;
752ceb1
+  char *p, *path;
752ceb1
+  char buf[8];
752ceb1
+  int fd;
752ceb1
+
752ceb1
+  if (!ed)
752ceb1
+    return;
752ceb1
+
752ceb1
+  p = xstrdup (sysfs_path);
752ceb1
+  ed = strstr (p, "host");
752ceb1
+
752ceb1
+  *ed = '\0';
752ceb1
+
752ceb1
+  path_size = (strlen (p) + sizeof ("vendor"));
752ceb1
+  path = xmalloc (path_size);
752ceb1
+
752ceb1
+  if (!path)
752ceb1
+    goto out;
752ceb1
+
752ceb1
+  snprintf (path, path_size, "%svendor", p);
752ceb1
+  fd = open (path, O_RDONLY);
752ceb1
+
752ceb1
+  if (fd < 0)
752ceb1
+    goto out;
752ceb1
+
752ceb1
+  memset (buf, 0, sizeof (buf));
752ceb1
+
752ceb1
+  if (read (fd, buf, sizeof (buf) - 1) < 0)
752ceb1
+    goto out;
752ceb1
+
752ceb1
+  close (fd);
752ceb1
+  sscanf (buf, "%x", vendor);
752ceb1
+
752ceb1
+  snprintf (path, path_size, "%sdevice", p);
752ceb1
+  fd = open (path, O_RDONLY);
752ceb1
+
752ceb1
+  if (fd < 0)
752ceb1
+    goto out;
752ceb1
+
752ceb1
+  memset (buf, 0, sizeof (buf));
752ceb1
+
752ceb1
+  if (read (fd, buf, sizeof (buf) - 1) < 0)
752ceb1
+    goto out;
752ceb1
+
752ceb1
+  close (fd);
752ceb1
+  sscanf (buf, "%x", device_id);
752ceb1
+
752ceb1
+ out:
752ceb1
+  free (path);
752ceb1
+  free (p);
752ceb1
+}
752ceb1
+#endif
752ceb1
+
752ceb1
 static void
752ceb1
 check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address)
752ceb1
 {
752ceb1
@@ -399,7 +497,7 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
752ceb1
 {
752ceb1
   const char *p, *digit_string, *disk_name;
752ceb1
   int host, bus, tgt, lun;
752ceb1
-  unsigned long int sas_address;
752ceb1
+  unsigned long int sas_address = 0;
752ceb1
   char *sysfs_path, disk[MAX_DISK_CAT - sizeof ("/fp@0,0")];
752ceb1
   char *of_path;
752ceb1
 
752ceb1
@@ -416,9 +514,8 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
752ceb1
     }
752ceb1
 
752ceb1
   of_path = find_obppath(sysfs_path);
752ceb1
-  free (sysfs_path);
752ceb1
   if (!of_path)
752ceb1
-    return NULL;
752ceb1
+    goto out;
752ceb1
 
752ceb1
   if (strstr (of_path, "qlc"))
752ceb1
     strcat (of_path, "/fp@0,0");
752ceb1
@@ -447,6 +544,46 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
752ceb1
     }
752ceb1
   else
752ceb1
     {
752ceb1
+#ifdef __sparc__
752ceb1
+      ofpath_sparc_addressing addressing = GRUB_OFPATH_SPARC_TGT_LUN;
752ceb1
+      int vendor = 0, device_id = 0;
752ceb1
+      char *optr = disk;
752ceb1
+
752ceb1
+      check_hba_identifiers (sysfs_path, &vendor, &device_id);
752ceb1
+
752ceb1
+      if (vendor == LSI_VENDOR_ID)
752ceb1
+        {
752ceb1
+          struct ofpath_sparc_hba *lsi_hba;
752ceb1
+
752ceb1
+	  /*
752ceb1
+	   * Over time different OF addressing schemes have been supported.
752ceb1
+	   * There is no generic addressing scheme that works across
752ceb1
+	   * every HBA.
752ceb1
+	   */
752ceb1
+          for (lsi_hba = sparc_lsi_hba; lsi_hba->device_id; lsi_hba++)
752ceb1
+            if (lsi_hba->device_id == device_id)
752ceb1
+              {
752ceb1
+                addressing = lsi_hba->addressing;
752ceb1
+                break;
752ceb1
+              }
752ceb1
+        }
752ceb1
+
752ceb1
+      if (addressing == GRUB_OFPATH_SPARC_WWN_ADDR)
752ceb1
+        optr += snprintf (disk, sizeof (disk), "/%s@w%lx,%x", disk_name,
752ceb1
+                          sas_address, lun);
752ceb1
+      else
752ceb1
+        optr += snprintf (disk, sizeof (disk), "/%s@%x,%x", disk_name, tgt,
752ceb1
+                          lun);
752ceb1
+
752ceb1
+      if (*digit_string != '\0')
752ceb1
+        {
752ceb1
+          int part;
752ceb1
+
752ceb1
+          sscanf (digit_string, "%d", &part);
752ceb1
+          snprintf (optr, sizeof (disk) - (optr - disk - 1), ":%c", 'a'
752ceb1
+                    + (part - 1));
752ceb1
+        }
752ceb1
+#else
752ceb1
       if (lun == 0)
752ceb1
         {
752ceb1
           int sas_id = 0;
752ceb1
@@ -494,8 +631,12 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev
752ceb1
             }
752ceb1
 	  free (lunstr);
752ceb1
         }
752ceb1
+#endif
752ceb1
     }
752ceb1
   strcat(of_path, disk);
752ceb1
+
752ceb1
+ out:
752ceb1
+  free (sysfs_path);
752ceb1
   return of_path;
752ceb1
 }
752ceb1